@dexwox-labs/a2a-server
Version:
TypeScript server implementation for Google's Agent-to-Agent (A2A) protocol - includes Express/WebSocket handlers, request validation and queue management
201 lines • 7.63 kB
JavaScript
;
/**
* @module TaskUpdater
* @description Manages task state transitions with validation
*
* This module provides functionality for managing task state transitions
* with validation to ensure that tasks follow the correct lifecycle.
* It enforces a state machine approach to task status changes.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskUpdater = void 0;
const a2a_core_1 = require("@dexwox-labs/a2a-core");
/**
* Error thrown when an invalid task state transition is attempted
*
* This error is thrown when a task state transition is attempted that
* is not allowed by the state machine rules.
*
* @example
* ```typescript
* // This would throw if the transition is invalid
* try {
* await taskUpdater.transitionTask('task-123', 'completed');
* } catch (error) {
* if (error instanceof InvalidTaskStateError) {
* console.error('Invalid state transition:', error.message);
* }
* }
* ```
*/
class InvalidTaskStateError extends a2a_core_1.A2AError {
/**
* Creates a new InvalidTaskStateError
*
* @param message - Error message describing the invalid transition
*/
constructor(message) {
super(message, -32002); // -32002 = Invalid state transition
}
}
/**
* Manages task state transitions with validation
*
* The TaskUpdater enforces a state machine approach to task status changes,
* ensuring that tasks can only transition between valid states. It maintains
* a history of transitions and provides methods for retrieving this history.
*
* @example
* ```typescript
* // Create a task updater with a task manager
* const taskManager = new TaskManager(taskStore);
* const taskUpdater = new TaskUpdater(taskManager);
*
* // Transition a task from 'submitted' to 'working'
* try {
* const updatedTask = await taskUpdater.transitionTask('task-123', 'working');
* console.log(`Task is now ${updatedTask.status}`);
* } catch (error) {
* console.error('Failed to transition task:', error.message);
* }
* ```
*/
class TaskUpdater {
/**
* Creates a new TaskUpdater
*
* @param taskManager - The task manager to use for retrieving and updating tasks
*/
constructor(taskManager) {
this.taskManager = taskManager;
this.transitions = this.buildStateTransitionMap();
}
/**
* Builds the state transition map for the task state machine
*
* This defines the valid transitions between task states:
* - submitted → working, failed
* - working → completed, failed, canceled
* - input_required → working, failed, canceled
* - failed → (terminal state, no transitions)
* - completed → (terminal state, no transitions)
* - canceled → (terminal state, no transitions)
*
* @returns A map of valid state transitions
* @internal
*/
buildStateTransitionMap() {
const transitions = new Map();
// Define valid state transitions
transitions.set('submitted', new Set(['working', 'failed']));
transitions.set('working', new Set(['completed', 'failed', 'canceled']));
transitions.set('input_required', new Set(['working', 'failed', 'canceled']));
transitions.set('failed', new Set([]));
transitions.set('completed', new Set([]));
transitions.set('canceled', new Set([]));
return transitions;
}
/**
* Transitions a task to a new state
*
* This method validates the state transition against the state machine rules,
* creates a transition record, and updates the task with the new state and
* transition history.
*
* @param taskId - ID of the task to transition
* @param newState - New state to transition the task to
* @returns Promise resolving to the updated task
* @throws InvalidTaskStateError if the transition is not allowed
*
* @example
* ```typescript
* // Transition a task from 'submitted' to 'working'
* try {
* const task = await taskUpdater.transitionTask('task-123', 'working');
* console.log('Task transitioned successfully');
* } catch (error) {
* if (error instanceof InvalidTaskStateError) {
* console.error('Invalid state transition:', error.message);
* } else {
* console.error('Failed to transition task:', error);
* }
* }
* ```
*/
transitionTask(taskId, newState) {
return __awaiter(this, void 0, void 0, function* () {
const currentTask = yield this.taskManager.getTask(taskId);
// Validate state transition
if (!this.isValidTransition(currentTask.status, newState)) {
throw new InvalidTaskStateError(`Invalid transition from ${currentTask.status} to ${newState}`);
}
// Create transition record
const transition = {
from: currentTask.status,
to: newState,
timestamp: new Date().toISOString()
};
// Update task with new state and history
return this.taskManager.updateTask(taskId, {
status: newState,
transitions: [...(currentTask.transitions || []), transition]
});
});
}
/**
* Checks if a state transition is valid
*
* Validates whether a transition from one state to another is allowed
* according to the state machine rules.
*
* @param from - Current state
* @param to - Target state
* @returns True if the transition is valid, false otherwise
* @internal
*/
isValidTransition(from, to) {
const allowedTransitions = this.transitions.get(from);
return allowedTransitions ? allowedTransitions.has(to) : false;
}
/**
* Gets the transition history for a task
*
* Retrieves the complete history of state transitions for a task,
* including the from state, to state, and timestamp for each transition.
*
* @param taskId - ID of the task
* @returns Promise resolving to an array of task transitions
*
* @example
* ```typescript
* // Get the transition history for a task
* const history = await taskUpdater.getTransitionHistory('task-123');
* console.log(`Task has undergone ${history.length} transitions`);
*
* // Log each transition
* history.forEach(transition => {
* console.log(
* `${new Date(transition.timestamp).toLocaleString()}: ` +
* `${transition.from} → ${transition.to}`
* );
* });
* ```
*/
getTransitionHistory(taskId) {
return __awaiter(this, void 0, void 0, function* () {
const task = yield this.taskManager.getTask(taskId);
return task.transitions || [];
});
}
}
exports.TaskUpdater = TaskUpdater;
//# sourceMappingURL=task-updater.js.map