openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
200 lines (199 loc) • 5.21 kB
JavaScript
//#region extensions/acpx/src/runtime-turn.ts
function createDeferredResult() {
let resolve;
let reject;
return {
promise: new Promise((resolvePromise, rejectPromise) => {
resolve = resolvePromise;
reject = rejectPromise;
}),
resolve,
reject
};
}
var LegacyRunTurnEventQueue = class {
constructor() {
this.items = [];
this.waits = [];
this.closed = false;
}
push(item) {
if (this.closed) return;
const waiter = this.waits.shift();
if (waiter) {
waiter.resolve(item);
return;
}
this.items.push(item);
}
clear() {
this.items.length = 0;
}
close() {
if (this.closed) return;
this.closed = true;
for (const waiter of this.waits.splice(0)) waiter.resolve(null);
}
fail(error) {
if (this.closed) return;
this.error = error;
this.closed = true;
for (const waiter of this.waits.splice(0)) waiter.reject(error);
}
async next() {
const item = this.items.shift();
if (item) return item;
if (this.error) throw toLintErrorObject(this.error, "Non-Error thrown");
if (this.closed) return null;
return await new Promise((resolve, reject) => {
this.waits.push({
resolve,
reject
});
});
}
async *iterate() {
for (;;) {
const item = await this.next();
if (!item) return;
yield item;
}
}
};
function legacyRunTurnAsStartTurn(runtime, input) {
const result = createDeferredResult();
result.promise.catch(() => {});
const queue = new LegacyRunTurnEventQueue();
let resultSettled = false;
const settleResult = (next) => {
if (resultSettled) return;
resultSettled = true;
result.resolve(next);
};
(async () => {
try {
for await (const event of runtime.runTurn(input)) {
if (event.type === "done") {
settleResult({
status: "completed",
...event.stopReason ? { stopReason: event.stopReason } : {}
});
continue;
}
if (event.type === "error") {
settleResult({
status: "failed",
error: {
message: event.message,
...event.code ? { code: event.code } : {},
...event.detailCode ? { detailCode: event.detailCode } : {},
...event.retryable === void 0 ? {} : { retryable: event.retryable }
}
});
continue;
}
queue.push(event);
}
settleResult({
status: "failed",
error: {
code: "ACP_TURN_FAILED",
message: "ACP turn ended without a terminal done event."
}
});
} catch (error) {
result.reject(error);
queue.fail(error);
return;
}
queue.close();
})();
return {
requestId: input.requestId,
events: queue.iterate(),
result: result.promise,
async cancel(inputArgs) {
await runtime.cancel({
handle: input.handle,
reason: inputArgs?.reason
});
},
async closeStream() {
queue.clear();
queue.close();
}
};
}
/** Start an ACP turn, adapting legacy runTurn-only runtimes when needed. */
function startRuntimeTurn(runtime, input) {
return runtime.startTurn?.(input) ?? legacyRunTurnAsStartTurn(runtime, input);
}
/** Start an ACP turn through a lazy runtime resolver. */
function lazyStartRuntimeTurn(resolveRuntime, input) {
const turnPromise = resolveRuntime().then((runtime) => startRuntimeTurn(runtime, input));
return {
requestId: input.requestId,
events: { async *[Symbol.asyncIterator]() {
yield* (await turnPromise).events;
} },
result: turnPromise.then((turn) => turn.result),
cancel(inputArgs) {
return turnPromise.then((turn) => turn.cancel(inputArgs));
},
closeStream(inputArgs) {
return turnPromise.then((turn) => turn.closeStream(inputArgs));
}
};
}
function toLintErrorObject(value, fallbackMessage) {
if (value instanceof Error) return value;
if (typeof value === "string") return new Error(value);
const error = new Error(fallbackMessage, { cause: value });
if (typeof value === "object" && value !== null || typeof value === "function") Object.assign(error, value);
return error;
}
//#endregion
//#region extensions/acpx/src/runtime-proxy.ts
/** Create an ACP runtime facade backed by an async runtime resolver. */
function createLazyAcpRuntimeProxy(resolveRuntime) {
return {
async ensureSession(input) {
return await (await resolveRuntime()).ensureSession(input);
},
startTurn(input) {
return lazyStartRuntimeTurn(resolveRuntime, input);
},
async *runTurn(input) {
yield* (await resolveRuntime()).runTurn(input);
},
async getCapabilities(input) {
return await (await resolveRuntime()).getCapabilities?.(input) ?? { controls: [] };
},
async getStatus(input) {
return await (await resolveRuntime()).getStatus?.(input) ?? {};
},
async setMode(input) {
await (await resolveRuntime()).setMode?.(input);
},
async setConfigOption(input) {
await (await resolveRuntime()).setConfigOption?.(input);
},
async doctor() {
return await (await resolveRuntime()).doctor?.() ?? {
ok: true,
message: "ok"
};
},
async prepareFreshSession(input) {
await (await resolveRuntime()).prepareFreshSession?.(input);
},
async cancel(input) {
await (await resolveRuntime()).cancel(input);
},
async close(input) {
await (await resolveRuntime()).close(input);
}
};
}
//#endregion
export { createLazyAcpRuntimeProxy as t };