import type { Employee, ModelRegistry } from "../shared/types.js"; import type { WorkflowTodoEventFeed } from "../work-items/workflow-event-feed.js"; import { type JsonValue, type WorkflowDefinition, type WorkflowId } from "./model.js"; import { type WorkflowDeciderAuthority } from "./approval-gate.js"; import { WorkflowRepositoryError, type CreateWorkflowInput, type CursorPage, type DefinitionListQuery, type RunListQuery, type WorkflowDefinitionSummary, type WorkflowRepository, type WorkflowRunSummary } from "./repository.js"; import type { WorkflowRunDetail } from "./runtime.js"; import { type WorkflowRunnerOptions, type WorkflowTodoApprovalMirror, type WorkflowTodoDispatchOverride, type WorkflowTodoLifecycle, type WorkflowTodoSessionLink } from "./runner.js"; import type { WorkflowSessionExecutor } from "./session-executor.js"; import { type FireWorkflowEventInput } from "./trigger-service.js"; import { type WorkflowValidationIssue } from "./validation.js"; export { WorkflowRepositoryError }; export type { FireWorkflowEventInput }; export interface StartWorkflowRunInput { workflowId: string; input: Record; idempotencyKey?: string; /** Bind this manual run to an existing Todo, exactly as a `todo-status` * trigger would — its gates mirror onto that Todo. Omit for an unbound run. */ todoId?: string; /** The session asking for the run. When it turns out to be a live Workflow * attempt the run is guarded and parented like a Workflow Call; every other * session — an operator, a cron run — starts an unparented run as before. */ callerSessionId?: string; } export interface RerunWorkflowInput { workflowId: string; runId: string; definition: "original" | "current"; idempotencyKey: string; } export interface DecideWorkflowApprovalInput { workflowId: string; runId: string; nodeId: string; decision: "approve" | "reject"; decidedBy: string; decidedByAuthority?: WorkflowDeciderAuthority; reason?: string; /** Required when approving a node that offers options; must be one of them. */ choice?: string; expectedRevision: number; } export interface RetryWorkflowNodeInput { workflowId: string; runId: string; nodeId: string; idempotencyKey: string; } export interface WorkflowCallInput { workflowId: string; caller: { workflowId: string; runId: string; nodeId: string; }; input: Record; idempotencyKey: string; itemIndex?: number; todoId?: string; } export declare class WorkflowServiceError extends Error { readonly code: "forbidden" | "conflict" | "invalid-definition"; readonly issues?: readonly WorkflowValidationIssue[]; constructor(code: "forbidden" | "conflict", message: string); constructor(code: "invalid-definition", message: string, issues: readonly WorkflowValidationIssue[]); } export type WorkflowTranscript = Array<{ id: string; role: string; content: string; timestamp: number; }>; /** The Todos side of a comment-wait: the earliest live operator comment on a * Todo written strictly inside the window between the park and its deadline. */ export interface WorkflowTodoCommentFeed { firstOperatorCommentAfter(todoId: string, after: string, until: string): { id: string; body: string; createdAt: string; attachments: ReadonlyArray<{ id: string; mime: string; }>; } | undefined; } export interface WorkflowServiceOptions extends Pick { repository: WorkflowRepository; executor: WorkflowSessionExecutor; employees: () => ReadonlyMap; models: () => ModelRegistry; readTranscript?: (sessionId: string) => WorkflowTranscript; now?: () => string; onChange?: (change: { workflowId: string; runId: string; }) => void; onDefinitionChange?: (change: { workflowId: string; revision: number; }) => void; todoEventFeed?: WorkflowTodoEventFeed; /** The Todo-facing ports, each documented on the runner: the operator replies * a parked `todo-comment` Wait node resumes on, the Approval gates mirrored * onto the bound Todo, the phase sessions linked to it for spend, the run * lifecycle reflected onto it, and the next attempt's engine/model. */ todoComments?: WorkflowTodoCommentFeed; todoApprovals?: WorkflowTodoApprovalMirror; todoSessions?: WorkflowTodoSessionLink; todoLifecycle?: WorkflowTodoLifecycle; todoDispatch?: WorkflowTodoDispatchOverride; /** Live session-cost aggregate for Workflow attempt sessions. */ sessionSpend?: (sessionIds: string[]) => number; } export declare class WorkflowService { private readonly options; private readonly runner; private readonly triggers; private unsubscribe; private wakeTimer; private disposed; constructor(options: WorkflowServiceOptions); private now; private definitionChanged; private runChanged; private wakeCaller; private requiredRun; private armWakeTimer; dispose(): void; listDefinitions(query: DefinitionListQuery): CursorPage; getDefinition(id: string): WorkflowDefinition | null; getRun(workflowId: string, runId: string): WorkflowRunDetail | null; getRunSpend(workflowId: string, runId: string): number; listRuns(workflowId: string, query: RunListQuery): CursorPage; submitAttemptOutput(input: { sessionId: string; outcome?: "success" | "failure"; fields?: unknown; summary?: string; }): Promise; extendAttemptDeadline(input: { sessionId: string; reason?: string; }): Promise; createDefinition(input: CreateWorkflowInput): WorkflowDefinition; saveDefinition(definition: WorkflowDefinition, expectedRevision: number): WorkflowDefinition; duplicateDefinition(sourceId: WorkflowId, input: { id: WorkflowId; title: string; }): WorkflowDefinition; setRetired(input: { id: string; retired: boolean; expectedRevision: number; }): WorkflowDefinition; setEnabled(input: { id: string; enabled: boolean; expectedRevision: number; }): WorkflowDefinition; startManual(input: StartWorkflowRunInput): Promise; fireEvent(input: FireWorkflowEventInput): Promise; callWorkflow(input: WorkflowCallInput): Promise; getAttemptTranscript(input: { workflowId: string; runId: string; nodeId: string; attempt: number; }): WorkflowTranscript; cancelRun(input: { workflowId: string; runId: string; reason: string; }): Promise; rerun(input: RerunWorkflowInput): Promise; decideApproval(input: DecideWorkflowApprovalInput): Promise; retryNode(input: RetryWorkflowNodeInput): Promise; /** Resume every run parked on a `todo-comment` Wait whose bound Todo was * commented on by the operator between the park and the node's timeout * deadline. Runs before the due-wait sweep so a reply that landed inside that * window beats its own timeout, and is bounded by the deadline so a sweep * arriving after one cannot answer a park that had already expired. */ private resumeCommentWaits; recover(now: string): Promise<{ resumedRuns: number; resumedWaits: number; resumedComments: number; }>; } //# sourceMappingURL=service.d.ts.map