openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
224 lines (223 loc) • 10.1 kB
JavaScript
import { r as resolveRuntimeWorkerUrl } from "./runtime-worker-url-CpdriB1D.js";
import { n as resolveInstalledManifestRegistryIndexFingerprint } from "./manifest-registry-installed-DdhpzefH.js";
import { f as serializeConfigResolutionFacts, o as getConfigResolutionFacts } from "./resolution-facts-Dks1tbik.js";
import { t as projectConfigOntoRuntimeSourceSnapshot } from "./runtime-source-projection-DOHmC11j.js";
import { k as cloneAuthProfileStore } from "./persisted-B_qhhBlh.js";
import { n as withPluginRuntimeGenerationScope } from "./generation-scope-Cf83d_iq.js";
import { o as setPreparedModelFullCatalogAuth } from "./prepared-model-runtime-auth-CnrySjUa.js";
import { o as captureProviderSyntheticAuthFacts } from "./provider-runtime-BRJDPNgk.js";
import { t as listManifestSyntheticAuthProviderRefs } from "./synthetic-auth.runtime.js";
import { n as WorkerTaskPool, t as WorkerTaskError } from "./worker-task-pool-BNbf5LmH.js";
import { n as markPreparedModelCatalogFull } from "./prepared-model-runtime.full-catalog-CFj7JJlS.js";
import { n as PreparedModelRuntimePublicationSupersededError } from "./prepared-model-runtime.errors-DeG6Ut3_.js";
import { t as fingerprintPreparedRuntimeFacts } from "./prepared-model-runtime.facts-vxXJKbiM.js";
//#region src/agents/prepared-model-catalog-worker.ts
/** Runs complete model-catalog discovery outside the Gateway event loop. */
const PREPARED_MODEL_CATALOG_WORKER_TIMEOUT_MS = 18e4;
const PREPARED_MODEL_CATALOG_WORKER_GENERATION_POLL_MS = 25;
var PreparedModelCatalogGenerationMismatchError = class extends Error {
constructor(agentDir, generationFingerprint, reconstructedFingerprint) {
super(`prepared model catalog worker reconstructed a different runtime generation for ${agentDir} (owner=${generationFingerprint} worker=${reconstructedFingerprint})`);
this.agentDir = agentDir;
this.generationFingerprint = generationFingerprint;
this.reconstructedFingerprint = reconstructedFingerprint;
this.name = "PreparedModelCatalogGenerationMismatchError";
}
};
function fingerprintPreparedModelWorkerRequest(input, request) {
return fingerprintPreparedRuntimeFacts([input.generationFingerprint, request]);
}
function fingerprintPreparedModelCatalogPlugins(snapshot) {
return fingerprintPreparedRuntimeFacts({
config: snapshot.configFingerprint ?? null,
index: resolveInstalledManifestRegistryIndexFingerprint(snapshot.index),
pluginIds: snapshot.pluginIds ?? null,
policy: snapshot.policyHash,
workspaceDir: snapshot.workspaceDir ?? null
});
}
function fingerprintPreparedModelCatalogGeneration(params) {
return fingerprintPreparedRuntimeFacts({
input: params.input,
sourceConfigForSecrets: params.sourceConfigForSecrets,
configResolutionFacts: params.configResolutionFacts,
sourceConfigResolutionFacts: params.sourceConfigResolutionFacts,
authStore: params.authStore,
providerIds: params.providerIds,
preferBuiltPluginArtifacts: params.preferBuiltPluginArtifacts === true,
pluginFingerprint: fingerprintPreparedModelCatalogPlugins(params.pluginMetadataSnapshot)
});
}
function createPreparedModelCatalogWorkerInput(params) {
const source = params.agentFacts.input;
const input = {
...source.agentId ? { agentId: source.agentId } : {},
agentDir: source.agentDir,
...source.inheritedAuthDir ? { inheritedAuthDir: source.inheritedAuthDir } : {},
...source.workspaceDir ? { workspaceDir: source.workspaceDir } : {},
...source.readOnly ? { readOnly: true } : {},
skipCredentials: true,
env: { ...params.agentFacts.env },
...source.allowGatewaySubagentBinding ? { allowGatewaySubagentBinding: true } : {},
...source.runtimePluginSelections ? { runtimePluginSelections: source.runtimePluginSelections } : {},
config: source.config
};
const sourceConfigForSecrets = projectConfigOntoRuntimeSourceSnapshot(source.config);
const configResolutionFacts = serializeConfigResolutionFacts(source.config);
const sourceConfigResolutionFacts = getConfigResolutionFacts(source.config) === getConfigResolutionFacts(sourceConfigForSecrets) ? configResolutionFacts : serializeConfigResolutionFacts(sourceConfigForSecrets);
const authStore = cloneAuthProfileStore(params.agentFacts.authStore);
const providerIds = [...params.agentFacts.providerIds];
const { normalizePluginId: _normalizePluginId, ...pluginMetadataSnapshot } = params.pluginMetadataSnapshot;
return {
kind: "catalog",
generationFingerprint: fingerprintPreparedModelCatalogGeneration({
input,
sourceConfigForSecrets,
configResolutionFacts,
sourceConfigResolutionFacts,
authStore,
providerIds,
preferBuiltPluginArtifacts: params.preferBuiltPluginArtifacts,
pluginMetadataSnapshot: params.pluginMetadataSnapshot
}),
input,
sourceConfigForSecrets,
configResolutionFacts,
sourceConfigResolutionFacts,
authStore,
providerIds,
preferBuiltPluginArtifacts: params.preferBuiltPluginArtifacts === true,
pluginMetadataSnapshot
};
}
function createPreparedModelCatalogWorker(params) {
const workerInput = createPreparedModelCatalogWorkerInput(params);
const metadataSnapshot = params.pluginMetadataSnapshot;
const superseded = () => new PreparedModelRuntimePublicationSupersededError(`prepared model runtime catalog generation was superseded for ${workerInput.input.agentDir}`);
let generationPoll;
let stoppedError;
let expectedFingerprint;
const captures = /* @__PURE__ */ new Map();
const assertCurrent = () => {
if (stoppedError) throw stoppedError;
if (!params.isCurrent()) throw superseded();
};
let pool;
const mismatch = (message) => new PreparedModelCatalogGenerationMismatchError(workerInput.input.agentDir, message.generationFingerprint, message.reconstructedFingerprint);
const createPool = () => new WorkerTaskPool({
workerUrl: resolveRuntimeWorkerUrl({
currentModuleUrl: import.meta.url,
sourceWorkerName: "prepared-model-catalog.worker",
distWorkerPath: "agents/prepared-model-catalog.worker.js"
}),
maxWorkers: 1,
idleTimeoutMs: 0,
restartOnError: false,
workerOptions: {
workerData: workerInput,
env: workerInput.input.env
},
validateResult: (message) => {
assertCurrent();
if (message.status === "generation-mismatch") throw mismatch(message);
if (message.status === "ok" && message.generationFingerprint !== expectedFingerprint) throw new Error("prepared model catalog worker returned a stale generation");
}
});
const stop = async (error) => {
stoppedError ??= error;
clearInterval(generationPoll);
generationPoll = void 0;
for (const controller of captures.keys()) controller.abort(stoppedError);
await Promise.allSettled(captures.values());
await pool?.close(stoppedError);
};
const request = async (command) => {
let message;
let requestPool;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(new WorkerTaskError("worker task timed out", "timeout")), PREPARED_MODEL_CATALOG_WORKER_TIMEOUT_MS);
try {
assertCurrent();
generationPoll ??= setInterval(() => {
if (!params.isCurrent()) stop(superseded());
}, PREPARED_MODEL_CATALOG_WORKER_GENERATION_POLL_MS);
generationPoll.unref();
const { input } = workerInput;
const capture = withPluginRuntimeGenerationScope({
metadataSnapshot,
pluginRegistry: params.pluginRegistry
}, () => captureProviderSyntheticAuthFacts({
config: input.config,
env: input.env,
workspaceDir: input.workspaceDir,
providerRefs: command.kind === "catalog" ? [...listManifestSyntheticAuthProviderRefs(metadataSnapshot.index), ...workerInput.providerIds] : [...workerInput.providerIds, ...command.providerIds],
signal: controller.signal
}));
captures.set(controller, capture);
let syntheticAuth;
try {
syntheticAuth = await capture;
} finally {
captures.delete(controller);
}
controller.signal.throwIfAborted();
const value = {
...command,
syntheticAuth
};
requestPool = pool ??= createPool();
message = await requestPool.run(() => {
assertCurrent();
expectedFingerprint = fingerprintPreparedModelWorkerRequest(workerInput, value);
return value;
}, {
timeoutMs: PREPARED_MODEL_CATALOG_WORKER_TIMEOUT_MS,
signal: controller.signal
});
assertCurrent();
} catch (error) {
const failure = error instanceof Error ? error : new Error(String(error));
if (failure instanceof PreparedModelCatalogGenerationMismatchError) {
if (pool === requestPool) pool = void 0;
await requestPool?.close(failure);
throw failure;
}
controller.abort(error);
await stop(failure);
throw error;
} finally {
clearTimeout(timeout);
}
if (message.status === "failed") throw new Error(message.error);
if (message.status === "generation-mismatch") throw mismatch(message);
return message;
};
return {
loadCatalog: async () => {
const message = await request({ kind: "catalog" });
if (message.kind !== "catalog") throw new Error("prepared model catalog worker returned an auth refresh result");
const modelCatalog = markPreparedModelCatalogFull(message.snapshot);
setPreparedModelFullCatalogAuth(modelCatalog, {
authStore: message.authStore,
authModes: message.authModes
});
return modelCatalog;
},
loadAuth: async ({ providerIds, profileIds }) => {
const normalizedProviderIds = [...new Set(providerIds)].toSorted((left, right) => left.localeCompare(right));
const normalizedProfileIds = profileIds ? [...new Set(profileIds)].toSorted((left, right) => left.localeCompare(right)) : void 0;
const message = await request({
kind: "auth-refresh",
providerIds: normalizedProviderIds,
...normalizedProfileIds ? { profileIds: normalizedProfileIds } : {}
});
if (message.kind !== "auth-refresh") throw new Error("prepared model auth refresh worker returned a catalog result");
return {
authStore: message.authStore,
authModes: message.authModes
};
}
};
}
//#endregion
export { fingerprintPreparedModelCatalogGeneration as n, fingerprintPreparedModelWorkerRequest as r, createPreparedModelCatalogWorker as t };