@drover/core

Public types and identity builders. No runtime.

The substrate every other drover package depends on. Pure types and a couple of identity builders.

Exports

ts
import {
  defineAgent,
  defineTool,
  // types
  type AgentSpec, type AgentInput, type AgentOutput,
  type ModelSpec, type ReasoningLevel, type SubagentConfig,
  type SystemPromptFn,
  type RunContext,
  type RunResult, type RunStatus,
  type HarnessEvent, type EventOfKind,
  type ToolResult, type Usage,
  type HarnessPlugin, type ToolDecision, type ErrorRecovery,
  type HistoryMessage,
  type ToolDef, type AnyToolDef, type ToolExecutionContext,
  // errors
  type HarnessError,
  InputValidationError, OutputValidationError,
  SubagentLimitError, QuotaExceededError,
  CancelledError, PausedForConfirmationError,
  ModelError, SandboxError, StorageError, PluginError,
} from "@drover/core";

defineAgent

ts
function defineAgent<I extends TSchema, O extends TSchema>(
  spec: AgentSpec<I, O>
): AgentSpec<I, O>;

Identity builder. Returns the spec unchanged; exists so TypeScript infers Static<I> and Static<O> at call sites without manual generics. See AgentSpec.

defineTool

ts
function defineTool<S extends TSchema>(tool: ToolDef<S>): ToolDef<S>;

Identity builder for ToolDef. Captures the TypeBox schema once so execute sees a statically-typed input.

Errors

Every drover error is a Data.TaggedError from Effect, so consumers can match by _tag:

ts
import { OutputValidationError } from "@drover/core";

if (err._tag === "OutputValidationError") {
  // err.attempts, err.lastIssues, err.lastText all typed
}

The aggregate union is HarnessError. Use that as the Effect error channel when composing.

RunResult

ts
interface RunResult<TOutput = unknown> {
  runId: string;
  status: "success" | "quota" | "cancelled" | "error" | "paused";
  output?: TOutput;
  finalText: string;
  turns: number;
  durationMs: number;
  usage: { inputTokens: number; outputTokens: number; costUsd?: number; ... };
  toolCalls: readonly string[];
  error?: { tag: string; message: string };
}

status: "paused" only when storage was wired and handle.pause() was called. The Promise resolution NEVER rejects — typed errors fold into error.

Tagged errors quick reference

_tagwhen
InputValidationErrorinput failed inputSchema
OutputValidationErroroutput failed outputSchema after retry budget
SubagentLimitErrordepth/fan-out/allowed limit hit
QuotaExceededErrora run budget (turns / duration / cost) was exhausted
CancelledErrorcaller aborted
PausedForConfirmationErrorconfirm-gate triggered (reserved for runtime)
ModelErrorrouting miss / circuit open / provider error / auth
SandboxErrorsandbox refused or failed an exec/read/write
StorageErrorstorage adapter failure
PluginErrorplugin hook threw

Type to search…

↑↓ navigate open esc close