Skip to main content
Glama
controller.ts3.86 kB
/** * Execution controller for debugging and introspection */ import type { ExecutionState, ExecutionStatus, ExecutionController as IExecutionController, } from "../types/execution.js"; import type { ExecutionContext } from "./context.js"; export class ExecutionController implements IExecutionController { private status: ExecutionStatus = "not_started"; private currentNodeId: string | null = null; private context: ExecutionContext | null = null; private breakpoints: Set<string> = new Set(); private pauseRequested: boolean = false; private stepRequested: boolean = false; private stopRequested: boolean = false; private resumePromise: Promise<void> | null = null; private resumeResolve: (() => void) | null = null; setContext(context: ExecutionContext): void { this.context = context; } setStatus(status: ExecutionStatus): void { this.status = status; } setCurrentNode(nodeId: string | null): void { this.currentNodeId = nodeId; } async waitIfPaused(): Promise<void> { if (this.status === "paused" || this.pauseRequested) { this.status = "paused"; this.pauseRequested = false; // Create promise for resume if it doesn't exist if (!this.resumePromise) { this.resumePromise = new Promise((resolve) => { this.resumeResolve = resolve; }); } // Wait for resume - execution is now paused await this.resumePromise; this.resumePromise = null; this.resumeResolve = null; } } shouldPause(nodeId: string): boolean { return this.breakpoints.has(nodeId) || this.pauseRequested; } /** * Check if we should pause due to a breakpoint and set pauseRequested if so */ checkAndSetBreakpointPause(nodeId: string): void { if (this.breakpoints.has(nodeId) && !this.pauseRequested && this.status === "running") { this.pauseRequested = true; } } shouldStop(): boolean { return this.stopRequested; } pause(): void { if (this.status === "running") { this.pauseRequested = true; } else { throw new Error(`Cannot pause: execution status is "${this.status}"`); } } resume(): void { if (this.status === "paused") { this.status = "running"; if (this.resumeResolve) { this.resumeResolve(); } } else { throw new Error(`Cannot resume: execution status is "${this.status}"`); } } async step(): Promise<void> { if (this.status === "paused") { this.stepRequested = true; this.resume(); // Wait for step to complete (will be paused again after one node) await this.waitIfPaused(); } else { throw new Error(`Cannot step: execution status is "${this.status}"`); } } getState(): ExecutionState { if (!this.context) { throw new Error("Execution context not set"); } return { status: this.status, currentNodeId: this.currentNodeId, executionHistory: this.context.getHistory(), context: this.context, }; } setBreakpoints(nodeIds: string[]): void { this.breakpoints = new Set(nodeIds); } clearBreakpoints(): void { this.breakpoints.clear(); } getBreakpoints(): string[] { return Array.from(this.breakpoints); } markStepComplete(): void { if (this.stepRequested) { this.stepRequested = false; this.pauseRequested = true; } } stop(): void { if (this.status === "running" || this.status === "paused") { this.stopRequested = true; const wasPaused = this.status === "paused"; this.status = "stopped"; // If paused, resume to allow stop to take effect if (wasPaused && this.resumeResolve) { this.resumeResolve(); } } else { throw new Error(`Cannot stop: execution status is "${this.status}"`); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TeamSparkAI/mcpGraph'

If you have feedback or need assistance with the MCP directory API, please join our Discord server