mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 20:35:39 -06:00
465043ca85
* fix(acp): enforce prompt and binding ownership * test(acp): align execution-start boundary * perf(startup): avoid broad ACP core import * fix(acp): order prompt replacement admission
98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
/**
|
|
* Lazy ACP runtime proxy for ACPX. It defers resolving the real runtime until
|
|
* the first ACP call while preserving the SDK runtime shape.
|
|
*/
|
|
import type { AcpRuntime, AcpRuntimeTurn, AcpRuntimeTurnInput } from "../runtime-api.js";
|
|
|
|
export type CompleteAcpRuntimeTurn = AcpRuntimeTurn &
|
|
Required<Pick<AcpRuntimeTurn, "promptStarted">>;
|
|
|
|
/**
|
|
* Contract for runtimes this extension resolves behind the lazy proxy. The
|
|
* SDK keeps these hooks optional for third-party backends, but every ACPX
|
|
* runtime (the extension's AcpxRuntime and the upstream acpx runtime)
|
|
* implements the full surface. Requiring them here turns an absent hook into
|
|
* a compile error instead of a silently fabricated success at runtime.
|
|
*/
|
|
export type CompleteAcpRuntime = Omit<AcpRuntime, "startTurn"> &
|
|
Required<
|
|
Pick<
|
|
AcpRuntime,
|
|
| "getCapabilities"
|
|
| "getStatus"
|
|
| "setMode"
|
|
| "setConfigOption"
|
|
| "doctor"
|
|
| "prepareFreshSession"
|
|
>
|
|
> & {
|
|
startTurn(input: AcpRuntimeTurnInput): CompleteAcpRuntimeTurn;
|
|
};
|
|
|
|
/** Start an ACP turn through a lazy runtime resolver without awaiting resolution up front. */
|
|
function lazyStartRuntimeTurn(
|
|
resolveRuntime: () => Promise<CompleteAcpRuntime>,
|
|
input: AcpRuntimeTurnInput,
|
|
): CompleteAcpRuntimeTurn {
|
|
const turnPromise = resolveRuntime().then((runtime) => runtime.startTurn(input));
|
|
return {
|
|
requestId: input.requestId,
|
|
get promptStarted() {
|
|
return turnPromise.then((turn) => turn.promptStarted);
|
|
},
|
|
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));
|
|
},
|
|
};
|
|
}
|
|
|
|
/** Create an ACP runtime facade backed by an async runtime resolver. */
|
|
export function createLazyAcpRuntimeProxy(
|
|
resolveRuntime: () => Promise<CompleteAcpRuntime>,
|
|
): CompleteAcpRuntime {
|
|
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);
|
|
},
|
|
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();
|
|
},
|
|
async prepareFreshSession(input) {
|
|
await (await resolveRuntime()).prepareFreshSession(input);
|
|
},
|
|
async cancel(input) {
|
|
await (await resolveRuntime()).cancel(input);
|
|
},
|
|
async close(input) {
|
|
await (await resolveRuntime()).close(input);
|
|
},
|
|
};
|
|
}
|