TaskSultan Docs tasksultan.com

Building automations

The framework loop and capabilities

How the runner drives an automation through INIT, GET TRANSACTION and PROCESS TRANSACTION and what a declared capability means.

The framework is a loop. You write the few functions that matter and the runner supplies everything around them: the browser, the logs, the retries, the screenshots and the trace. This page describes the shape of the loop and the context handed to each call.

#The transaction loop

The runner executes a fixed sequence. It writes the current phase into state.json before each step, so the Studio can show where a run is without guesswork.

  1. INIT runs once. Login and environment preparation belong here.
  2. GET TRANSACTION asks the automation for the next unit of work.
  3. PROCESS TRANSACTION runs that unit.
  4. On success the loop returns to step 2. On a business failure or an exhausted system failure it records the outcome and returns to step 2. On null from GET TRANSACTION it leaves the loop.
  5. END PROCESS runs once and the summary is written, success or failure.

Two safeguards sit in the loop. INIT and GET TRANSACTION are themselves wrapped in the retry policy, so a flaky login or a poll that times out does not end the run on the first try. And a transaction that already reached a terminal outcome and comes back from the queue is skipped, not reprocessed. More than ten of those in a row abort the run with QUEUE_LOOP rather than spin.

#The context the loop hands you

Every lifecycle function receives a RunContext. It is the whole surface the automation gets.

interface RunContext {
  automationId: string;
  runId: string;
  steps: StepRecorder;              // ctx.steps.record(name, work)
  baseURL: string;
  log: Logger;
  browser: Browser;
  context: BrowserContext;
  page: Page;
  credentials: CredentialProvider;  // ctx.credentials.get(name)
  excel: ExcelFacade;
  files: FileFacade;
  email: EmailFacade;
  api: ApiFacade;
  db: DbFacade;
  pdf: PdfFacade;
  desktop: DesktopFacade;
  settings: RobotSettings;
  screenshotsDir: string;
  screenshot: (name: string) => Promise<string>;
  requestStop: () => void;
  checkAborted: () => void;
  note: (msg: string, data?: Record<string, unknown>) => void;
}

ctx.page is the single page the run drives. ctx.log writes into the run's own log files. ctx.credentials.get resolves a secret by name, never a value in the source. ctx.steps is the recorder that gives a failure something useful to say: await ctx.steps.record('submit the customer form', async () => { ... }) names a bounded span of work, and a failed step appears beside the transaction it belonged to. ctx.checkAborted lets an operator stop a run at a safe point rather than in the middle of a click.

#Capabilities an automation declares

capabilities is a closed union of eight tokens: web, excel, files, api, database, email, pdf and desktop. Declaring one is a promise that the automation needs that engine.

The declaration does two things. It travels into the packaged manifest, where the Orchestrator will not place the job on a robot that cannot present the engine. It also gates the facade at run time: a facade whose capability is not declared throws a SystemException carrying a stable code such as FILES_NOT_DECLARED. A facade whose capability is declared but was not supplied throws the matching FILES_UNAVAILABLE. Either way the refusal names itself, so a missing engine cannot look like a green run.

web is the exception. The runner launches the browser itself, so there is no WEB_NOT_DECLARED.

#Things that catch people out

  • getTransaction must not return a transaction that already has a terminal outcome. The loop guards against it, but a queue that keeps handing back the same item ends the run with QUEUE_LOOP.
  • A run whose transactions all fail is not a failed run. It finishes completed-with-errors, which still exits 0. The failed status is reserved for a fatal error that stopped the loop.
  • A stop request is a SystemException with retryable: false, so the retry policy never retries an operator's decision.