{"version":3,"file":"types.mjs","sources":["../../../src/hooks/types.ts"],"sourcesContent":["// src/hooks/types.ts\nimport type { BaseMessage } from '@langchain/core/messages';\n\n/**\n * Closed set of hook lifecycle events supported by the hooks system.\n *\n * These mirror the subset of Claude Code's event surface that makes sense\n * for a library context (no filesystem/CLI-specific events). See\n * `docs/hooks-design-report.md` §3.2 for the mapping to existing\n * `@librechat/agents` emission points.\n */\nexport const HOOK_EVENTS = [\n  'RunStart',\n  'UserPromptSubmit',\n  'PreToolUse',\n  'PostToolUse',\n  'PostToolUseFailure',\n  'PermissionDenied',\n  'SubagentStart',\n  'SubagentStop',\n  'Stop',\n  'StopFailure',\n  'PreCompact',\n  'PostCompact',\n] as const;\n\nexport type HookEvent = (typeof HOOK_EVENTS)[number];\n\n/** Tool-gating decision; executeHooks folds with `deny > ask > allow` precedence. */\nexport type ToolDecision = 'allow' | 'deny' | 'ask';\n\n/** Stop-loop decision; `block` means \"do not stop, run another turn\". Any `block` wins. */\nexport type StopDecision = 'continue' | 'block';\n\n/**\n * Fields shared by every `HookInput`. Discriminated by `hook_event_name`.\n *\n * - `runId` identifies the current agent run and is always present.\n * - `threadId` identifies the conversation thread when the host has one.\n * - `agentId` is only set when the hook fires inside a subagent scope.\n */\nexport interface BaseHookInput {\n  runId: string;\n  threadId?: string;\n  agentId?: string;\n}\n\nexport interface RunStartHookInput extends BaseHookInput {\n  hook_event_name: 'RunStart';\n  messages: BaseMessage[];\n}\n\nexport interface UserPromptSubmitHookInput extends BaseHookInput {\n  hook_event_name: 'UserPromptSubmit';\n  prompt: string;\n  attachments?: BaseMessage[];\n}\n\n/**\n * Fires before a tool is invoked. Hook may return `deny`/`ask`/`allow` and/or\n * an `updatedInput` that replaces the tool arguments before invocation.\n *\n * `toolInput` is intentionally typed as `Record<string, unknown>` because the\n * SDK is tool-agnostic — concrete tool argument shapes are only known at the\n * call site and are narrowed by the host. This is the one escape hatch in\n * the hook type system.\n */\nexport interface PreToolUseHookInput extends BaseHookInput {\n  hook_event_name: 'PreToolUse';\n  toolName: string;\n  toolInput: Record<string, unknown>;\n  toolUseId: string;\n  stepId?: string;\n  /**\n   * Number of times this tool has been invoked in prior batches within the\n   * current run. Within a single batch of parallel calls, all calls to the\n   * same tool share the same turn value — per-call discrimination within a\n   * batch is not supported in v1.\n   */\n  turn?: number;\n}\n\nexport interface PostToolUseHookInput extends BaseHookInput {\n  hook_event_name: 'PostToolUse';\n  toolName: string;\n  toolInput: Record<string, unknown>;\n  toolOutput: unknown;\n  toolUseId: string;\n  stepId?: string;\n  turn?: number;\n}\n\nexport interface PostToolUseFailureHookInput extends BaseHookInput {\n  hook_event_name: 'PostToolUseFailure';\n  toolName: string;\n  toolInput: Record<string, unknown>;\n  toolUseId: string;\n  error: string;\n  stepId?: string;\n  turn?: number;\n}\n\nexport interface PermissionDeniedHookInput extends BaseHookInput {\n  hook_event_name: 'PermissionDenied';\n  toolName: string;\n  toolInput: Record<string, unknown>;\n  toolUseId: string;\n  reason: string;\n}\n\nexport interface SubagentStartHookInput extends BaseHookInput {\n  hook_event_name: 'SubagentStart';\n  parentAgentId?: string;\n  agentId: string;\n  agentType: string;\n  inputs: BaseMessage[];\n}\n\nexport interface SubagentStopHookInput extends BaseHookInput {\n  hook_event_name: 'SubagentStop';\n  agentId: string;\n  agentType: string;\n  messages: BaseMessage[];\n}\n\nexport interface StopHookInput extends BaseHookInput {\n  hook_event_name: 'Stop';\n  messages: BaseMessage[];\n  stopReason?: string;\n  stopHookActive: boolean;\n}\n\nexport interface StopFailureHookInput extends BaseHookInput {\n  hook_event_name: 'StopFailure';\n  error: string;\n  lastAssistantMessage?: BaseMessage;\n}\n\nexport interface PreCompactHookInput extends BaseHookInput {\n  hook_event_name: 'PreCompact';\n  messagesBeforeCount: number;\n  /**\n   * What triggered compaction. Matches `SummarizationTrigger.type` from the\n   * agent's summarization config. `'default'` means no trigger was\n   * configured and compaction fired because messages were pruned.\n   */\n  trigger:\n    | 'token_ratio'\n    | 'remaining_tokens'\n    | 'messages_to_refine'\n    | 'default'\n    | (string & {});\n}\n\nexport interface PostCompactHookInput extends BaseHookInput {\n  hook_event_name: 'PostCompact';\n  summary: string;\n  /**\n   * Number of messages remaining after compaction. The summarize node\n   * returns a `removeAll` signal that clears all messages from state;\n   * the summary itself is injected into the system prompt, not as a\n   * message. This is `0` at the point of hook dispatch.\n   */\n  messagesAfterCount: number;\n}\n\n/** Discriminated union of every hook input shape. */\nexport type HookInput =\n  | RunStartHookInput\n  | UserPromptSubmitHookInput\n  | PreToolUseHookInput\n  | PostToolUseHookInput\n  | PostToolUseFailureHookInput\n  | PermissionDeniedHookInput\n  | SubagentStartHookInput\n  | SubagentStopHookInput\n  | StopHookInput\n  | StopFailureHookInput\n  | PreCompactHookInput\n  | PostCompactHookInput;\n\n/** Compile-time map from event name to its input shape. */\nexport type HookInputByEvent = {\n  RunStart: RunStartHookInput;\n  UserPromptSubmit: UserPromptSubmitHookInput;\n  PreToolUse: PreToolUseHookInput;\n  PostToolUse: PostToolUseHookInput;\n  PostToolUseFailure: PostToolUseFailureHookInput;\n  PermissionDenied: PermissionDeniedHookInput;\n  SubagentStart: SubagentStartHookInput;\n  SubagentStop: SubagentStopHookInput;\n  Stop: StopHookInput;\n  StopFailure: StopFailureHookInput;\n  PreCompact: PreCompactHookInput;\n  PostCompact: PostCompactHookInput;\n};\n\n/**\n * Fields common to every hook output. Hooks that have nothing to say simply\n * return `{}` (or omit the fields below).\n */\nexport interface BaseHookOutput {\n  /** Context string to inject into the conversation. Accumulated across hooks. */\n  additionalContext?: string;\n  /** True to prevent the next model turn. Any hook can set this. */\n  preventContinuation?: boolean;\n  /** Reason reported alongside `preventContinuation`. */\n  stopReason?: string;\n}\n\nexport type RunStartHookOutput = BaseHookOutput;\n\nexport interface UserPromptSubmitHookOutput extends BaseHookOutput {\n  decision?: ToolDecision;\n  reason?: string;\n}\n\nexport interface PreToolUseHookOutput extends BaseHookOutput {\n  decision?: ToolDecision;\n  reason?: string;\n  /**\n   * Replacement tool input. Merged into the pending tool call by the host.\n   *\n   * When multiple hooks set `updatedInput` within a single `executeHooks`\n   * call, the last writer in registration order wins (outer loop: matcher\n   * registration order; inner loop: hook position within the matcher). The\n   * winner is deterministic — `Promise.all` preserves input-array order.\n   * Consumers that need a single authoritative rewrite should still scope\n   * `updatedInput` to one hook per matcher to avoid confusing precedence.\n   */\n  updatedInput?: Record<string, unknown>;\n}\n\nexport interface PostToolUseHookOutput extends BaseHookOutput {\n  /**\n   * Replacement tool output. Flows through the aggregated result so the\n   * host can substitute it before appending the tool result message.\n   * Ordering semantics match `PreToolUseHookOutput.updatedInput`:\n   * last-writer-wins in registration order.\n   */\n  updatedOutput?: unknown;\n}\n\nexport type PostToolUseFailureHookOutput = BaseHookOutput;\n\nexport type PermissionDeniedHookOutput = BaseHookOutput;\n\nexport interface SubagentStartHookOutput extends BaseHookOutput {\n  decision?: ToolDecision;\n  reason?: string;\n}\n\nexport type SubagentStopHookOutput = BaseHookOutput;\n\nexport interface StopHookOutput extends BaseHookOutput {\n  decision?: StopDecision;\n  reason?: string;\n}\n\nexport type StopFailureHookOutput = BaseHookOutput;\n\nexport type PreCompactHookOutput = BaseHookOutput;\n\nexport type PostCompactHookOutput = BaseHookOutput;\n\n/** Compile-time map from event name to its output shape. */\nexport type HookOutputByEvent = {\n  RunStart: RunStartHookOutput;\n  UserPromptSubmit: UserPromptSubmitHookOutput;\n  PreToolUse: PreToolUseHookOutput;\n  PostToolUse: PostToolUseHookOutput;\n  PostToolUseFailure: PostToolUseFailureHookOutput;\n  PermissionDenied: PermissionDeniedHookOutput;\n  SubagentStart: SubagentStartHookOutput;\n  SubagentStop: SubagentStopHookOutput;\n  Stop: StopHookOutput;\n  StopFailure: StopFailureHookOutput;\n  PreCompact: PreCompactHookOutput;\n  PostCompact: PostCompactHookOutput;\n};\n\n/** Superset output shape used by the executor's fold loop. */\nexport type HookOutput =\n  | RunStartHookOutput\n  | UserPromptSubmitHookOutput\n  | PreToolUseHookOutput\n  | PostToolUseHookOutput\n  | PostToolUseFailureHookOutput\n  | PermissionDeniedHookOutput\n  | SubagentStartHookOutput\n  | SubagentStopHookOutput\n  | StopHookOutput\n  | StopFailureHookOutput\n  | PreCompactHookOutput\n  | PostCompactHookOutput;\n\n/**\n * A hook callback is a plain async function registered against a specific\n * event. The `signal` is always supplied by `executeHooks` and combines the\n * batch's parent signal with the per-hook timeout — callbacks that perform\n * long-running work should observe it.\n */\nexport type HookCallback<E extends HookEvent = HookEvent> = (\n  input: HookInputByEvent[E],\n  signal: AbortSignal\n) => HookOutputByEvent[E] | Promise<HookOutputByEvent[E]>;\n\n/**\n * A matcher groups one or more callbacks under a shared regex filter and\n * shared timeout/once/internal flags. The generic `E` ties the callback\n * types to the event the matcher is registered against.\n */\nexport interface HookMatcher<E extends HookEvent = HookEvent> {\n  /**\n   * Regex pattern matched against the event's primary query string (e.g.\n   * the tool name for `PreToolUse`, the agent type for `SubagentStart`).\n   *\n   * Omitted or empty means \"always match\". For events that do not supply a\n   * query string (`RunStart`, `Stop`, etc.), only wildcard matchers fire —\n   * a non-empty pattern on such events will never match.\n   *\n   * Patterns are treated as trusted input: `executeHooks` compiles them\n   * with `new RegExp(pattern)` without any sandbox, and a pathological\n   * pattern can block the event loop. Host registration code is expected\n   * to validate or length-bound patterns that originate from user input.\n   */\n  pattern?: string;\n  /** Callbacks that fire when the matcher hits. Executed in parallel. */\n  hooks: HookCallback<E>[];\n  /** Per-matcher timeout in ms. Defaults to the executor's batch timeout. */\n  timeout?: number;\n  /**\n   * Atomically remove the matcher before its first dispatch.\n   *\n   * `executeHooks` claims `once: true` matchers synchronously — between\n   * `getMatchers` and its first `await` — so two concurrent calls cannot\n   * both dispatch the same matcher. Whichever call runs its sync prefix\n   * first wins the matcher; the other sees an empty bucket.\n   *\n   * Semantics are \"at most one dispatch, ever\" — if every hook in the\n   * matcher throws, the matcher is still gone. Use `once` for\n   * fire-and-forget bootstrapping (registration, telemetry, setup). Hosts\n   * that need retry semantics should register a normal matcher and\n   * self-unregister via the callback returned from `registry.register`.\n   */\n  once?: boolean;\n  /** Internal hooks are excluded from telemetry and non-fatal error logging. */\n  internal?: boolean;\n}\n\n/**\n * Storage shape for matchers keyed by event. Each event's matcher list is\n * a generic array parameterized by that event type, so lookup via\n * `HooksByEvent[E]` preserves type-safe callback signatures.\n */\nexport type HooksByEvent = {\n  [E in HookEvent]?: HookMatcher<E>[];\n};\n\n/**\n * Aggregated result of a single `executeHooks` call. Fields are populated\n * according to the fold rules in `executeHooks.ts`.\n */\nexport interface AggregatedHookResult {\n  /** Folded tool-gating decision; `deny > ask > allow`. */\n  decision?: ToolDecision;\n  /** Folded stop decision; any `block` wins. */\n  stopDecision?: StopDecision;\n  /** Reason from the hook that set the winning decision. */\n  reason?: string;\n  /**\n   * Replacement tool input from a `PreToolUse` hook.\n   *\n   * Last-writer-wins in **registration order**: `executeHooks` uses\n   * `Promise.all`, which preserves input-array order, so the fold iterates\n   * outcomes in the same order they were pushed — outer loop over matchers\n   * as they sit in the registry, inner loop over each matcher's `hooks`\n   * array. The winner is therefore deterministic but may not match the\n   * order in which hooks actually completed. Consumers that want a single\n   * authoritative rewrite should still register one `updatedInput`-setting\n   * hook per matcher to avoid subtle precedence bugs.\n   */\n  updatedInput?: Record<string, unknown>;\n  /**\n   * Replacement tool output from a `PostToolUse` hook.\n   *\n   * Same last-writer-wins-in-registration-order semantics as\n   * `updatedInput`. Present only when at least one hook set it; `undefined`\n   * means \"use the original tool output\".\n   */\n  updatedOutput?: unknown;\n  /** Accumulated `additionalContext` strings from every hook, in order. */\n  additionalContexts: string[];\n  /** True if any hook returned `preventContinuation`. */\n  preventContinuation?: boolean;\n  /**\n   * Reason recorded alongside `preventContinuation`. First winner wins:\n   * once a hook sets both flags, later hooks that also set\n   * `preventContinuation` do not overwrite the reason.\n   */\n  stopReason?: string;\n  /** Error messages from hooks that threw; always present (possibly empty). */\n  errors: string[];\n}\n"],"names":[],"mappings":"AAGA;;;;;;;AAOG;AACI,MAAM,WAAW,GAAG;IACzB,UAAU;IACV,kBAAkB;IAClB,YAAY;IACZ,aAAa;IACb,oBAAoB;IACpB,kBAAkB;IAClB,eAAe;IACf,cAAc;IACd,MAAM;IACN,aAAa;IACb,YAAY;IACZ,aAAa;;;;;"}