import type { TracingContext, TracingOptions } from '../observability/index.js'; import { RequestContext } from '../request-context/index.js'; import type { ObservationalMemoryRecord } from '../storage/types.js'; import { Workspace } from '../workspace/workspace.js'; import type { AvailableModel, HeartbeatHandler, HarnessConfig, HarnessDisplayState, HarnessEventListener, HarnessMessage, HarnessMode, HarnessSession, HarnessThread, ModelAuthStatus, PermissionPolicy, PermissionRules, ToolCategory } from './types.js'; /** * The Harness orchestrates multiple agent modes, shared state, memory, and storage. * It's the core abstraction that a TUI (or other UI) controls. * * @example * ```ts * const harness = new Harness({ * id: "my-coding-agent", * storage: new LibSQLStore({ url: "file:./data.db" }), * stateSchema: z.object({ * currentModelId: z.string().optional(), * }), * modes: [ * { id: "plan", name: "Plan", default: true, agent: planAgent }, * { id: "build", name: "Build", agent: buildAgent }, * ], * }) * * harness.subscribe((event) => { * if (event.type === "message_update") renderMessage(event.message) * }) * * await harness.init() * await harness.sendMessage({ content: "Hello!" }) * ``` */ export declare class Harness { #private; readonly id: string; private config; private stateSchema; private state; private currentModeId; private currentThreadId; private resourceId; private defaultResourceId; private listeners; private abortController; private abortRequested; private currentRunId; private currentOperationId; private followUpQueue; private pendingApprovalResolve; private pendingApprovalToolName; private pendingSuspensionRunId; private pendingSuspensionToolCallId; private pendingQuestions; private pendingPlanApprovals; private workspace; private workspaceFn; private workspaceInitialized; private browser; private browserFn; private heartbeatTimers; private tokenUsage; private sessionGrantedCategories; private sessionGrantedTools; private displayState; constructor(config: HarnessConfig); /** * Initialize the harness — loads storage and workspace. * Must be called before using the harness. */ init(): Promise; /** * Select the most recent thread, or create one if none exist. */ selectOrCreateThread(): Promise; private getMemoryStorage; /** * Get current harness state (read-only snapshot). */ getState(): Readonly; /** * Update harness state. Validates against schema if provided. * Emits state_changed event. */ setState(updates: Partial): Promise; private getSchemaDefaults; listModes(): HarnessMode[]; getCurrentModeId(): string; getCurrentMode(): HarnessMode; /** * Switch to a different mode. * Aborts any in-progress generation and switches to the mode's default model. */ switchMode({ modeId }: { modeId: string; }): Promise; /** * Load the stored model ID for a specific mode. * Falls back to: thread metadata -> mode's defaultModelId -> current model. */ private loadModeModelId; /** * Get the agent for the current mode. */ private getCurrentAgent; /** * Get a short display name from the current model ID. */ getModelName(): string; /** * Get the full model ID (e.g., "anthropic/claude-sonnet-4"). */ getFullModelId(): string; /** * Switch to a different model at runtime. */ switchModel({ modelId, scope, modeId, }: { modelId: string; scope?: 'global' | 'thread'; modeId?: string; }): Promise; getCurrentModelId(): string; hasModelSelected(): boolean; /** * Check if the current model's provider has authentication configured. * Uses the provider registry's `apiKeyEnvVar` and the optional `modelAuthChecker` hook. */ getCurrentModelAuthStatus(): Promise; /** * Get all available models from the provider registry with auth status. * Uses the optional `modelAuthChecker`, `modelUseCountProvider`, and * `customModelCatalogProvider` hooks. */ listAvailableModels(): Promise; private getProviderApiKeyEnvVar; getCurrentThreadId(): string | null; getResourceId(): string; setResourceId({ resourceId }: { resourceId: string; }): void; getDefaultResourceId(): string; getKnownResourceIds(): Promise; createThread({ title }?: { title?: string; }): Promise; /** * Returns a memory accessor with thread and message management methods. */ get memory(): { createThread: ({ title }?: { title?: string; }) => Promise; switchThread: ({ threadId }: { threadId: string; }) => Promise; listThreads: (options?: { allResources?: boolean; }) => Promise; renameThread: ({ title }: { title: string; }) => Promise; deleteThread: ({ threadId }: { threadId: string; }) => Promise; }; private deleteThread; renameThread({ title }: { title: string; }): Promise; cloneThread({ sourceThreadId, title, resourceId, }?: { sourceThreadId?: string; title?: string; resourceId?: string; }): Promise; switchThread({ threadId }: { threadId: string; }): Promise; listThreads(options?: { allResources?: boolean; }): Promise; setThreadSetting({ key, value }: { key: string; value: unknown; }): Promise; private deleteThreadSetting; private loadThreadMetadata; /** * Load observational memory progress for the current thread. * Reads the OM record and recent messages to reconstruct status, * then emits an `om_status` event for the UI. */ loadOMProgress(): Promise; getObservationalMemoryRecord(): Promise; /** * Returns the observer model ID from state, falling back to omConfig defaults. */ getObserverModelId(): string | undefined; /** * Returns the reflector model ID from state, falling back to omConfig defaults. */ getReflectorModelId(): string | undefined; /** * Returns the observation threshold from state, falling back to omConfig defaults. */ getObservationThreshold(): number | undefined; /** * Returns the reflection threshold from state, falling back to omConfig defaults. */ getReflectionThreshold(): number | undefined; /** * Resolves the observer model ID to a language model instance via `resolveModel`. */ getResolvedObserverModel(): import("../memory").MastraLanguageModel | undefined; /** * Resolves the reflector model ID to a language model instance via `resolveModel`. */ getResolvedReflectorModel(): import("../memory").MastraLanguageModel | undefined; /** * Switch the Observer model. */ switchObserverModel({ modelId }: { modelId: string; }): Promise; /** * Switch the Reflector model. */ switchReflectorModel({ modelId }: { modelId: string; }): Promise; getSubagentModelId({ agentType }?: { agentType?: string; }): string | null; setSubagentModelId({ modelId, agentType }: { modelId: string; agentType?: string; }): Promise; grantSessionCategory({ category }: { category: ToolCategory; }): void; grantSessionTool({ toolName }: { toolName: string; }): void; getSessionGrants(): { categories: ToolCategory[]; tools: string[]; }; getToolCategory({ toolName }: { toolName: string; }): ToolCategory | null; setPermissionForCategory({ category, policy }: { category: ToolCategory; policy: PermissionPolicy; }): void; setPermissionForTool({ toolName, policy }: { toolName: string; policy: PermissionPolicy; }): void; getPermissionRules(): PermissionRules; /** * Resolve whether a tool call should be auto-approved, denied, or asked. * Resolution chain: yolo → per-tool policy → session tool grant → * session category grant → category policy → "ask" */ private resolveToolApproval; /** * Send a message to the current agent. * Streams the response and emits events. */ sendMessage({ content, files, tracingContext, tracingOptions, requestContext: requestContextInput, }: { content: string; files?: Array<{ data: string; mediaType: string; filename?: string; }>; tracingContext?: TracingContext; tracingOptions?: TracingOptions; requestContext?: RequestContext; }): Promise; listMessages(options?: { limit?: number; }): Promise; listMessagesForThread({ threadId, limit }: { threadId: string; limit?: number; }): Promise; getFirstUserMessageForThread({ threadId }: { threadId: string; }): Promise; getFirstUserMessagesForThreads({ threadIds }: { threadIds: string[]; }): Promise>; private convertToHarnessMessage; /** * Process a stream response (shared between sendMessage and tool approval). */ private processStream; /** * Abort the current operation. */ abort(): void; /** * Steer the agent mid-stream: aborts current run and sends a new message. */ steer({ content, requestContext }: { content: string; requestContext?: RequestContext; }): Promise; /** * Queue a follow-up message to be processed after the current operation completes. */ followUp({ content, requestContext }: { content: string; requestContext?: RequestContext; }): Promise; getFollowUpCount(): number; isRunning(): boolean; getCurrentRunId(): string | null; /** * Returns a read-only snapshot of the canonical display state. * UIs should use this to render instead of building up state from raw events. */ getDisplayState(): Readonly; /** * Reset display state fields that are scoped to a thread. * Called on thread switch/creation. */ private resetThreadDisplayState; /** * Respond to a pending tool approval from the UI. * "always_allow_category" grants the tool's category for the rest of the session, then approves. */ respondToToolApproval({ decision, requestContext, }: { decision: 'approve' | 'decline' | 'always_allow_category'; requestContext?: RequestContext; }): void; /** * Respond to a pending tool suspension from the UI. * Provides resume data so the suspended tool can continue execution. */ respondToToolSuspension({ resumeData, requestContext, }: { resumeData: any; requestContext?: RequestContext; }): Promise; /** * Register a pending question resolver. * Called by agent tools (e.g., ask_user) to pause execution until the UI responds. */ registerQuestion({ questionId, resolve }: { questionId: string; resolve: (answer: string) => void; }): void; /** * Resolve a pending question with the user's answer. * Called by the UI when the user responds to a question dialog. */ respondToQuestion({ questionId, answer }: { questionId: string; answer: string; }): void; /** * Register a pending plan approval resolver. * Called by agent tools (e.g., submit_plan) to pause execution until approval. */ registerPlanApproval({ planId, resolve, }: { planId: string; resolve: (result: { action: 'approved' | 'rejected'; feedback?: string; }) => void; }): void; /** * Respond to a pending plan approval. * On approval: switches to the default mode, then resolves the promise. * On rejection: resolves with feedback (stays in current mode). */ respondToPlanApproval({ planId, response, }: { planId: string; response: { action: 'approved' | 'rejected'; feedback?: string; }; }): Promise; private handleToolApprove; private handleToolDecline; private handleToolResume; /** * Subscribe to harness events. Returns an unsubscribe function. */ subscribe(listener: HarnessEventListener): () => void; private emit; private dispatchToListeners; /** * Apply a display state update based on an incoming event. * This is the centralized state machine that keeps HarnessDisplayState in sync * with every event the Harness emits. */ private applyDisplayStateUpdate; /** * Build the toolsets object that includes built-in harness tools (ask_user, submit_plan, * and optionally subagent) plus any user-configured tools. * Used by sendMessage, handleToolApprove, and handleToolDecline. */ private buildToolsets; /** * Build request context for agent execution. * Tools can access harness state via requestContext.get('harness'). */ private buildRequestContext; /** * Resolve memory from config — handles both static instances and dynamic factory functions. */ private resolveMemory; getTokenUsage(): { promptTokens: number; completionTokens: number; totalTokens: number; }; private persistTokenUsage; getWorkspace(): Workspace | undefined; /** * Eagerly resolve the workspace. For dynamic workspaces (factory function), * this triggers resolution and caches the result so getWorkspace() returns it. * Useful for code paths outside the request flow (e.g. slash commands). */ resolveWorkspace({ requestContext, }?: { requestContext?: RequestContext; }): Promise; hasWorkspace(): boolean; isWorkspaceReady(): boolean; destroyWorkspace(): Promise; private startHeartbeats; registerHeartbeat(handler: HeartbeatHandler): void; removeHeartbeat({ id }: { id: string; }): Promise; stopHeartbeats(): Promise; destroy(): Promise; getSession(): Promise; private generateId; } //# sourceMappingURL=harness.d.ts.map