import {
  _ as LifecycleJobContext,
  n as CapabilityStartContext,
  s as LifecycleCapability,
  v as LifecycleJobOutcome
} from "../../capability-runner-BiVUtjqC.js";
import { a as SkillSource } from "../../source-9RQzlEhM.js";
import {
  AgentChange,
  Conversation,
  ConversationWatch,
  ConversationWindow,
  Cursor,
  EntryQuery,
  EntryRecord,
  Extension,
  Harness,
  InputEntry,
  Page,
  UserInput,
  Wake
} from "@earendil-works/pi-durable";
import { Context } from "@earendil-works/chord/context";
import { Api, Model, ModelThinkingLevel } from "@earendil-works/pi-ai";
import { SqliteStorage } from "@earendil-works/pi-durable/storage/sqlite";

//#region src/harness/pi/types.d.ts
/**
 * `PiHarness`'s own types: how the harness addresses sessions and reports
 * operations. Anything pi already publishes (input, transcript entries,
 * events) is pi's type, used directly.
 */
/** A pi conversation, addressed by its id as a string. The root is `"1"`. */
type PiSessionId = string;
/**
 * What a submission does when the session is already running.
 *
 * - `followUp` (default): answered after the current run, as its own run.
 * - `steer`: joins the running work after the current tool round.
 * - `reject`: not admitted. `submit()` rejects with pi-durable's
 *   `ConversationBusy` and saves nothing, so the same `operationId` can be
 *   submitted again later. Use it to submit only if idle, atomically.
 */
type PiWhenBusy = "followUp" | "steer" | "reject";
/**
 * What a submission does when the session is idle.
 *
 * - unset (default): starts a run.
 * - `reject`: not admitted. `submit()` rejects with pi-durable's
 *   `ConversationIdle` and saves nothing. With `whenBusy: "steer"`, the
 *   input joins the running work or is refused, in one step that cannot
 *   race the run's end.
 */
type PiWhenIdle = "reject";
type PiSubmitOptions = {
  /** Default: the root session. */ readonly session?: PiSessionId /** Idempotency key. Submitting the same id twice returns the same receipt. */;
  readonly operationId?: string;
  readonly whenBusy?: PiWhenBusy;
  readonly whenIdle?: PiWhenIdle;
  /**
   * The transcript entry the input is placed as, instead of pi's `pi.user`:
   * for input the user did not type, such as a scheduled prompt, a webhook,
   * or an approval's outcome. The model still gets the input as a user
   * message; `kind` and `data` record where it came from. The kind must not
   * start with `pi.`.
   */
  readonly entry?: InputEntry;
};
type PiContinueOptions = {
  /** Idempotency key. Continuing with the same id twice returns the same receipt. */ readonly operationId?: string;
};
type PiSessionOptions = {
  /** Default: the root session. */ readonly session?: PiSessionId;
};
/** Returned once a submission is durable. It says nothing about the model yet. */
type PiReceipt = {
  readonly operationId: string;
  readonly session: PiSessionId /** False when this operation id was already submitted. */;
  readonly accepted: boolean;
};
/** How one operation ended. */
type PiOperationResult = {
  readonly operationId: string;
  readonly session: PiSessionId /** `done`: answered. `unanswered`: failed, aborted, or withdrawn. */;
  readonly status:
    | "done"
    | "unanswered" /** Why an unanswered operation ended, in pi's words. */;
  readonly reason?: string /** The final assistant text, when answered. */;
  readonly text?: string;
};
type PiPromptResponse = PiOperationResult & {
  /** The session's active transcript after the operation. */ readonly messages: readonly EntryRecord[];
};
/** A submission pi has not settled yet. */
type PiPendingOperation = {
  readonly operationId: string;
  readonly session: PiSessionId /** `queued` in pi's inbox, or `running` as part of the current run. */;
  readonly status: "queued" | "running";
};
type PiSessionInfo = {
  readonly id: PiSessionId /** The session this one was forked from. */;
  readonly parent?: PiSessionId;
  readonly busy: boolean;
};
//#endregion
//#region src/harness/pi/harness.d.ts
/** The root session's id. */
declare const ROOT_SESSION: PiSessionId;
/**
 * What the factory is handed: the things only the harness can build.
 * Everything else `Harness.open` takes (models, registry, settings, env,
 * onReport) the factory builds itself.
 */
type PiHarnessContext = {
  /** pi's storage over this object's SQLite, its migrations already run. */ readonly storage: SqliteStorage /** Background context, for the open itself. */;
  readonly context: Context;
  /**
   * Pass this to `Harness.open` as its `onWake` option. pi calls it when it
   * next needs to run, and the harness sets this object's alarm for then.
   *
   * With it, pi sets no in-memory timer for a sleeping task (a retry
   * backoff, a poll, a `sleepUntil`), so the object can hibernate until the
   * alarm. Without it the harness still works, but pi's timer keeps the
   * object in memory, and billed, while a task sleeps, and the harness logs
   * a warning when it opens pi.
   *
   * The harness reads pi's wake times against `Date.now()`, so do not pass
   * `now` to `Harness.open`.
   */
  readonly onWake: (wake: Wake) => void;
};
/**
 * Opens pi's `Harness`. The harness adopts what it returns. Pass `onWake`
 * through to `Harness.open`.
 *
 * ```ts
 * harness: async ({ storage, context, onWake }) => {
 *   const registry = createRegistry();
 *   registry.install(await skills(sources));
 *   return Harness.open(storage, { models, registry, onWake }, context);
 * }
 * ```
 */
type PiHarnessFactory = (
  context: PiHarnessContext
) => Harness | Promise<Harness>;
/**
 * A model, as pi-ai describes one: `createAI`'s `ai("@cf/…")` returns one.
 *
 * Only its `provider` and `id` are used. pi stores that reference with
 * the session and resolves it, at each request, against the `Models` the
 * factory opened pi with. So the model must be one those `Models` list,
 * and options passed to `ai(id, options)` here, such as `fallback`, are not
 * applied.
 */
type PiModel = Pick<Model<Api>, "provider" | "id">;
/**
 * Applied to a session the first time it is created. Without a model, a
 * session's generation fails as unanswered until `session.setModel` sets one.
 */
type PiSessionDefaults = {
  /**
   * Model for new sessions, by its `provider` and `id`; it must be on the
   * `Models` the factory opens pi with (see `PiModel`). Change one
   * session's with `session.setModel`.
   */
  readonly model?: PiModel;
  readonly thinkingLevel?: ModelThinkingLevel;
  /**
   * Most tool rounds one run takes: the round that reaches it runs its
   * tools, then the run's operations end unanswered with reason
   * `turn_limit`. An integer, 1 or more. Default: no limit.
   */
  readonly maxTurns?: number;
};
/** `PiHarness`'s options. Only `harness`, which opens pi, is required. */
type PiHarnessOptions = {
  /** Opens pi's `Harness` over the storage this object prepared. */ readonly harness: PiHarnessFactory /** What a new session starts with. */;
  readonly defaults?: PiSessionDefaults;
};
/**
 * pi-durable hosted in a Durable Object, behind a small harness interface:
 * `harness.prompt()`, `harness.sessions`, `harness.session(id)`. How a session reaches a
 * client (sockets, SSE, RPC) is the host's glue, built on `session.events()`.
 *
 * pi owns everything about a run: the transcript, the inbox of steers and
 * follow-ups, generation and tool tasks, retries, crash recovery, and the
 * live view. It keeps all of it in its own tables in this object's SQLite
 * database (see `session-store.ts`).
 *
 * What pi cannot do on a Durable Object is wake itself: its scheduler runs
 * in memory, and an evicted object has no memory. The harness is that wake,
 * with one Lifecycle job driven by `pi.wake()`. Input goes to pi once, in
 * `submit()`, after the job is scheduled. While pi has work running, the
 * job waits on it, rescheduling itself as a heartbeat. While pi's tasks
 * sleep, the job is due when the first one wakes; pi tells the harness
 * through the `onWake` the factory passes to `Harness.open`. When pi has
 * nothing to do, the job completes. An eviction mid-run leaves the job due,
 * so its alarm restarts the object, pi reopens and resumes its own tasks,
 * and the job waits again.
 */
declare class PiHarness extends LifecycleCapability {
  #private;
  readonly sessions: PiSessions;
  constructor(options: PiHarnessOptions);
  onStart(_context: CapabilityStartContext): Promise<void>;
  onJob(context: LifecycleJobContext): Promise<LifecycleJobOutcome | void>;
  /**
   * A wake dispatch that failed through Lifecycle's retries, as when pi
   * cannot be opened. Lifecycle would complete the job, and pi's work would
   * never be woken again, so try again later: at the heartbeat, doubling
   * while the failures continue, up to 10 minutes.
   */
  onJobError(
    context: LifecycleJobContext,
    error: unknown
  ): LifecycleJobOutcome | void;
  /** Close pi's in-memory resources. Durable state is untouched. */
  dispose(): Promise<void>;
  /** A handle on one session. No I/O until you call it. */
  session(id?: PiSessionId): PiSession;
  /** Submit a prompt and wait for its answer. */
  prompt(
    input: UserInput,
    options?: PiSubmitOptions
  ): Promise<PiPromptResponse>;
  /** Durably submit a prompt. Resolves before the model runs. */
  submit(input: UserInput, options?: PiSubmitOptions): Promise<PiReceipt>;
  /**
   * Run an idle session again on its transcript as it is, without new input.
   * See `PiSession.continue`.
   */
  continue(options?: PiSessionOptions & PiContinueOptions): Promise<PiReceipt>;
  /** Stop one operation, or everything running in a session. */
  abort(
    options?: PiSessionOptions & {
      readonly operationId?: string;
    }
  ): Promise<boolean>;
  wait(
    operationId: string,
    options?: PiSessionOptions & {
      readonly signal?: AbortSignal;
    }
  ): Promise<PiOperationResult>;
  /** The session's active transcript, as pi's entries. */
  messages(options?: PiSessionOptions): Promise<EntryRecord[]>;
  /** Submissions pi has not settled yet, oldest first. */
  pending(options?: PiSessionOptions): Promise<PiPendingOperation[]>;
  /** The opened pi Harness, for anything the interface does not cover. */
  pi(): Promise<Harness>;
  /** @internal */
  conversation(session: PiSessionId): Promise<Conversation>;
  /** @internal */
  storage(): Promise<SqliteStorage>;
  /** @internal */
  enqueue(
    session: PiSessionId,
    input: UserInput,
    options: PiSubmitOptions
  ): Promise<PiReceipt>;
  /** @internal Start a run on the context as it is, without new input. */
  enqueueContinue(
    session: PiSessionId,
    options: PiContinueOptions
  ): Promise<PiReceipt>;
  /** @internal Withdraw a queued input, or abort the run it joined. */
  withdraw(session: PiSessionId, operationId: string): Promise<boolean>;
  /** @internal Wait for pi to settle an operation, by its request id. */
  settled(
    session: PiSessionId,
    operationId: string,
    signal?: AbortSignal
  ): Promise<PiOperationResult>;
  /** @internal The per-conversation defaults supported by pi-durable. */
  agentDefaults(): AgentChange;
}
/** One pi conversation, addressed through the harness. */
declare class PiSession {
  #private;
  readonly id: PiSessionId;
  constructor(harness: PiHarness, id: PiSessionId);
  /** Durably submit a prompt. Resolves before the model runs. */
  submit(input: UserInput, options?: PiSubmitOptions): Promise<PiReceipt>;
  /** Submit and wait for the answer and the updated transcript. */
  prompt(
    input: UserInput,
    options?: PiSubmitOptions
  ): Promise<PiPromptResponse>;
  /**
   * Start a run on the transcript as it is, without a new message: for
   * example, after a run ended unanswered because the model failed or the
   * object kept crashing. Only an idle session takes one; a busy one rejects
   * with pi-durable's `ConversationBusy`. A transcript that ends in an answer
   * settles `unanswered` with reason `nothing_to_answer`.
   */
  continue(options?: PiContinueOptions): Promise<PiReceipt>;
  /** Join the running work after its current tool round. */
  steer(
    input: UserInput,
    options?: Omit<PiSubmitOptions, "whenBusy">
  ): Promise<PiReceipt>;
  /** Wait for an operation to settle. Aborting `signal` stops only the wait. */
  wait(operationId: string, signal?: AbortSignal): Promise<PiOperationResult>;
  /**
   * Withdraw one queued operation (or abort the run it joined), or, with no
   * id, abort the session: pi withdraws queued inputs and aborts the
   * running work.
   */
  abort(operationId?: string): Promise<boolean>;
  /** Start a new context, optionally from a handoff note. */
  reset(handoff?: string): Promise<void>;
  /**
   * Change this session's model, by its `provider` and `id`; it must be on
   * the `Models` the factory opened pi with (see `PiModel`).
   */
  setModel(model: PiModel): Promise<void>;
  /** The active transcript, as pi's entries since the newest reset. */
  messages(): Promise<EntryRecord[]>;
  /**
   * Watch this session: pi's conversation view, a window over the transcript
   * with the session's documents, such as `pi.live` (the answer being
   * streamed, running tools, and why the last run ended without an answer)
   * and `pi.inbox`. The first value holds the newest entries; new entries
   * are appended. Each change carries pi's operations, for a client that
   * forwards them. To render more than the window, merge each value into a
   * `ConversationTranscript` that pages with `entries()`.
   */
  watch(
    window?: ConversationWindow,
    context?: Context
  ): Promise<ConversationWatch>;
  /**
   * A page of this session's transcript, newest first unless `query.order`
   * is `ascending`, including entries before its resets. The loader a
   * `ConversationTranscript` takes.
   */
  entries(
    query: Omit<EntryQuery, "conversationId">,
    limit: number,
    context?: Context
  ): Promise<Page<EntryRecord, Cursor>>;
  busy(): Promise<boolean>;
}
/** Every pi conversation in this object. */
declare class PiSessions {
  #private;
  constructor(harness: PiHarness);
  get(id: PiSessionId): PiSession;
  /** A new top-level session, configured like the root. */
  create(): Promise<PiSession>;
  /** A new session that sees `from`'s history up to its newest entry. */
  fork(from: PiSessionId): Promise<PiSession>;
  /**
   * Every conversation, including ones subagent tools own. Read from pi's
   * storage directly: the Harness has no conversation listing.
   */
  list(): Promise<PiSessionInfo[]>;
}
//#endregion
//#region src/harness/pi/session-store.d.ts
/**
 * pi's session store on a Durable Object's SQLite database.
 *
 * pi owns its sessions: conversations, entries, tasks, submissions, and
 * documents live in pi's own schema, created and migrated by pi's portable
 * `SqliteStorage` through pi's own Durable Object adapter. The store keeps
 * pi's tables under a prefix, so they cannot collide with the SDK's or the
 * host's tables in the same object.
 *
 * It is the Durable Object counterpart of `agents/sessions` for a harness
 * that brings its own session model, and has nothing pi-harness specific in
 * it: any harness built on pi-durable can open its storage with it.
 */
type PiSessionStoreOptions = {
  /**
   * Prefix for every table and index pi creates. Must not start with `_cf_`,
   * which Durable Objects reserve. Default `pi_`.
   */
  readonly prefix?: string;
};
/** Open pi-durable's storage over this object's SQLite database. */
declare function openPiSessionStore(
  storage: DurableObjectStorage,
  options?: PiSessionStoreOptions
): Promise<SqliteStorage>;
//#endregion
//#region src/harness/pi/skills.d.ts
/**
 * `agents/skills` sources as a pi extension, named `agents.skills`: the
 * activation tools and a `skills` system prompt section. Install it on
 * pi's registry in the harness factory. Sources are read once, when the
 * extension is built.
 *
 * ```ts
 * import * as agentSkills from "agents/skills";
 *
 * registry.install(
 *   await skills([agentSkills.workspace(workspace), agentSkills.r2(env.SKILLS)])
 * );
 * ```
 *
 * @param sources - Skill sources in priority order.
 * @returns The pi extension.
 */
declare function skills(sources: readonly SkillSource[]): Promise<Extension>;
//#endregion
export {
  type PiContinueOptions,
  PiHarness,
  type PiHarnessContext,
  type PiHarnessFactory,
  type PiHarnessOptions,
  type PiModel,
  type PiOperationResult,
  type PiPendingOperation,
  type PiPromptResponse,
  type PiReceipt,
  PiSession,
  type PiSessionDefaults,
  type PiSessionId,
  type PiSessionInfo,
  type PiSessionOptions,
  type PiSessionStoreOptions,
  PiSessions,
  type PiSubmitOptions,
  type PiWhenBusy,
  type PiWhenIdle,
  ROOT_SESSION,
  openPiSessionStore,
  skills
};
//# sourceMappingURL=index.d.ts.map
