framework
Version:
The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.
115 lines • 5.83 kB
TypeScript
import type { Driver, DriverEvent } from './driver/index.js';
import { type FrameworkEvent } from './events.js';
/** Inputs to {@link emitSessionStart}. */
export interface SessionStartOptions {
emit: (event: FrameworkEvent) => void;
driver: Driver;
/** The workspace the run works in. */
cwd: string;
/** The session link, literal or templated with `{sessionId}`. */
sessionLink?: string | undefined;
/** The model id the driver was started with (#1438), recorded on the event per leg. */
model?: string | undefined;
}
/**
* Emit the run's opening `session` event. A literal link is shown right away; a
* templated one (`.../{sessionId}`) can only resolve once the driver reports its
* session id, so it waits for the `session-update` from {@link createDriverEventHandler}.
*/
export declare function emitSessionStart(opts: SessionStartOptions): void;
/** Inputs to {@link createDriverEventHandler}. */
export interface DriverEventHandlerOptions {
emit: (event: FrameworkEvent) => void;
/** The session link template, when the caller configured one. */
sessionLink?: string | undefined;
/** The run's spend cap (#322). Omitted = uncapped. */
budgetUsd?: number | undefined;
/**
* Answers "has the account reached its quota boundary?" between turns (#879).
* Returns the label of the window that reached it, or null while there is room.
*/
consumptionGate?: (() => string | null) | undefined;
/** Tripped when the budget cap is crossed. */
budgetController: AbortController;
/** Tripped when the consumption gate reports a window is spent. */
consumptionController: AbortController;
}
/** What {@link createDriverEventHandler} hands back. */
export interface DriverEventHandler {
/** Wire this as the driver session's `onEvent`. */
onDriverEvent: (event: DriverEvent) => void;
/** The window that reached the boundary, once the consumption gate has fired. */
consumptionTrip: () => string | undefined;
}
/**
* Watch the driver's black box (#165) and turn it into the run's stream: surface the
* real session id as `session-update` once known (that is the honest handle a UI links
* to, and it changes per prompt, so re-emit), fold each turn's usage into the run total,
* and trip the two self-stops.
*
* Both stops fire *after* the turn that crossed them: its cost is already spent, so the
* point is to stop the next one. Each is signalled once, and the run's `AbortSignal.any`
* composition carries it downstream. An agent that reports no price leaves `costUsd`
* undefined and so can never trip the budget cap (#540). A consumption gate that throws
* is treated as "carry on": an unreadable quota must not stop the work (#519), and the
* gate is answered from a cached reading because a live one spawns the agent CLI (~5s).
*/
export declare function createDriverEventHandler(opts: DriverEventHandlerOptions): DriverEventHandler;
/** Inputs to {@link createRunControls}. */
export interface RunControlsOptions {
emit: (event: FrameworkEvent) => void;
/** The caller's abort signal (Stop button / Ctrl+C / control channel), if any. */
signal?: AbortSignal | undefined;
sessionLink?: string | undefined;
budgetUsd?: number | undefined;
consumptionGate?: (() => string | null) | undefined;
}
/** The run's abort plumbing plus its driver-event sink. */
export interface RunControls extends DriverEventHandler {
/** The composed signal every driver turn runs under. */
runSignal: AbortSignal;
/** Trips a clean stop once this run has spent its budget cap (#322). */
budgetController: AbortController;
/** Trips a clean pause once the account's quota window is spent (#529). */
consumptionController: AbortController;
/** Trips a clean stop when the user declines a plan (#358); inert on the direct path. */
declineController: AbortController;
}
/**
* Compose the run's signal and wire its driver-event handler in one place. The caller's
* signal is OR'd (via {@link AbortSignal.any}) with three self-stops — the budget cap
* (#322), a spent consumption window (#529), and a declined plan (#358) — so anything
* downstream that watches `runSignal` stops the same way regardless of which fired.
* Shared by the build (`run.ts`) and direct-prompt (`prompt-run.ts`) paths.
*/
export declare function createRunControls(opts: RunControlsOptions): RunControls;
/** Inputs to {@link endStopDetail}. */
export interface StopDetailOptions {
/** The error the run's turn loop threw. */
err: unknown;
/** The caller's own signal, to tell a caller stop from a self-stop. */
signal?: AbortSignal | undefined;
budgetController: AbortController;
consumptionController: AbortController;
declineController: AbortController;
consumptionTrip: () => string | undefined;
budgetUsd?: number | undefined;
/**
* Leave a resume note when the run paused on a consumption limit, returning where
* it will resume from. Injected (not imported) so this module stays free of the
* todo loop it would otherwise import in a cycle.
*/
leaveResumeNote: () => Promise<string | undefined>;
}
/**
* Classify why a run's turn loop threw and render the `end` event's `detail`. A caller
* interrupt, a budget cap (#322), a declined plan (#358), or a spent consumption window
* (#529) are all clean stops; anything else is a real failure. The resume note is written
* here (once `paused` is known) rather than at the trip, because it is file I/O racing the
* run unwinding. Shared so the two run paths can never disagree on what "stopped" means.
*/
export declare function endStopDetail(opts: StopDetailOptions): Promise<{
stopped: boolean;
detail: string;
}>;
//# sourceMappingURL=run-telemetry.d.ts.map