import type { AgentTelemetryConfig, AgentTool } from "@gajae-code/agent-core"; import type { Model, ServiceTier, ToolChoice } from "@gajae-code/ai/core"; import type { AsyncJobManager } from "../async"; import type { PromptTemplate } from "../config/prompt-templates"; import type { Settings } from "../config/settings"; import type { Skill } from "../extensibility/skills"; import type { GoalModeState, GoalRuntime } from "../goals"; import type { HindsightSessionState } from "../hindsight/state"; import type { WorkflowGateEmitter } from "../modes/shared/agent-wire/workflow-gate-broker"; import type { PlanModeState } from "../plan-mode/state"; import type { AgentRegistry } from "../registry/agent-registry"; import type { ForkContextSeed, ForkContextSeedOptions, PurgeQueuedCustomMessagesResult } from "../session/agent-session"; import type { ArtifactManager } from "../session/artifacts"; import type { ClientBridge } from "../session/client-bridge"; import type { CustomMessage } from "../session/messages"; import type { ToolChoiceQueue } from "../session/tool-choice-queue"; import type { SkillActiveEntry } from "../skill-state/active-state"; import type { AgentOutputManager } from "../task/output-manager"; import type { DiscoverableTool, DiscoverableToolSearchIndex } from "../tool-discovery/tool-index"; import type { EventBus } from "../utils/event-bus"; import type { WorkspaceTree } from "../workspace-tree"; import type { BashRestrictionProfile } from "./bash-allowed-prefixes"; import type { CheckpointState } from "./checkpoint"; import { BUILTIN_TOOLS } from "./descriptors"; import type { TodoPhase } from "./todo-write"; export type { LspStartupServerInfo } from "../lsp"; export type { BashToolDetails, BashToolInput } from "./bash"; export * from "./descriptors"; export type { FindToolDetails, FindToolInput } from "./find"; export type { ReadToolDetails, ReadToolInput } from "./read"; export type { SearchToolDetails, SearchToolInput } from "./search"; export { TOOL_CATALOG } from "./tool-catalog.generated"; export type { WriteToolDetails, WriteToolInput } from "./write"; /** Tool type (AgentTool from pi-ai) */ export type Tool = AgentTool; /** Built-in automation surfaces that an SDK host may back with its own transport. */ export type AutomationToolName = "browser" | "computer"; /** * Host-owned implementations for the built-in automation surfaces. * * Each implementation must use the matching built-in name. The normal * AgentTool execute signature carries cancellation through its AbortSignal, * while the implementation owns the model-facing schema and description. */ export type AutomationTools = Partial>; export type ContextFileEntry = { path: string; content: string; depth?: number; }; export type { DiscoverableTool, DiscoverableToolSearchIndex, DiscoverableToolSearchResult, DiscoverableToolSource, } from "../tool-discovery/tool-index"; /** A typed remote action available to an ask answer source. */ export type AskRemoteControlId = "navigation_forward"; export interface AskRemoteControl { id: AskRemoteControlId; kind: "navigation"; label: "Next" | "Done"; enabled: boolean; } export interface AskAnswerRequest { question: string; options: string[]; interaction: "selector" | "custom_editor" | "clarification_editor"; controls: readonly AskRemoteControl[]; /** Optional zero-based recommendation into the authoritative raw options. */ recommendedIndex?: number; /** True while the question accepts several options before the navigation control commits. */ multi?: boolean; /** * Options currently selected in the multi-select loop, as authoritative option * labels. Remote transports render the selection state so a toggle is visible. */ selectedOptions?: readonly string[]; /** Milliseconds before a remote source auto-selects; absent means no timeout. */ timeoutMs?: number; /** Number of trailing synthetic transition entries (Other/clarification) appended by the ask tool. */ transitionCount?: number; } export type AskRemoteInteraction = { kind: "value"; value: string; } | { kind: "control"; controlId: AskRemoteControlId; }; export type AskSettlement = { kind: "commit"; } | { kind: "resolve_without_commit"; reason: "toggle" | "other_transition" | "clarification_transition" | "clarification_submitted" | "empty_navigation" | "back_navigation" | "cancelled" | "aborted" | "timed_out" | "exception" | "shutdown"; } | { kind: "invalid"; reason: "invalid_option" | "invalid_control" | "invalid_structured_answer" | "empty_custom" | "empty_clarification"; }; export type AskSelectedAckOutcome = { status: "delivered"; messageId: number; } | { status: "failed"; reason: "unsupported" | "no_participant" | "ambiguous_participant" | "route_missing" | "expired" | "cancelled" | "telegram_rejected" | "session_closed"; } | { status: "unknown"; reason: "transport_ambiguous" | "origin_disconnected" | "host_timeout" | "shutdown"; }; export type AskSettlementResult = { kind: "committed"; ack: AskSelectedAckOutcome; } | { kind: "resolved_without_commit"; } | { kind: "invalid_closed"; }; export interface AskRemoteReceipt { source: "remote"; interaction: AskRemoteInteraction; settle(value: AskSettlement): Promise; } export type AskAnswerSourceResult = AskRemoteReceipt | string | undefined; /** * Source of remote answers for interactive asks. `awaitAnswer` remains the legacy * wire for existing integrations; typed sources opt into `awaitAnswerRequest`. * This keeps a string-only source from accidentally acquiring acknowledgement * authority while allowing SDK-routed interactions to settle durably. */ export interface AskAnswerSource { awaitAnswer(question: string, options: string[], signal?: AbortSignal): Promise; awaitAnswerRequest?(request: AskAnswerRequest, signal?: AbortSignal): Promise; } /** Session context for tool factories */ export interface ToolSession { /** Current working directory */ cwd: string; /** Whether UI is available */ hasUI: boolean; /** Whether this session will bind a workflow-gate emitter after tool construction. */ workflowGateEligible?: boolean; /** Skip Python kernel availability check and warmup */ skipPythonPreflight?: boolean; /** Pre-loaded context files (AGENTS.md, etc) */ contextFiles?: ContextFileEntry[]; /** Pre-loaded workspace tree (forwarded to subagents to skip re-scanning) */ workspaceTree?: WorkspaceTree; /** Pre-loaded skills */ /** * Explicit user home for runtime skill discovery. Tests construct sessions * against an isolated home because the trusted-home resolver deliberately * ignores `$HOME` on Linux (it reads the NSS account database instead), so a * `process.env.HOME` override cannot steer user-scope discovery there. * * Production sessions leave this unset and the trusted OS home governs. * Runtime discovery only; never threaded into capability loading. */ home?: string; skills?: Skill[]; /** Currently executing skill prompt, when this tool session is inside one. */ getActiveSkillState?: () => Pick | undefined; /** Get the active skill prompt's current phase so the skill tool can apply * its terminal-phase chain guard. Returns the raw phase string or undefined * when no active skill (or accessor) is available. */ getActiveSkillPhase?: () => string | undefined; /** Restrict provider-facing deep-interview ask metadata to the active workflow stage. */ getDeepInterviewAskStage?: () => "topology" | "post-topology" | undefined; /** Pre-loaded prompt templates */ promptTemplates?: PromptTemplate[]; /** Whether LSP integrations are enabled */ enableLsp?: boolean; /** Whether an edit-capable tool is available in this session (controls hashline output) */ hasEditTool?: boolean; /** Event bus for tool/extension communication */ eventBus?: EventBus; /** Output schema for structured completion (subagents) */ outputSchema?: unknown; /** Whether to include the yield tool by default */ requireYieldTool?: boolean; /** Task recursion depth (0 = top-level, 1 = first child, etc.) */ taskDepth?: number; /** Current role-agent type/name for nested task sessions. */ currentAgentType?: string; /** Get session file */ getSessionFile: () => string | null; /** Get eval kernel owner ID for session-scoped retained-kernel cleanup. */ getEvalKernelOwnerId?: () => string | null; /** Reject new eval (python or js) work once session disposal has started. */ assertEvalExecutionAllowed?: () => void; /** Track tool-owned eval work so session disposal can await/abort it like direct session eval runs. */ trackEvalExecution?(execution: Promise, abortController: AbortController): Promise; /** Register a safe request handler that asks a managed foreground bash call to fold into a background job. */ registerForegroundBashBackgroundRequestHandler?: (handler: () => void) => () => void; /** Whether a managed foreground bash call is currently foldable into a background job. */ hasForegroundBashBackgroundRequestHandler?: () => boolean; /** Request that the active managed foreground bash call fold into a background job, if supported. */ requestForegroundBashBackground?: () => boolean; /** Get the session-owned or inherited async job manager. */ getAsyncJobManager?: () => AsyncJobManager | undefined; /** Resolves when the session queues user steering (or `signal` aborts) without consuming it; wait-style tools use this to end their observation early. */ waitForUserSteering?: (signal: AbortSignal) => Promise; /** Get session ID */ getSessionId?: () => string | null; /** Get credential-selection session identity. */ getCredentialSessionId?: () => string | null; /** Scope-held MCP facade for mcp:// resolution. */ getMcpManager?: () => import("../runtime-mcp/manager").MCPManager | undefined; /** Whether local:// must use external managed scratch instead of artifacts/local. */ isManagedSessionDestination?: () => boolean; /** Get Hindsight runtime state for this agent session. */ getHindsightSessionState?: () => HindsightSessionState | undefined; /** Agent identity used for IRC routing. Returns the registry id (e.g. "0-Main", "0-AuthLoader"). */ getAgentId?: () => string | null; /** Look up a registered tool by name (used by the eval js backend's tool bridge). */ getToolByName?: (name: string) => AgentTool | undefined; /** Look up a registered tool with the session's execution guards applied. */ getToolForExecution?: (name: string) => AgentTool | undefined; /** Purge undelivered queued custom messages matching the predicate. Returns counts. */ purgeQueuedCustomMessages?: (predicate: (message: CustomMessage) => boolean) => PurgeQueuedCustomMessagesResult; /** Agent registry for IRC routing across live sessions. */ agentRegistry?: AgentRegistry; /** Optional restricted bash command prefixes for read-only role agents and constrained modes. */ bashAllowedPrefixes?: string[]; /** Restriction policy for sessions that deliberately expose a narrow bash surface. */ bashRestrictionProfile?: BashRestrictionProfile; /** Optional per-session allowlist for tools exposed through search_tool_bm25. */ discoverableToolAllowedNames?: readonly string[]; /** Throw instead of warn when toolNames contains an unknown name. */ strictToolNames?: boolean; /** Get artifacts directory for artifact:// URLs */ getArtifactsDir?: () => string | null; /** Additional artifacts directories explicitly authorized for this session's tree (parent/child/sibling reads). Derived only from the explicitly adopted/shared `ArtifactManager`; never enumerates unrelated live sessions. */ getAuthorizedArtifactsDirs?: () => readonly string[]; /** Get the ArtifactManager backing this session (shared across parent + subagents). */ getArtifactManager?: () => ArtifactManager | null; /** Prove that an ArtifactManager belongs to this concrete session or its explicitly adopted parent tree. */ isArtifactManagerAuthorized?: (manager: ArtifactManager) => boolean; /** Adopt a task-created fallback manager into the concrete session owner. */ adoptArtifactManager?: (manager: ArtifactManager) => void; /** Linearizably establish the concrete session owner's canonical artifact manager. */ ensureArtifactManager?: () => Promise; /** Release a task-created fallback manager when its logical session ends. */ releaseArtifactManager?: (manager: ArtifactManager) => void; /** Register teardown work owned by the current logical session. */ registerSessionCleanup?: (cleanup: () => Promise | void) => () => void; /** Allocate a new artifact path and ID for session-scoped truncated output. */ allocateOutputArtifact?: (toolType: string) => Promise<{ id?: string; path?: string; }>; /** Get session spawns */ getSessionSpawns: () => string | null; /** Get resolved model string if explicitly set for this session */ getModelString?: () => string | undefined; /** Current model, when selected. */ model?: Model; /** Get the current session model string, regardless of how it was chosen */ getActiveModelString?: () => string | undefined; /** Auth storage for passing to subagents (avoids re-discovery) */ authStorage?: import("../session/auth-storage").AuthStorage; /** Model registry for passing to subagents (avoids re-discovery) */ modelRegistry?: import("../config/model-registry").ModelRegistry; /** Agent output manager for unique agent:// IDs across task invocations */ agentOutputManager?: AgentOutputManager; /** Settings instance for passing to subagents */ settings: Settings; /** * The session's REQUESTED effective agent directory, independent of the * global Settings singleton (which can be reused across sessions). */ getSessionAgentDir?: () => string; /** Live service-tier intent of the parent session, inherited by `inherit` subagents. */ serviceTier?: ServiceTier; /** Whether the effective subagent tier grants fast mode for a resolved provider. */ isFastForSubagentProvider?: (provider?: string, supportsServiceTier?: boolean) => boolean; /** Plan mode state (if active) */ getPlanModeState?: () => PlanModeState | undefined; /** Goal mode state (if active or paused) */ getGoalModeState?: () => GoalModeState | undefined; /** SDK workflow-gate emitter, when a remote gate responder is connected. */ getWorkflowGateEmitter?: () => WorkflowGateEmitter | undefined; /** * Optional SDK-routed answer source for interactive asks. When present, the * tool races the local UI selection against the remote SDK answer. * No-op when undefined: the ask path behaves exactly as before. */ getAskAnswerSource?: () => AskAnswerSource | undefined; /** Optional per-session restriction for goal tool operations. */ goalToolAllowedOps?: readonly ("create" | "get" | "complete" | "resume" | "drop" | "pause")[]; /** Goal runtime for the active agent session. */ getGoalRuntime?: () => GoalRuntime | undefined; /** * Agent-invokable session rescope (issue #4629): move the whole session to * an existing directory, running the same sequence as the `/move` handler * (flush → moveTo → setProjectDir → plugin/capability cache reset). Absent * in contexts where relocation must not happen: subagent sessions * (taskDepth > 0) and read-only/restricted bash profiles. Bound to one * successful move per session, rejects re-entrant calls, and only narrows: * the canonical (realpath) target must be a strict descendant of the * canonical current cwd. Throws when the target does not exist, is not a * directory, or escapes the current scope. */ rescopeSessionCwd?: (path: string) => Promise<{ from: string; to: string; }>; /** Bridge to the connected client (e.g. ACP editor host). Tools should route fs/terminal/permission requests through this when available. */ getClientBridge?: () => ClientBridge | undefined; /** Get compact conversation context for subagents (excludes tool results, system prompts) */ getCompactContext?: () => string; /** Get cached todo phases for this session. */ getTodoPhases?: () => TodoPhase[]; /** Replace cached todo phases for this session. */ setTodoPhases?: (phases: TodoPhase[]) => void; /** Explicit top-level MCP config path; affects effective discovery mode before manager setup. */ mcpConfigPath?: string; /** Whether any form of tool discovery is active (tools.discoveryMode !== "off" or mcp.discoveryMode). */ isToolDiscoveryEnabled?: () => boolean; /** Get all hidden-but-discoverable tools for search_tool_bm25 prompts. */ getDiscoverableTools?: (filter?: { source?: import("../tool-discovery/tool-index").DiscoverableToolSource; }) => DiscoverableTool[]; /** Get the cached generic discoverable search index. */ getDiscoverableToolSearchIndex?: () => DiscoverableToolSearchIndex; /** Get tool names activated by prior search_tool_bm25 calls (all sources). */ getSelectedDiscoveredToolNames?: () => string[]; /** Merge tool selections into the active session tool set. */ activateDiscoveredTools?: (toolNames: string[]) => Promise; /** The tool-choice queue used to force forthcoming tool invocations and carry invocation handlers. */ getToolChoiceQueue?(): ToolChoiceQueue; /** Build a model-provider-specific ToolChoice that targets the named tool, or undefined if unsupported. */ buildToolChoice?(toolName: string): ToolChoice | undefined; /** Build a named tool-choice decision, preserving whether exact named forcing survived capability degradation. */ buildToolChoiceResult?(toolName: string): import("../utils/tool-choice").NamedToolChoiceResult; /** Steer a hidden custom message into the conversation (e.g. a preview reminder). */ steer?(message: { customType: string; content: string; details?: unknown; }): void; /** Peek the currently in-flight tool-choice queue directive's invocation handler. Used by the `resolve` tool to dispatch to the pending action. */ peekQueueInvoker?(): ((input: unknown) => Promise | unknown) | undefined; /** Peek the long-lived "standing" resolve handler registered by a mode (e.g. plan mode). * Consulted by the `resolve` tool as a fallback when no queue invoker is in flight, * letting modes accept `resolve` invocations without forcing the tool choice every turn. */ peekStandingResolveHandler?(): ((input: unknown) => Promise | unknown) | undefined; /** Register or clear the standing resolve handler. Passing `null` clears it. */ setStandingResolveHandler?(handler: ((input: unknown) => Promise | unknown) | null): void; /** Get active checkpoint state if any. */ getCheckpointState?: () => CheckpointState | undefined; /** Set or clear active checkpoint state. */ setCheckpointState?: (state: CheckpointState | null) => void; /** Per-session cache of file contents as last shown to the model by * `read`/`search`. Used by hashline anchor-stale recovery to reconstruct * the version the model authored anchors against when the file changed * out-of-band. Lazily initialized by `getFileReadCache`. */ fileReadCache?: import("../edit/file-read-cache").FileReadCache; /** Per-session log of unresolved git merge conflict regions surfaced by * `read`. Each entry gets a stable id N referenced by `write conflict://N` * to splice the recorded region with replacement content. Lazily initialized * by `getConflictHistory`. */ conflictHistory?: import("./conflict-detect").ConflictHistory; /** Queue a hidden message to be injected at the next agent turn. */ queueDeferredMessage?(message: CustomMessage): void; /** Dispatch a custom message through the active session. Used by the `skill` * tool to dispatch another skill prompt same-turn after recording a handoff. */ sendCustomMessage?(message: Pick, options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn"; }): Promise; /** Get the active OpenTelemetry config so subagent dispatch can forward * the parent's tracer/hooks with the subagent's own identity stamped. */ getTelemetry?: () => AgentTelemetryConfig | undefined; /** Build a sanitized fork-context seed for task subagents. */ buildForkContextSeed?: (options: ForkContextSeedOptions) => Promise; } export type ToolFactory = (session: ToolSession) => Tool | null | Promise; export type BuiltinToolLoadMode = "essential" | "discoverable"; /** Default essential tool names when tools.essentialOverride is empty. */ export declare const DEFAULT_ESSENTIAL_TOOL_NAMES: readonly string[]; /** * Resolve the active essential built-in tool names from settings. * Returns `tools.essentialOverride` if non-empty (filtered to known built-ins), * otherwise `DEFAULT_ESSENTIAL_TOOL_NAMES`. */ export declare function computeEssentialBuiltinNames(settings: Settings): string[]; /** * Public callable factory map. External callers may invoke `BUILTIN_TOOLS.read(session)` or * `BUILTIN_TOOLS[name](session)` to construct a public coding-harness tool directly. * * Hindsight memory helpers are intentionally excluded: memory is a private backend * integration, not a public gajae-code tool surface. */ export interface BuiltinCapabilityCatalogEntry { name: string; label: string; summary: string; docsPath: string; callableBuiltin: boolean; defaultEnabled: boolean; } export declare const BUILTIN_CAPABILITY_CATALOG: readonly BuiltinCapabilityCatalogEntry[]; export type ToolName = keyof typeof BUILTIN_TOOLS; export interface EvalBackendsAllowance { python: boolean; js: boolean; } /** * Parse the `GJC_PY` multi-value token into per-backend booleans. * * Tokens (case-insensitive): * - `0` / `bash` → JavaScript only (`{ py: false, js: true }`) * - `1` / `py` → Python only (`{ py: true, js: false }`) * - `js` → JavaScript only (`{ py: false, js: true }`) * - `mix` / `both` → both backends (`{ py: true, js: true }`) * * Returns `null` when `GJC_PY` is unset, empty, or holds an unrecognized * token, so the caller can fall back to the legacy `PI_PY` / `PI_JS` flags or * per-key settings. This matches the documented contract that invalid values * are ignored. */ export declare function parseGjcPy(env: Record): { py: boolean; js: boolean; } | null; /** * Resolve eval-backend allowance from environment only. `GJC_PY` wins when set * to a recognized token; otherwise the legacy `PI_PY` / `PI_JS` flags apply. * Returns `null` when no env override is set so the caller can defer to settings. */ export declare function resolveEvalBackendsFromEnv(env: Record): EvalBackendsAllowance | null; /** Read per-backend allowance from settings (defaults true). */ export declare function readEvalBackendsAllowance(session: ToolSession): EvalBackendsAllowance; /** * Materialize the active eval backend allowance. `GJC_PY` takes precedence * over the legacy `PI_PY` / `PI_JS` env flags, which in turn override the * per-key settings (defaults true). When no env override is set, settings win. */ export declare function resolveEvalBackends(session: ToolSession): EvalBackendsAllowance; /** * Create tools from the descriptor registry. */ export declare function createTools(session: ToolSession, toolNames?: string[], automationTools?: AutomationTools): Promise;