openclaw / src /plugins /runtime /index.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
4c76b0d verified
Raw History Blame Contribute Delete
10.5 kB
import { resolveSandboxWorkspaceAuthority } from "../../agents/sandbox/workspace-authority.js";
// Plugin runtime entrypoint assembles runtime helpers available to activated plugins.
import { getRuntimeConfig } from "../../config/config.js";
import {
listImageGenerationProviders,
listMusicGenerationProviders,
listVideoGenerationProviders,
} from "../../media-generation/registry.js";
import { RequestScopedSubagentRuntimeError } from "../../plugin-sdk/error-runtime.js";
import {
createLazyRuntimeMethod,
createLazyRuntimeMethodBinder,
createLazyRuntimeModule,
createLazyRuntimeSurface,
} from "../../shared/lazy-runtime.js";
import { VERSION } from "../../version.js";
import { listWebSearchProviders, runWebSearch } from "../../web-search/runtime.js";
import {
resolveNativePluginModelAuth,
resolveNativePluginModelConfig,
} from "../loader-runtime-load.js";
import { createRuntimeAgent } from "./runtime-agent.js";
import { createRuntimeBase } from "./runtime-base.js";
import { createRuntimeChannel } from "./runtime-channel.js";
import { createRuntimeEvents } from "./runtime-events.js";
import { createRuntimeLogging } from "./runtime-logging.js";
import { createRuntimeMedia } from "./runtime-media.js";
import { createRuntimeTaskFlow } from "./runtime-taskflow.js";
import { createRuntimeTasks } from "./runtime-tasks.js";
import type { PluginRuntimeFactory, PluginRuntime } from "./types.js";
const loadTtsRuntime = createLazyRuntimeModule(() => import("../../plugin-sdk/tts-runtime.js"));
const loadTtsRequestRuntime = createLazyRuntimeModule(() => import("./runtime-tts-request.js"));
const loadMediaUnderstandingRuntime = createLazyRuntimeModule(
() => import("../../media-understanding/runtime.js"),
);
const loadGatewayPluginRuntime = createLazyRuntimeModule(
() => import("../../gateway/server-plugins.js"),
);
function createRuntimeGateway(): PluginRuntime["gateway"] {
return {
isAvailable: async () => {
const runtime = await loadGatewayPluginRuntime();
return runtime.hasInProcessGatewayContext();
},
request: async (method, params, options) => {
const runtime = await loadGatewayPluginRuntime();
return runtime.dispatchTrustedPluginGatewayMethod(method, params, options);
},
};
}
function createRuntimeTts(): PluginRuntime["tts"] {
const bindTtsRuntime = createLazyRuntimeMethodBinder(loadTtsRuntime);
const bindTtsRequestRuntime = createLazyRuntimeMethodBinder(loadTtsRequestRuntime);
return {
prepareTtsRequest: bindTtsRequestRuntime((runtime) => runtime.prepareTtsRequest),
textToSpeech: bindTtsRuntime((runtime) => runtime.textToSpeech),
textToSpeechStream: bindTtsRuntime((runtime) => runtime.textToSpeechStream),
textToSpeechTelephony: bindTtsRuntime((runtime) => runtime.textToSpeechTelephony),
listVoices: bindTtsRuntime((runtime) => runtime.listSpeechVoices),
};
}
function createRuntimeMediaUnderstandingFacade(): PluginRuntime["mediaUnderstanding"] {
const bindMediaUnderstandingRuntime = createLazyRuntimeMethodBinder(
loadMediaUnderstandingRuntime,
);
return {
resolveAudioInputBudget: bindMediaUnderstandingRuntime(
(runtime) => runtime.resolveAudioInputBudget,
),
runFile: bindMediaUnderstandingRuntime((runtime) => runtime.runMediaUnderstandingFile),
describeImageFile: bindMediaUnderstandingRuntime((runtime) => runtime.describeImageFile),
describeImageFileWithModel: bindMediaUnderstandingRuntime(
(runtime) => runtime.describeImageFileWithModel,
),
extractStructuredWithModel: bindMediaUnderstandingRuntime(
(runtime) => runtime.extractStructuredWithModel,
),
describeVideoFile: bindMediaUnderstandingRuntime((runtime) => runtime.describeVideoFile),
transcribeAudioFile: bindMediaUnderstandingRuntime((runtime) => runtime.transcribeAudioFile),
};
}
function createRuntimeLlmFacade(): PluginRuntime["llm"] {
const loadAcquireLocalService = createLazyRuntimeMethod(
() => import("../../agents/provider-local-service.js"),
(runtime) => runtime.createConfiguredProviderLocalServiceAcquirer(getRuntimeConfig),
);
const loadLlm = createLazyRuntimeSurface(
() => import("./runtime-llm.runtime.js"),
(m) =>
m.createRuntimeLlm({
getConfig: getRuntimeConfig,
authority: {
allowComplete: true,
},
}),
);
return {
acquireLocalService: (...args) => loadAcquireLocalService(...args),
complete: async (params) => {
const llm = await loadLlm();
return llm.complete(params);
},
};
}
function createUnavailableSubagentRuntime(): PluginRuntime["subagent"] {
const unavailable = () => {
throw new RequestScopedSubagentRuntimeError();
};
return {
complete: unavailable,
run: unavailable,
waitForRun: unavailable,
getSessionMessages: unavailable,
deleteSession: unavailable,
};
}
function createUnavailableNodesRuntime(): PluginRuntime["nodes"] {
const unavailable = () => {
throw new Error("Plugin node runtime is only available inside the Gateway.");
};
return {
list: unavailable,
invoke: unavailable,
openDuplex: unavailable,
};
}
function createRuntimeWorktrees(): PluginRuntime["worktrees"] {
const loadService = () => import("../../agents/worktrees/service.js");
return {
async resolveCheckoutRoot(params) {
const { findGitCheckoutRoot } = await import("../../agents/worktrees/git.js");
return findGitCheckoutRoot(params.path) ?? undefined;
},
async hasSelfContainedCheckoutMetadata(params) {
const { hasSelfContainedGitMetadata } = await import("../../agents/worktrees/git.js");
return await hasSelfContainedGitMetadata(params.path);
},
async create(params) {
const { managedWorktrees } = await loadService();
const record = await managedWorktrees.create(params);
await managedWorktrees.acquire(record.id);
return { id: record.id, path: record.path, branch: record.branch };
},
async release(params) {
const { managedWorktrees } = await loadService();
await managedWorktrees.releaseByPath(params.path);
},
async removeIfLossless(params) {
const { managedWorktrees } = await loadService();
return managedWorktrees.removeIfLosslessByPath(params.path, {
ownerKind: params.ownerKind,
ownerId: params.ownerId,
});
},
};
}
function createRuntimeSandbox(agent: PluginRuntime["agent"]): PluginRuntime["sandbox"] {
const resolveWorkspaceAuthority = (
params: Parameters<PluginRuntime["sandbox"]["resolveWorkspaceAuthority"]>[0],
) =>
resolveSandboxWorkspaceAuthority({
...params,
sessionEntry: agent.session.getSessionEntry({
agentId: params.agentId,
sessionKey: params.sessionKey,
}),
});
return {
resolveWorkspaceAuthority,
async prepareWorkspaceAuthority(params) {
const authority = resolveWorkspaceAuthority(params);
if (!authority.sandboxed || authority.confinementError) {
return authority;
}
const { resolveSandboxContext } = await import("../../agents/sandbox/context.js");
await resolveSandboxContext({
config: params.config,
agentId: params.agentId,
sessionKey: params.sessionKey,
workspaceDir: params.workspaceDir,
requireCurrentConfig: true,
});
return authority;
},
};
}
// Loaded by path from the plugin loader, so static export analysis cannot see this contract.
export const createPluginRuntime: PluginRuntimeFactory = (
_options = {},
base = createRuntimeBase(),
) => {
const taskFlow = createRuntimeTaskFlow();
const tasks = createRuntimeTasks({
managedTaskFlow: taskFlow,
});
const agent = createRuntimeAgent();
let modelAuth = _options.modelAuth;
let modelConfig = _options.modelConfig;
const runtime: PluginRuntime = {
// Sourced from the shared OpenClaw version resolver (#52899) so plugins
// always see the same version the CLI reports, avoiding API-version drift.
version: VERSION,
gateway: _options.gateway ?? createRuntimeGateway(),
config: base.config,
agent,
hooks: _options.hooks ?? {
dispatchHookAgentTurn: async () => {
throw new Error("Plugin hook runtime is only available inside the Gateway.");
},
},
subagent: _options.subagent ?? createUnavailableSubagentRuntime(),
nodes: _options.nodes ?? createUnavailableNodesRuntime(),
sandbox: createRuntimeSandbox(agent),
worktrees: createRuntimeWorktrees(),
system: base.system,
media: createRuntimeMedia(),
webSearch: {
listProviders: listWebSearchProviders,
search: runWebSearch,
},
channel: createRuntimeChannel(
_options.dispatchReplyFromConfig
? { dispatchReplyFromConfig: _options.dispatchReplyFromConfig }
: undefined,
),
events: createRuntimeEvents(),
logging: createRuntimeLogging(),
state: base.state,
tasks,
tts: createRuntimeTts(),
mediaUnderstanding: createRuntimeMediaUnderstandingFacade(),
get modelAuth() {
return (modelAuth ??= resolveNativePluginModelAuth());
},
get modelConfig() {
return (modelConfig ??= resolveNativePluginModelConfig());
},
// Listings stay synchronous; execution loads only when requested.
imageGeneration: {
generate: async (params) =>
(await import("../../image-generation/runtime.js")).generateImage(params),
listProviders: (params) => listImageGenerationProviders(params?.config),
},
videoGeneration: {
generate: async (params) =>
(await import("../../video-generation/runtime.js")).generateVideo(params),
listProviders: (params) => listVideoGenerationProviders(params?.config),
},
musicGeneration: {
generate: async (params) =>
(await import("../../music-generation/runtime.js")).generateMusic(params),
listProviders: (params) => listMusicGenerationProviders(params?.config),
},
llm: createRuntimeLlmFacade(),
};
// SDK consumers retain these getter-only descriptors after lazy runtime materialization.
for (const key of [
"tts",
"mediaUnderstanding",
"imageGeneration",
"videoGeneration",
"musicGeneration",
"llm",
] as const) {
const value = runtime[key];
Object.defineProperty(runtime, key, { get: () => value });
}
return runtime;
};
export type { PluginRuntime } from "./types.js";