andy-stack_vaultkeeper-ai/Services/AbortService.ts
Andrew Beal 2de8109a74 refactor: restructure AI prompt and agent architecture for multi-agent planning support
- Move prompts from AIClasses to AIPrompts directory
- Replace centralized IPrompt injection with direct property setters on IAIClass
- Remove allowDestructiveActions parameter from streamRequest methods
- Add toolDefinitions, systemPrompt, and userInstruction properties to IAIClass
- Refactor AIFunctionDefinitions to static methods with agent-specific tool sets
- Add planning agent function definitions (CreatePlan, Replan, CompleteStep, SubmitPlan)
- Create AIControllerService to handle agent orchestration
- Add execution plan related copy strings and replacement utility
- Update all AI providers (Claude, Gemini, OpenAI) to use new architecture
2025-12-30 19:07:00 +00:00

70 lines
No EOL
2 KiB
TypeScript

// This class is designed to provide a single centralised abort controller
export class AbortService {
private abortController: AbortController = new AbortController();
public static isAbortError(error: unknown): boolean {
return error instanceof DOMException && error.name === "AbortError";
}
public reset = () => this.initialiseAbortController(); // semantic alias for initialiseAbortController
public initialiseAbortController(): void {
this.abort();
this.abortController = new AbortController();
}
public signal(): AbortSignal {
return this.abortController.signal;
}
public reason(): Error {
return this.signal().reason instanceof Error ? this.signal().reason as Error : new Error("Aborted");
}
public abort(reason?: string): void {
this.abortController.abort(
new DOMException(reason ?? "Aborted", "AbortError")
);
}
// useful if you need to rethrow the abort error
public throw(): never {
throw this.reason();
}
public async abortableOperation<T>(executor: () => Promise<T>): Promise<T> {
const signal = this.abortController.signal;
if (signal.aborted) {
this.throw();
}
let abortHandler: () => void;
let abortWon = false;
const executorPromise = executor();
const abortPromise = new Promise<never>((_, reject) => {
abortHandler = () => {
abortWon = true;
reject(this.reason());
};
signal.addEventListener("abort", abortHandler, { once: true });
});
// Suppress AbortErrors from executor once abort has won the race
executorPromise.catch(error => {
if (abortWon && AbortService.isAbortError(error)) {
return;
}
});
abortPromise.catch(() => {});
try {
return await Promise.race([executorPromise, abortPromise]);
} finally {
signal.removeEventListener("abort", abortHandler!);
}
}
}