import { MemoryModule } from '../modules/memory/memory.module.js'; import { Document } from '../types/document.js'; import { UserWorkflow } from '../types/memory.js'; import { ScheduleTrigger } from '../types/schedule.js'; import { JobRunnerService } from './job-runner.service.js'; import { UserWorkflowService } from './user-workflow.service.js'; import { WorkflowExecutionService } from './workflow-execution.service.js'; import '../modules/memory/base.memory.js'; import '../types/list.js'; import './workflow-variable-resolver.service.js'; import '../modules/a2a/a2a.module.js'; import '@a2a-js/sdk'; import '../types/connector.js'; import '../types/stream.js'; import '../modules/models/model.module.js'; import '../modules/models/base.model.js'; import './tool-calling.service.js'; import '../modules/mcp/mcp.module.js'; import '../types/mcp.js'; import '@modelcontextprotocol/sdk/client/sse.js'; import '@modelcontextprotocol/sdk/client/stdio.js'; import '@modelcontextprotocol/sdk/client/streamableHttp.js'; /** * Cron-based scheduler for user workflows plus one-shot document auto * refreshes. Triggering (node-cron / minute tick) is separated from * execution: every run goes through the JobRunner, which owns concurrency, * retries and the rate-limit cooldown. This service owns run history and * schedule state (nextRunAt, autoRefresh bookkeeping). */ declare class SchedulerService { private userWorkflowService; private workflowExecutionService; private jobRunner; private memoryModule; private tasks; private pendingAutoRefresh; private tickTimer?; private static readonly TICK_INTERVAL_MS; private static readonly MAX_CONSECUTIVE_FAILURES; /** Consecutive failed cron runs per workflowId; reset on success. */ private consecutiveFailures; constructor(userWorkflowService: UserWorkflowService, workflowExecutionService: WorkflowExecutionService, jobRunner: JobRunnerService, memoryModule: MemoryModule); start(): Promise; stop(): Promise; scheduleWorkflow(workflow: UserWorkflow): Promise; unscheduleWorkflow(workflowId: string): Promise; rescheduleWorkflow(workflow: UserWorkflow): Promise; /** * Executes one scheduled workflow run through the JobRunner and records * it in schedule_runs. Public for tests and manual triggering. * * Never rejects: execution errors are absorbed by the JobRunner, and * bookkeeping (memory) errors are caught and logged here so that * fire-and-forget callers (boot catch-up) cannot crash the process * with an unhandled rejection. */ runWorkflowJob(workflowId: string, trigger: ScheduleTrigger, scheduledFor: number): Promise; private runWorkflowJobWithRunId; /** Reflects a created/updated document in the pending auto-refresh list. */ notifyDocumentAutoRefresh(document: Document): void; /** Drops a (deleted) document from the pending list. */ removeDocumentAutoRefresh(documentId: string): void; /** Exposed for tests: starts the minute tick without full start(). */ startTickForTest(): void; private startTick; private loadAutoRefreshDocuments; private tick; /** * Expands a document auto refresh into per-slot jobs (the JobRunner * throttles them), accumulates doneSlotIds, and completes the refresh * only when every target slot succeeded. Failed slots stay pending so * the next boot catch-up retries ONLY them. * * Never rejects: slot execution failures are absorbed by the JobRunner * (submit() never rejects), and bookkeeping (memory) errors are caught * and logged here so that fire-and-forget callers (tick) cannot crash * the process with an unhandled rejection. */ runAutoRefreshJob(documentId: string, trigger: ScheduleTrigger, scheduledFor: number): Promise; private runAutoRefreshJobWithRunId; /** * Candidate slot ids for a document's auto-refresh: an explicit allowlist, * or (default) every slot with a binding. Shared by * {@link deriveAutoRefreshTargeting} and {@link reconcileManualSlotFill} so * the two stay in sync. */ private getAutoRefreshTargetSlotIds; /** * Expands {@link getAutoRefreshTargetSlotIds} into the derivation recorded * on the run: what the document offered, what this run will actually * submit, and every slot dropped along the way with its reason. Three * different filters can shrink the target set (no binding, an explicit * allowlist, the done ledger) and none of them left a trace before — a * 3-of-6 run and a genuine 3-slot run looked identical in storage. */ private deriveAutoRefreshTargeting; /** * Reconciles a successful MANUAL slot fill into the auto-refresh ledger. * If the slot is a target of a pending (active, incomplete) autoRefresh, * mark it done; if that completes every target, stamp completedAt and drop * the pending entry. Idempotent; never throws (bookkeeping must not fail * the fill request). */ reconcileManualSlotFill(documentId: string, slotId: string): Promise; } export { SchedulerService };