import { prompt } from "@oh-my-pi/pi-utils"; import btwUserPrompt from "../../prompts/system/btw-user.md" with { type: "text" }; import { BtwPanelComponent } from "../components/btw-panel"; import type { InteractiveModeContext } from "../types"; interface BtwRequest { component: BtwPanelComponent; abortController: AbortController; question: string; } export class BtwController { #activeRequest: BtwRequest | undefined; constructor(private readonly ctx: InteractiveModeContext) {} hasActiveRequest(): boolean { return this.#activeRequest !== undefined; } handleEscape(): boolean { if (!this.#activeRequest) return false; this.#closeActiveRequest({ abort: this.#activeRequest.abortController.signal.aborted === false }); return true; } dispose(): void { this.#closeActiveRequest({ abort: true }); } async start(question: string): Promise { const trimmedQuestion = question.trim(); if (!trimmedQuestion) { this.ctx.showStatus("Usage: /btw "); return; } const model = this.ctx.session.model; if (!model) { this.ctx.showError("No active model available for /btw."); return; } this.#closeActiveRequest({ abort: true }); const request: BtwRequest = { component: new BtwPanelComponent({ question: trimmedQuestion, tui: this.ctx.ui }), abortController: new AbortController(), question: trimmedQuestion, }; this.ctx.btwContainer.clear(); this.ctx.btwContainer.addChild(request.component); this.ctx.ui.requestRender(); this.#activeRequest = request; void this.#runRequest(request); } async #runRequest(request: BtwRequest): Promise { try { const promptText = prompt.render(btwUserPrompt, { question: request.question }); const { replyText } = await this.ctx.session.runEphemeralTurn({ promptText, onTextDelta: delta => { if (this.#isActiveRequest(request)) { request.component.appendText(delta); } }, signal: request.abortController.signal, }); if (!this.#isActiveRequest(request)) { return; } if (replyText) { request.component.setAnswer(replyText); } request.component.markComplete(); } catch (error) { if (!this.#isActiveRequest(request)) { return; } if (request.abortController.signal.aborted) { request.component.markAborted(); return; } request.component.markError(error instanceof Error ? error.message : String(error)); } } #closeActiveRequest(options: { abort: boolean }): void { const request = this.#activeRequest; if (!request) return; this.#activeRequest = undefined; if (options.abort) { request.abortController.abort(); } request.component.close(); this.ctx.btwContainer.clear(); this.ctx.ui.requestRender(); } #isActiveRequest(request: BtwRequest): boolean { return this.#activeRequest === request; } }