import "reflect-metadata";
import { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest } from "./agent-runner.mjs";
import { Observable, ReplaySubject } from "rxjs";
import { AbstractAgent, BaseEvent, Message } from "@ag-ui/client";

//#region src/v2/runtime/runner/in-memory.d.ts
interface InMemoryLimits {
  /** LRU cap on distinct threads. */
  maxThreads?: number;
  /** FIFO cap on runs kept per thread. `Infinity` or `0` disables the cap. */
  maxRunsPerThread?: number;
  /**
   * Approximate byte ceiling on RETAINED thread/run history. Enforced at run
   * completion (in `appendRun`), where LRU non-running threads are evicted to
   * keep the total under this limit.
   *
   * Limitation: this bounds only history that has already been committed. A
   * single in-flight run's buffered events (`currentRunEvents` and the two
   * `ReplaySubject<BaseEvent>(Infinity)` buffers in `run()`) are NOT counted
   * until that run completes, so `maxBytes` does not bound a single runaway
   * run mid-stream.
   *
   * Limitation: byte eviction drops only other LRU non-running threads and
   * never self-evicts the active/just-appended thread, so a single dominant
   * thread's own retained history is not byte-trimmed (bounded only by
   * `maxRunsPerThread`). `maxBytes` is thus a cross-thread ceiling enforced by
   * evicting OTHER threads, not a per-thread cap.
   */
  maxBytes?: number;
}
/**
 * Constructor options for {@link InMemoryAgentRunner}.
 *
 * Extends {@link InMemoryLimits} so bounds can be passed inline alongside the
 * per-runner behavior flags. Be aware of the scope difference: the limits
 * reconfigure the process-global store shared by every runner, whereas
 * `onConcurrentRun` applies only to the runner instance it is passed to.
 */
interface InMemoryAgentRunnerOptions extends InMemoryLimits {
  /**
   * How to handle a `run()` for a thread that already has an in-flight run.
   * `"throw"` (default) rejects with "Thread already running". `"supersede"`
   * aborts the prior run and starts the new one.
   */
  onConcurrentRun?: "throw" | "supersede";
}
declare const ɵINMEMORY_DEFAULTS: Required<InMemoryLimits>;
/**
 * Normalize a fully-resolved limits bag so every field is well-formed before it
 * can reach an enforcement loop. Each field is validated independently against
 * {@link ɵisValidLimit}; an invalid value is CLAMPED to its
 * {@link ɵINMEMORY_DEFAULTS} floor and a single `console.warn` naming the field
 * and the received value is emitted.
 *
 * Clamp-and-warn (rather than throw) is deliberate and matches this file's
 * established posture toward bad input: `ɵestimateBytes` swallows serialization
 * failures and returns 0, the limits-clobber path warns rather than throwing,
 * and both the eviction and clobber logs are wrapped so "logging must never
 * break construction/a run". Constructing a bounded in-memory runner is a
 * best-effort, non-durable convenience; a typo'd bound must degrade to a safe
 * default, never abort construction or (worse) surface later as an unhandled
 * rejection from the fire-and-forget finalize path.
 */
declare function ɵnormalizeLimits(limits: Required<InMemoryLimits>): Required<InMemoryLimits>;
/**
 * Best-effort approximate byte size of a value, via serialized length.
 * Never throws — returns 0 when the value cannot be serialized. This is an
 * approximation (UTF-16 length, not exact heap bytes), used only for relative
 * accounting against `maxBytes`.
 */
declare function ɵestimateBytes(value: unknown): number;
/**
 * Per-run finalize intent, captured once when a run starts and mutated (only)
 * by whoever aborts THAT run — `stop()` or a superseding `run()`. The run's own
 * teardown reads this captured holder instead of the shared, mutable
 * `store.stopRequested`, so a later run that resets store state can never cause
 * an intentionally-stopped run to be finalized as an error (or vice versa).
 */
interface RunFinalizeControl {
  /** True once THIS run has been asked to stop (clean stop, not an error). */
  stopRequested: boolean;
}
interface HistoricRun {
  threadId: string;
  runId: string;
  /** ID of the agent that executed this run. */
  agentId: string;
  parentRunId: string | null;
  events: BaseEvent[];
  /**
   * Snapshot of all messages (input + generated) at the end of this run, as
   * passed in by the caller. NOTE: `BoundedThreadStore.appendRun` moves this
   * snapshot to the THREAD level (`InMemoryEventStore.messagesSnapshot`) and
   * clears this field to `[]`, so a stored HistoricRun never carries messages.
   * The thread-messages fallback reads the thread-level snapshot, not this.
   */
  messages: Message[];
  createdAt: number;
  /** Approximate retained byte size of `events`; set by BoundedThreadStore at append. */
  approxEventBytes?: number;
  /**
   * Legacy field retained for shape compatibility. `appendRun` always zeroes it
   * because message bytes are accounted at the thread level, not per run.
   */
  approxMessageBytes?: number;
}
/**
 * Lightweight thread summary returned by {@link InMemoryAgentRunner.listThreads}.
 * Shape matches the Intelligence platform's ThreadRecord so the same HTTP
 * response envelope can be used for both backends.
 */
interface InMemoryThread {
  id: string;
  name: string | null;
  agentId: string;
  organizationId: "";
  createdById: "";
  archived: false;
  createdAt: string;
  updatedAt: string;
}
declare class InMemoryEventStore {
  threadId: string;
  constructor(threadId: string);
  /** The subject that current consumers subscribe to. */
  subject: ReplaySubject<BaseEvent> | null;
  /** True while a run is actively producing events. */
  isRunning: boolean;
  /** Current run ID */
  currentRunId: string | null;
  /** Historic completed runs */
  historicRuns: HistoricRun[];
  /** Currently running agent instance (if any). */
  agent: AbstractAgent | null;
  /** Subject returned from run() while the run is active. */
  runSubject: ReplaySubject<BaseEvent> | null;
  /**
   * Thread-level lifecycle flag: true once a stop/supersede has been requested
   * for the currently-owning run but that run has not yet finalized. Drives
   * eviction protection, the connect() bridge, and stop() de-dup. This is NOT
   * the finalize intent read by a run's teardown — that lives per-run on
   * {@link activeFinalize}, so a superseding run resetting this field cannot
   * mislabel the run it replaced. A new run resets this to false when it takes
   * ownership.
   */
  stopRequested: boolean;
  /**
   * Finalize control of the currently-owning run. `stop()` and a superseding
   * `run()` flip the owning run's flag through this reference; each run also
   * captures the SAME object in its closure, so its teardown finalizes against
   * its own intent regardless of what a later run does to the store.
   */
  activeFinalize: RunFinalizeControl | null;
  /** Reference to the events emitted in the current run. */
  currentEvents: BaseEvent[] | null;
  /**
   * The thread's single latest NON-EMPTY message snapshot, held at the THREAD
   * level (independent of `historicRuns` lifecycle). Decoupling the snapshot
   * from per-run storage means run-cap FIFO eviction and interleaved
   * empty-snapshot runs can never drop or pin the thread's message history.
   */
  messagesSnapshot: Message[];
  /** Approximate retained byte size of `messagesSnapshot`. */
  approxMessagesSnapshotBytes: number;
  /**
   * The thread's true creation timestamp (epoch ms), captured from the FIRST
   * run ever appended and held at the THREAD level (independent of
   * `historicRuns` lifecycle). Decoupling it from per-run storage means run-cap
   * FIFO eviction — which shifts the oldest entries off `historicRuns` — can
   * never move the reported creation time forward. `null` until the first run
   * lands. Mirrors the `messagesSnapshot` thread-level decoupling.
   */
  createdAt: number | null;
}
declare class ɵBoundedThreadStore {
  private readonly map;
  private totalBytes;
  private warned;
  /** True once limits have been EXPLICITLY set (via setLimits), not just the constructor default. */
  private limitsExplicitlySet;
  /** Warn-once latch for the clobber warning, kept distinct from the eviction `warned` latch. */
  private clobberWarned;
  private limits;
  constructor(limits: Required<InMemoryLimits>);
  get byteTotal(): number;
  /**
   * The store's CURRENT effective bounds. Exposed (with the `ɵ` internal-API
   * prefix) so a partial `setLimits` can coalesce unspecified fields against the
   * live config rather than the hardcoded {@link ɵINMEMORY_DEFAULTS} — a partial
   * update must be a partial update, never a silent reset of the fields the
   * caller did not mention. Returns a copy so callers cannot mutate the store's
   * bounds through it.
   */
  get ɵlimits(): Required<InMemoryLimits>;
  /**
   * Reconfigure the process-global store's bounds. Called by the
   * {@link InMemoryAgentRunner} constructor when limits are passed. Because the
   * store is a per-process singleton, this replaces the bounds for ALL in-memory
   * threads. Emits {@link LIMITS_CLOBBER_GUIDANCE} at most ONCE per store when a
   * SECOND (or later) explicit set arrives whose resolved values differ from the
   * prior explicit set — i.e. a genuine clobber of an already-customized config.
   * The first explicit customization (defaults → custom) is the intended
   * override and never warns; identical re-sets never warn.
   */
  setLimits(limits: Required<InMemoryLimits>): void;
  get size(): number;
  /** Re-insert at the tail so Map iteration order stays LRU-first. */
  private touchOrder;
  getOrCreate(threadId: string): InMemoryEventStore;
  get(threadId: string, opts: {
    touch: boolean;
  }): InMemoryEventStore | undefined;
  peek(threadId: string): InMemoryEventStore | undefined;
  /**
   * Evict the least-recently-used thread that is neither running NOR
   * mid-finalization. Returns false if none evictable. The `protect` thread
   * (typically the one just created) is never evicted, so a fresh thread is not
   * immediately dropped when it is the only non-running candidate.
   *
   * A thread is skipped while `isRunning` OR `stopRequested` is set.
   * `stop()` flips `isRunning` to false the moment it aborts the agent, but the
   * run keeps finalizing asynchronously (the abort trips the `catch` in
   * `runAgent`, which later calls `appendRun`). During that window
   * `stopRequested` stays true; evicting the thread then would make the pending
   * `appendRun` hit `if (!store) return` and silently drop the aborted run's
   * history. Guarding on `stopRequested` keeps the thread alive until
   * finalization completes.
   */
  private evictOneLru;
  appendRun(threadId: string, run: HistoricRun): void;
  private enforceRunCap;
  /**
   * Trim the store back under the byte ceiling by evicting LRU non-running
   * threads. `protect` (the just-appended thread) is never self-evicted, so a
   * fresh run pushes OTHER threads out rather than dropping itself.
   */
  private evictByBytesIfNeeded;
  private removeThread;
  private evictThreadsIfNeeded;
  private noteEviction;
  listThreads(): InMemoryThread[];
  clear(): void;
}
/**
 * Process-wide singleton backing every {@link InMemoryAgentRunner}. Exported
 * (with the `ɵ` internal-API prefix) so tests can inspect the exact store the
 * runner writes to; not part of the public API.
 */
declare const ɵGLOBAL_STORE: ɵBoundedThreadStore;
declare class InMemoryAgentRunner extends AgentRunner {
  readonly ɵsupportsLocalThreadEndpoints = true;
  /**
   * How to handle a `run()` for a thread that already has an in-flight run.
   * `"throw"` (default) preserves the historic behavior. `"supersede"` aborts
   * the prior run (mirroring `stop()`) and starts the new one — opted into by
   * the hosted-bot listener so a fast follow-up turn on the same thread cleanly
   * replaces a still-running (or wedged) prior turn instead of erroring with
   * "Thread already running".
   */
  private readonly onConcurrentRun;
  /**
   * @param options Per-runner behavior (`onConcurrentRun`) plus optional bounds
   * for the in-memory store ({@link InMemoryLimits}).
   *
   * Note the differing scopes: `onConcurrentRun` is per-runner instance, while
   * the limits reconfigure the PROCESS-GLOBAL store shared by every
   * `InMemoryAgentRunner`. Omit the limits for safe defaults
   * ({@link ɵINMEMORY_DEFAULTS}); passing none leaves the store untouched. When
   * multiple runners are constructed with differing limits, the last-constructed
   * wins — in practice the OSS/SSE default construction passes nothing. If a
   * second (or later) runner is constructed with limits that DIFFER from an
   * already-customized store, a one-time `console.warn` is emitted to signal that
   * the shared store's bounds are being clobbered for ALL in-memory threads.
   */
  constructor(options?: InMemoryAgentRunnerOptions);
  run(request: AgentRunnerRunRequest): Observable<BaseEvent>;
  connect(request: AgentRunnerConnectRequest): Observable<BaseEvent>;
  isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean>;
  stop(request: AgentRunnerStopRequest): Promise<boolean | undefined>;
  /**
   * Returns a summary of every thread that has been run through this runner.
   *
   * This powers the local-dev fallback for `GET /threads` when the Intelligence
   * platform is not configured. Each entry mirrors the shape of a platform
   * `ThreadRecord` so the HTTP handler can use the same response envelope.
   */
  listThreads(): InMemoryThread[];
  /**
   * Returns all messages for a thread, using the snapshot captured at the end
   * of the most recent run.
   *
   * This powers the local-dev fallback for `GET /threads/:threadId/messages`
   * when the Intelligence platform is not configured. The returned `Message[]`
   * objects come directly from the ag-ui agent, so their shape is compatible
   * with the Intelligence platform's `ThreadMessage` type.
   */
  getThreadMessages(threadId: string): Message[];
  /**
   * Returns all AG-UI events for a thread, compacted across historic runs.
   *
   * Powers the local-dev fallback for `GET /threads/:threadId/events` when the
   * Intelligence platform is not configured. The compaction logic matches
   * the connection-replay path in {@link connect}, so the stream a
   * late-joining inspector sees matches what this method returns.
   */
  getThreadEvents(threadId: string): BaseEvent[];
  /**
   * Returns the agent state snapshot for a thread.
   *
   * Derived from the last `STATE_SNAPSHOT` in the compacted event stream. The
   * AG-UI `compactEvents` helper consolidates STATE_DELTA events and produces
   * a single trailing STATE_SNAPSHOT when state changes exist, so this is a
   * faithful view of state at the end of the most recent run.
   *
   * Returns `null` when the thread has never emitted a STATE_SNAPSHOT.
   */
  getThreadState(threadId: string): Record<string, unknown> | null;
  /**
   * Clears all in-memory thread history.
   *
   * Powers the local-dev fallback for `POST /threads/clear`, letting consumers
   * (e.g. the demo's Clear button) reset to an empty thread list without
   * restarting the runtime. Intentionally not exposed on the Intelligence
   * platform path: there, thread history lives in a real database and must
   * not be wiped this way.
   */
  clearThreads(): void;
}
//#endregion
export { InMemoryAgentRunner, InMemoryAgentRunnerOptions, InMemoryLimits, InMemoryThread, ɵBoundedThreadStore, ɵGLOBAL_STORE, ɵINMEMORY_DEFAULTS, ɵestimateBytes, ɵnormalizeLimits };
//# sourceMappingURL=in-memory.d.mts.map