UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

146 lines (145 loc) • 6.56 kB
import { r as racePromiseWithAbortSignal } from "./abort-signal-Z3A36sLL.mjs"; import { t as notifyListeners } from "./listeners-BogSNJ-R.mjs"; import { A as validateAgentRunDelegatedAuthority, b as registerAgentRunDelegatedAuthorityClosedHandler, c as getActiveAgentRunDelegatedAuthority } from "./agent-run-registry-RDoBEeyg.mjs"; import { Ar as validateQuestionWaitAnswerParams, Dr as validateQuestionListParams, Er as validateQuestionGetParams, Or as validateQuestionRequestParams, kr as validateQuestionResolveParams } from "./src-D2gvuSyP.mjs"; import { t as GatewayClientRequestError } from "./request-error-BPxqIrwb.mjs"; import { h as registerActiveEmbeddedRunHumanInputWait } from "./run-state-BCpgti2M.mjs"; import { i as getGatewayToolCallerIdentity } from "./gateway-caller-context-BeMzkOlX.mjs"; import { t as questionShapeError } from "./question-validation-C3R346Mf.mjs"; import { n as QuestionManagerError, r as QuestionManagerErrorCodes, t as QuestionManager } from "./question-manager-BIP4Oi7t.mjs"; //#region src/infra/embedded-question-broker.ts const EMBEDDED_SECRET_STORE_REQUEST_BLOCKER = "Secret store requests need a running Gateway; ask the operator to run `openclaw secrets store` or use the Control UI."; let activeBroker = null; function invalidRequest(message) { return new GatewayClientRequestError({ code: "INVALID_REQUEST", message }); } /** Serves the question RPC contract for one embedded backend lifetime. */ var EmbeddedQuestionBroker = class { constructor(scheduler) { this.listeners = /* @__PURE__ */ new Set(); this.stopped = false; this.removeAuthorityListener = registerAgentRunDelegatedAuthorityClosedHandler(() => { this.manager.cancelClosedAuthorities(); }); this.manager = new QuestionManager(scheduler); } subscribe(listener) { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; } request(params, signal) { signal?.throwIfAborted(); if (this.stopped) throw new Error("Embedded question broker is stopped"); if (!validateQuestionRequestParams(params)) throw invalidRequest("Invalid question.request params"); if (params.questions.some((question) => question.secretStore)) throw invalidRequest(EMBEDDED_SECRET_STORE_REQUEST_BLOCKER); const error = questionShapeError(params.questions, { allowPlainSecretQuestions: true, validateUrls: false }); if (error) throw invalidRequest(error); const caller = getGatewayToolCallerIdentity(); const authority = caller?.approvalAuthority ?? (caller?.operationalRunInstance ? getActiveAgentRunDelegatedAuthority(caller.operationalRunInstance) : void 0); const isRequesterActive = () => { try { return !signal?.aborted && !caller?.approvalSignals?.some((inputSignal) => inputSignal.aborted) && (!caller?.operationalRunInstance || authority !== void 0) && (!authority || validateAgentRunDelegatedAuthority(authority)) && caller?.approvalAuthorityCheck?.() !== false && caller?.receiptAuthority?.() !== false; } catch { return false; } }; const abort = () => { this.manager.get(record.id); }; const record = this.manager.request({ ...structuredClone(params), ...caller ? { agentId: caller.agentId, sessionKey: caller.sessionKey, ...caller.operationalRunInstance ? { runId: caller.operationalRunInstance.runId } : {} } : {}, timeoutMs: params.timeoutMs ?? 9e5, isRequesterActive, registerHumanInputWait: authority ? (isPending) => registerActiveEmbeddedRunHumanInputWait(authority, isPending) : void 0, onResolved: (event) => { signal?.removeEventListener("abort", abort); notifyListeners(this.listeners, { event: "question.resolved", payload: event }); } }); signal?.addEventListener("abort", abort, { once: true }); notifyListeners(this.listeners, { event: "question.requested", payload: record }); return { id: record.id, expiresAtMs: record.expiresAtMs }; } async waitAnswer(params, signal) { signal?.throwIfAborted(); if (!validateQuestionWaitAnswerParams(params)) throw invalidRequest("Invalid question.waitAnswer params"); return await racePromiseWithAbortSignal(this.manager.waitAnswer(params.id, params.timeoutMs, params.includeResolutionId), signal); } resolve(params) { if (!validateQuestionResolveParams(params)) throw invalidRequest("Invalid question.resolve params"); if ("cancel" in params) return this.manager.cancel(params.id, params.resolvedBy); if (params.secretStoreAllowedHosts !== void 0) throw invalidRequest("Secret store allowed hosts require a store-bound question."); return this.manager.resolve(params.id, params.answers, params.resolvedBy, { resolutionId: params.resolutionId }); } get(params) { if (!validateQuestionGetParams(params)) throw invalidRequest("Invalid question.get params"); const question = this.manager.get(params.id); if (!question) throw new QuestionManagerError(QuestionManagerErrorCodes.NOT_FOUND, `question '${params.id}' was not found`); return { question }; } list(params = {}) { if (!validateQuestionListParams(params)) throw invalidRequest("Invalid question.list params"); return { questions: this.manager.list() }; } async call(method, params, extra) { extra?.signal?.throwIfAborted(); try { switch (method) { case "question.request": return this.request(params, extra?.signal); case "question.waitAnswer": return await this.waitAnswer(params, extra?.signal); case "question.resolve": return this.resolve(params); case "question.get": return this.get(params); case "question.list": return this.list(params); default: throw invalidRequest(`Unsupported embedded question method: ${method}`); } } catch (error) { if (error instanceof QuestionManagerError) throw new GatewayClientRequestError({ code: "INVALID_REQUEST", message: error.message, details: { reason: error.code } }); throw error; } } stop() { if (this.stopped) return; this.stopped = true; this.removeAuthorityListener(); for (const question of this.manager.list()) this.manager.cancel(question.id, "tui:embedded:stopped"); this.manager.close(); this.listeners.clear(); } }; function setEmbeddedQuestionBroker(broker) { activeBroker = broker; } function clearEmbeddedQuestionBroker(broker) { if (activeBroker === broker) activeBroker = null; } function getEmbeddedQuestionBroker() { return activeBroker; } //#endregion export { setEmbeddedQuestionBroker as i, clearEmbeddedQuestionBroker as n, getEmbeddedQuestionBroker as r, EmbeddedQuestionBroker as t };