import type { RuntimeContext } from "./state/context.js"; import type { GlobalStore } from "./state/globalStore.js"; import type { StateStack } from "./state/stateStack.js"; import type { ThreadStore } from "./state/threadStore.js"; import type { Runner } from "./runner.js"; import type { HandlerEntry, HandlerFn } from "./types.js"; import type { CallFrame } from "./callDepth.js"; import type { DecisionScope } from "./decision/collector.js"; import type { StatelogClient } from "../statelogClient.js"; export type CallsiteLocation = { moduleId: string; scopeName: string; stepPath: string; }; export type Run = { ctx: RuntimeContext; stack: StateStack; threads: ThreadStore; /** * The globals this run reads and writes. Outside a fork branch it is * the same object as `ctx.globals`. It is a separate field so a branch * can hold a clone: `runBatch` clones the parent's store for each * branch, and generated code reads `__run.globals`, so a branch sees * its own copy without disturbing the parent's. */ globals: GlobalStore; /** * The branch stack of the tool invocation this code runs in, set by the * tool loop for the body's duration. `endTurn()` and `handBack()` write * their marks here, and the loop drains this stack when the tool * returns. Every frame builder copies it from the outer frame, so code * in a `parallel`, `fork`, or `async` branch of the body still marks * the tool and not the branch. Absent outside a tool invocation. */ toolInvocationStack?: StateStack; /** * Per-call-site source location for the currently-executing step. * Seeded by `Runner.runInScope` for every step body. Stdlib helpers * that need to attribute a checkpoint to its originating step * (`checkpoint()`) read this slot instead of receiving the location * as a trailing positional arg from generated code. * * Optional because not every run has one: the top-level * `runNode` frame and `runInBootstrapFrame` deliberately omit it * (any checkpoint created in bootstrap scope gets the empty * `""::""::""` fallback, as it always has). */ callsite?: CallsiteLocation; /** * The `Runner` driving the currently-executing step, if any. * Seeded by `Runner.runInScope` so TS helpers like `agency.interrupt` * can call `runner.halt(...)` without having to receive the runner * as an argument. Absent in bootstrap frames and in the outer * `withResumableScope` body frame (only inside `s.step(...)` does * a Runner come into scope). */ runner?: Runner; /** * The decision-call collector of the enclosing fork or parallel block * and the key of the arm this frame runs in. Absent outside a block. * See lib/runtime/decision/collector.ts. */ decisions?: DecisionScope; /** * The call chain that led here, innermost first. `withCallDepth` adds a * link for each call and stops runaway recursion. `null` at the root. */ callDepth: CallFrame | null; /** * How many handler chains are running one inside another on this path. * `runHandlerChain` adds one and refuses to go past its limit. */ handlerChainDepth: number; /** * The handler entries whose functions are running on this path, outermost * first. The handler chain skips these, so a handler function never hears * an interrupt raised inside itself. */ executingHandlers: HandlerEntry[]; /** * The callbacks that are running on this path. A callback already in the * list is not fired again, and the runner puts off an external pause while * the list is not empty. */ activeCallbacks: object[]; /** * The logger for this run's branch: the logging client bound to the * branch's tag store and span stack. Every run in a branch shares one. */ log: StatelogClient; /** * What this run is waiting for, for the wrong-run check. Unlike every * other field it is written to. A child run always gets its own. */ state: RunState; }; /** * How many things a run has started and is waiting for, and the name of * the latest. A run is usable when the count is 0. */ export type RunState = { waiting: number; waitingFor: string; /** True once TypeScript code has raised an interrupt on this run. A run * takes one such raise. See lib/runtime/agencyInterrupt.ts. */ raisedFromTypeScript: boolean; }; /** The state of a run that is waiting for nothing. */ export declare function freshState(): RunState; /** * Thrown when code starts work with a run that is waiting for something it * started. Only the innermost run can be used: the code inside a step, a * call, or a fork branch must use the run it was given. */ export declare class RunInUseError extends Error { constructor(what: string, run: Run); } /** * Check that `run` is not waiting for something it started. The operations * that start work for Agency code or a helper call this: a call, a Runner * step, an interrupt, a callback. `what` says what was attempted. * * Every run has the same type, so the type checker cannot tell the right * run from the wrong one. This catches the mistake where it happens, and it * does not depend on any hidden state. */ export declare function assertUsable(run: Run, what: string): Run; /** * A copy of `run` with `overrides` and its own state, for work the caller * does not wait for. The caller keeps running, so nothing is counted * against `run`. */ export declare function detachedRun(run: Run, overrides: Partial): Run; /** * Run `fn` under a child of `parent`, and count `parent` as waiting until * `fn` has finished. `what` names the wait, for the error. * * The child is `parent` with `overrides` and its own state. This is how * every step, call, handler, and callback gets its run. */ export declare function withChildRun(parent: Run, overrides: Partial, what: string, fn: (run: Run) => T): T; /** * The logger for a run made at the root of a branch that already exists: * the context's client bound to `globals` and to the span stack that is * current now. A test's stub client has no `logFor`, and is used as it is. */ export declare function logOf(ctx: RuntimeContext, globals: GlobalStore): StatelogClient; /** * The four values that follow a path of calls. They are required on every * frame, so a frame built without them does not compile. A frame that * dropped them would turn off the recursion limits and the rule that a * handler does not hear its own raises, with no error anywhere. */ export type Lineage = Pick; /** * The lineage a new frame starts with: the outer frame's when there is one, * and empty values at the root of a run. */ export declare function lineageOf(outer: Run | undefined): Lineage; /** * Call a function that does not take a run. The function can read the run * with `currentRun()` until its first `await`. * * The previous value is restored in a `finally`. If a throw skipped the * restore, the next helper to run would read another request's run: its * globals, its thread, and its handlers. */ export declare function callPlain(run: Run, fn: (...args: A) => T, args: A, thisArg?: unknown): T; /** * Run `fn` under `run`: hand it the run, and make the run readable with * `currentRun()` for the synchronous part of the call. Every place that * makes a child run goes through here. */ export declare function withRun(run: Run, fn: (run: Run) => T): T; /** * The run this function was called under. Call it on the function's first * line, before any `await`, and keep the result: * * export async function _fetch(url: string) { * const run = currentRun(); * ... * } * * It throws after the first `await`. A helper that needs the run later must * have taken it at the top. */ export declare function currentRun(): Run; /** * The run of the plain call in progress, or `undefined` when there is none. * * Like `currentRun()` it is only right until a function's first `await`. * Unlike it, this does not throw afterwards. It returns `undefined`, which * looks the same as "not inside a run". So use it only where a missing run * has a harmless answer, such as a default or a skipped log line, and call * it on the function's first line. Anything that tracks a limit, a guard, * or a handler must use `currentRun()` or take a run. * * A root run reads it too. A run started from inside another run (a nested * `runNode`, or a test context inside a test context) takes its lineage * from the outer one, so the recursion limits keep counting across the * nesting. That works when the inner run is started before an `await`. */ export declare function currentRunOrNone(): Run | undefined; /** * Run `fn` under a child of `run` whose `callsite` is `loc`. For TS helpers * that want to attach a per-internal-substep checkpoint location to nested * `checkpoint()` calls. */ export declare function withCallsite(run: Run, loc: CallsiteLocation, fn: (run: Run) => T): T; /** * Run `fn` with `handler` pushed onto `ctx.handlers`; pop in finally. * Two call sites consume this: `AgencyFunction.invoke()`'s preapprove * branch and (in a future PR) `agency.withHandler`. Co-locating the * combinator here means neither call site repeats the push/try/finally * dance and there is no circular import between agencyFunction.ts and * the agency namespace module. */ export declare function withPushedHandler(ctx: RuntimeContext, handler: HandlerFn, fn: () => Promise, liveGuardIds: string[]): Promise; /** * The old name for `currentRun()`. * * @deprecated Use `currentRun()` inside the runtime, and `agency.current()` * in your own helpers. This name stays exported for one release. */ export declare function getRuntimeContext(): Run; /** * For tests that construct a RuntimeContext by hand. It makes a root run * from the three values and calls `fn` with it. The run is also readable * with `currentRun()` until `fn`'s first `await`. */ export declare function runInTestContext(ctx: RuntimeContext, stack: StateStack, threads: ThreadStore, fn: (run: Run) => T): T; /** * Run `fn` under a run suitable for code that runs *outside* any * agent node body — module-level global-init, top-level callback * registration, and the resume/rewind prelude. The `threads` slot is a * `BootstrapThreadStore` sentinel: any attempt to use a message-thread * builtin from inside `fn` throws with an actionable error rather than * silently writing into a placeholder that the runtime is about to * discard. * * The `stack` slot is the caller's current `ctx.stateStack`. At the * `runNode` / `respondToInterrupts` / `rewindFrom` `*registerTopLevel * Callbacks` and `onAgentStart` call sites that's the bare pre-restore * stack (no node frames pushed) — which is the contract * `__initializeGlobals` always expected. At the resume / rewind * `graph.run` call sites it's the restored stack carrying the * checkpoint frames; that's also fine because `Runner.runInScope` on * the first step makes a child run with the per-node ThreadStore. * * Declared `async` so synchronous throws inside `fn` (including the * very common case of the `BootstrapThreadStore` sentinel throwing) * surface as rejected promises for `.catch(...)` callers, not as * uncaught sync exceptions. */ export declare function runInBootstrapFrame(ctx: RuntimeContext, fn: (run: Run) => T | Promise): Promise;