diff --git a/src/domain/Service.ts b/src/domain/Service.ts index 73e6dc8..faaaf12 100644 --- a/src/domain/Service.ts +++ b/src/domain/Service.ts @@ -1,10 +1,12 @@ import { Logger } from 'winston' +import { EventEmitter } from 'node:events' -export default abstract class Service { +export default abstract class Service extends EventEmitter { protected name: string protected logger: Logger protected constructor(name: string, logger: Logger) { + super() this.name = name this.logger = logger.child({ service: name }) } diff --git a/src/index.ts b/src/index.ts index 28e30fb..50a0863 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,4 @@ export { default as Agent } from './Agent' + +export { default as Runner } from './services/runner' +export { default as ActionReport } from './services/runner/domain/ActionReport' diff --git a/src/services/runner/Runner.ts b/src/services/runner/Runner.ts index 5c44632..dff73bb 100644 --- a/src/services/runner/Runner.ts +++ b/src/services/runner/Runner.ts @@ -13,7 +13,13 @@ import { ErrorResult } from './domain/ErrorResult' import ParsedResult from '../mind/domain/ParsedResult' import CycleResult from './domain/CycleResult' import { Logger } from 'winston' +import ActionReport from './domain/ActionReport' +import RunnerStatus from './domain/RunnerStatus' +/** + * The Runner class provides a high-level interface for interacting with runners. + * @public + */ export default class Runner extends Service { constructor( public readonly page: PageWrapper, @@ -32,9 +38,20 @@ export default class Runner extends Service { } private readonly actions: Action[] = [] + private _status: RunnerStatus = RunnerStatus.Starting + public get status(): RunnerStatus { + return this._status + } + public set status(value: RunnerStatus) { + this._status = value + this.emit('status', value) + } + public async run(): Promise { this.logger.debug(`Starting task: ${this.task}`) + this.status = RunnerStatus.Running + while ( this.cycles.total < config.cycles.max && this.cycles.failed < config.cycles.failed @@ -50,6 +67,11 @@ export default class Runner extends Service { this.logger.debug(`Cycle ${this.cycles.total} completed`) if (action.type === ActionType.Done) { + this.status = + action.arguments.status === 'success' + ? RunnerStatus.Done + : RunnerStatus.Failed + return { success: action.arguments.status === 'success', message: action.arguments.reason as string, @@ -61,6 +83,8 @@ export default class Runner extends Service { if (config.delay) await this.sleep(config.delay) } + this.status = RunnerStatus.Failed + if (this.cycles.failed >= config.cycles.failed) { return { success: false, @@ -137,11 +161,15 @@ export default class Runner extends Service { result.action.status = status this.actions.push(result.action) - this.logger.info('Performed action', { + const report: ActionReport = { action: result.action, reasoning: result.reasoning, duration: Date.now() - startedAt, - }) + } + + this.logger.info('Performed action', report) + + this.emit('action', report) return { success: true, diff --git a/src/services/runner/domain/ActionReport.ts b/src/services/runner/domain/ActionReport.ts new file mode 100644 index 0000000..c1d7ab5 --- /dev/null +++ b/src/services/runner/domain/ActionReport.ts @@ -0,0 +1,12 @@ +import Action from './Action' + +/** + * Represents a report of an action execution. + * @public + */ +export type ActionReport = { + action: Action + reasoning?: string + duration: number +} +export default ActionReport diff --git a/src/services/runner/domain/RunnerStatus.ts b/src/services/runner/domain/RunnerStatus.ts new file mode 100644 index 0000000..a32c052 --- /dev/null +++ b/src/services/runner/domain/RunnerStatus.ts @@ -0,0 +1,7 @@ +export enum RunnerStatus { + Starting = 'Starting', + Running = 'Running', + Done = 'Done', + Failed = 'Failed', +} +export default RunnerStatus