Files
openclaw/src/plugins/runtime/runtime-agent.ts
2026-06-04 14:50:14 -07:00

210 lines
6.6 KiB
TypeScript

import { resolveAgentDir, resolveAgentWorkspaceDir } from "../../agents/agent-scope.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../agents/defaults.js";
import { resolveAgentIdentity } from "../../agents/identity.js";
import {
buildConfiguredModelCatalog,
resolveThinkingDefault,
} from "../../agents/model-selection.js";
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
import { ensureAgentWorkspace } from "../../agents/workspace.js";
import { normalizeThinkLevel, resolveThinkingProfile } from "../../auto-reply/thinking.js";
import { getRuntimeConfig } from "../../config/config.js";
import { resolveSessionFilePath, resolveStorePath } from "../../config/sessions/paths.js";
import {
listSessionEntries as listAccessorSessionEntries,
loadSessionEntry,
patchSessionEntry as patchAccessorSessionEntry,
replaceSessionEntry,
updateSessionEntry,
} from "../../config/sessions/session-accessor.js";
import {
loadSessionStore,
saveSessionStore,
updateSessionStore,
} from "../../config/sessions/store.js";
import type { SessionEntry } from "../../config/sessions/types.js";
import { createLazyRuntimeMethod, createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { defineCachedValue } from "./runtime-cache.js";
import type { PluginRuntime } from "./types.js";
type RuntimeSessionStoreReadParams = {
agentId?: string;
env?: NodeJS.ProcessEnv;
hydrateSkillPromptRefs?: boolean;
sessionKey: string;
storePath?: string;
};
type RuntimeSessionStoreListParams = Partial<Omit<RuntimeSessionStoreReadParams, "sessionKey">>;
type RuntimeSessionStoreEntrySummary = {
sessionKey: string;
entry: SessionEntry;
};
type RuntimeSessionStoreEntryUpdateParams = {
storePath: string;
sessionKey: string;
update: (
entry: SessionEntry,
) => Promise<Partial<SessionEntry> | null> | Partial<SessionEntry> | null;
skipMaintenance?: boolean;
takeCacheOwnership?: boolean;
};
type RuntimeSessionStoreEntryPatchParams = RuntimeSessionStoreReadParams & {
fallbackEntry?: SessionEntry;
preserveActivity?: boolean;
replaceEntry?: boolean;
update: (
entry: SessionEntry,
context: { existingEntry?: SessionEntry },
) => Promise<Partial<SessionEntry> | null> | Partial<SessionEntry> | null;
};
type RuntimeUpsertSessionEntryParams = RuntimeSessionStoreReadParams & {
entry: SessionEntry;
};
const loadEmbeddedAgentRuntime = createLazyRuntimeModule(
() => import("./runtime-embedded-agent.runtime.js"),
);
function resolveRuntimeThinkingCatalog(
params: Parameters<PluginRuntime["agent"]["resolveThinkingPolicy"]>[0],
) {
if (params.catalog) {
return params.catalog;
}
const configuredCatalog = buildConfiguredModelCatalog({ cfg: getRuntimeConfig() });
return configuredCatalog.length > 0 ? configuredCatalog : undefined;
}
function getSessionEntry(params: RuntimeSessionStoreReadParams): SessionEntry | undefined {
return loadSessionEntry({
agentId: params.agentId,
env: params.env,
hydrateSkillPromptRefs: params.hydrateSkillPromptRefs,
sessionKey: params.sessionKey,
storePath: params.storePath,
});
}
function listSessionEntries(
params: RuntimeSessionStoreListParams = {},
): RuntimeSessionStoreEntrySummary[] {
return listAccessorSessionEntries({
agentId: params.agentId,
env: params.env,
hydrateSkillPromptRefs: params.hydrateSkillPromptRefs,
storePath: params.storePath,
});
}
async function patchSessionEntry(
params: RuntimeSessionStoreEntryPatchParams,
): Promise<SessionEntry | null> {
return await patchAccessorSessionEntry(
{
agentId: params.agentId,
env: params.env,
hydrateSkillPromptRefs: params.hydrateSkillPromptRefs,
sessionKey: params.sessionKey,
storePath: params.storePath,
},
params.update,
{
fallbackEntry: params.fallbackEntry,
preserveActivity: params.preserveActivity,
replaceEntry: params.replaceEntry,
},
);
}
async function updateSessionStoreEntry(
params: RuntimeSessionStoreEntryUpdateParams,
): Promise<SessionEntry | null> {
// Preserve the plugin runtime's object-parameter API while routing the actual
// mutation through the storage-neutral session accessor seam.
return await updateSessionEntry(
{
sessionKey: params.sessionKey,
storePath: params.storePath,
},
params.update,
{
skipMaintenance: params.skipMaintenance,
takeCacheOwnership: params.takeCacheOwnership,
},
);
}
async function upsertSessionEntry(params: RuntimeUpsertSessionEntryParams): Promise<void> {
// The public runtime helper historically replaced the full entry. Use the
// replace seam so removed fields do not survive as merge leftovers.
await replaceSessionEntry(
{
agentId: params.agentId,
env: params.env,
hydrateSkillPromptRefs: params.hydrateSkillPromptRefs,
sessionKey: params.sessionKey,
storePath: params.storePath,
},
params.entry,
);
}
/** Creates the plugin runtime agent facade with lazy embedded-agent/session helpers. */
export function createRuntimeAgent(): PluginRuntime["agent"] {
const agentRuntime = {
defaults: {
model: DEFAULT_MODEL,
provider: DEFAULT_PROVIDER,
},
resolveAgentDir,
resolveAgentWorkspaceDir,
resolveAgentIdentity,
resolveThinkingDefault,
normalizeThinkingLevel: normalizeThinkLevel,
resolveThinkingPolicy: (params) => {
const profile = resolveThinkingProfile({
...params,
catalog: resolveRuntimeThinkingCatalog(params),
});
const policy: Omit<
ReturnType<PluginRuntime["agent"]["resolveThinkingPolicy"]>,
"defaultLevel"
> = {
levels: profile.levels.map(({ id, label }) => ({ id, label })),
};
return profile.defaultLevel ? { ...policy, defaultLevel: profile.defaultLevel } : policy;
},
resolveAgentTimeoutMs,
ensureAgentWorkspace,
} satisfies Omit<PluginRuntime["agent"], "runEmbeddedAgent" | "runEmbeddedPiAgent" | "session"> &
Partial<Pick<PluginRuntime["agent"], "runEmbeddedAgent" | "runEmbeddedPiAgent" | "session">>;
defineCachedValue(agentRuntime, "runEmbeddedAgent", () =>
createLazyRuntimeMethod(loadEmbeddedAgentRuntime, (runtime) => runtime.runEmbeddedAgent),
);
defineCachedValue(
agentRuntime,
"runEmbeddedPiAgent",
() => (agentRuntime as PluginRuntime["agent"]).runEmbeddedAgent,
);
defineCachedValue(agentRuntime, "session", () => ({
resolveStorePath,
getSessionEntry,
listSessionEntries,
patchSessionEntry,
upsertSessionEntry,
loadSessionStore,
saveSessionStore,
updateSessionStore,
updateSessionStoreEntry,
resolveSessionFilePath,
}));
return agentRuntime as PluginRuntime["agent"];
}