refactor: eliminate export name collisions (#122084)

* refactor: eliminate export name collisions

* chore(scripts): burn resolved collision baselines

* refactor: narrow legacy session load options

* chore: refresh SDK and session debt baselines

* refactor: adopt upstream secrets collision fix

* test(plugin-sdk): mock renamed session store core

* fix(scripts): track renamed session accessor core
This commit is contained in:
Peter Steinberger
2026-08-11 10:41:50 -07:00
committed by GitHub
parent 653ab3b2aa
commit ebb2770000
426 changed files with 1992 additions and 2374 deletions
@@ -1 +1 @@
{"contentHash":"f0501615d366cab1ceffabfcbb580b9a9f1008bbd4e24a46e1fc10d73e9cd2a3","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
{"contentHash":"14115e942e60b33851a102cf0091ec7c6e29e015ad800471c095346de6708e0b","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"ae5e7178a886a346e7a7d88e80344b84c84679e156d08eb863c8a5e2bbffe03c","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
{"contentHash":"944bceb3db8adc5516b7f80933a3a3dd483cfeb162b102f78e7f31e40286ac54","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"2f175fa56f7836b6dc666ef556b964ecfa83f6f81f683340907c7456c8f301ea","entrypoint":"agent-runtime","importSpecifier":"openclaw/plugin-sdk/agent-runtime"}
{"contentHash":"e0ee84e5e66b6c524a69e4d5791ee3d962859937e572b452db54b926f57219a3","entrypoint":"agent-runtime","importSpecifier":"openclaw/plugin-sdk/agent-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"9360377bb569d5f8f53151152e4b1e27e860ebc38d176ee3d71cbf3461c79ca8","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
{"contentHash":"0841384461391ee65d656cdcce3e956417be3a861f6a7dcde8b7592e951c8381","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
@@ -1 +1 @@
{"contentHash":"5e756ed6e46b362058d9ca438cf858c463bb01fd55269b0b019341fe0075bcda","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
{"contentHash":"87519437ca1f4ed669866f5efa28ab61836ead8c9251f2d401d755b43debdaa4","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
@@ -1 +1 @@
{"contentHash":"3523cddf2dad5146687de9564879903e20224b140f4a9756ba57e76034c6490a","entrypoint":"channel-inbound","importSpecifier":"openclaw/plugin-sdk/channel-inbound"}
{"contentHash":"2598df91c020fd173ef4c0b171718a4fd90e90599536ff71ca3f4d1b3adf97fe","entrypoint":"channel-inbound","importSpecifier":"openclaw/plugin-sdk/channel-inbound"}
@@ -1 +1 @@
{"contentHash":"5091fb6b03b3e1b3cb6b51323cb7bd991f8022d1aac479b4a67982993dec79cf","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
{"contentHash":"b6454c9a2e9fd243ec392fb51d1542fc176f350bc682213813f0ea7fc0166af6","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
@@ -1 +1 @@
{"contentHash":"33c41deadb29159ecaf9e40c0053d43a81531ca48145f11217f811e4232c5cf2","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
{"contentHash":"6236a390dab6017b4eef42591729660b3e114b43ae34798d41482670a3ee0613","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
@@ -1 +1 @@
{"contentHash":"c6e8524442d54875e1ce5ec211394472c2e2734fbfbebe320b069346374b922d","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
{"contentHash":"b2bbf7a51a586c54b554475998b6a259be1e7fc7db9604c2e1205f56ff35f704","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"1edb0e67f51c958fff1d3ace6e47debb831555720208ebfb732cf65de2bb333a","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
{"contentHash":"c5239579070b39b2d63a3cf6b9faa66152e5d71f64d73716a84c4cc510054d2d","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"243be23ce58934cc502148cde9b747c4e8d26d176526e99dda383f16f20fc124","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
{"contentHash":"fe90342ef9fd6a4173e1feed09852380f256fafafb7836bc2c1df7400a8bcf3c","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
@@ -1 +1 @@
{"contentHash":"a27b168ddc12affa72e1d646d36ea8ef65f18f2de7a7397f0f9e816659e54c0e","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
{"contentHash":"23c052386a61874b2f9d19f872a90a9e6863971e812e573d8271b89d92181e30","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
@@ -1 +1 @@
{"contentHash":"336c432da880945a8dccc3f6e0c96cc062b4afdd96b73b35382ffedc537762be","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
{"contentHash":"f31959d35168e31228f318289d78117945dcd79e8ff5c57473636025c7f8d881","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"66b344dc4d56bdb7d3c1ddccb64899a013f98e1dda7f734e6b75de49c41ba0fc","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
{"contentHash":"76391f09ded09871b1a5ac2fbbf2bd9901f55c529cdd97c00a0111aeb319ba33","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"e7788890d54d5784f4bce552c7143a0083cd1cdd46f126b98d66ad8357327e51","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
{"contentHash":"d05730f5b90c0164e719e97694582d27f15ec4442c8d764044b0960a6e575c93","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
@@ -1 +1 @@
{"contentHash":"4b0295b65533f821a02e3399298424b35c2c75082e4d53d57ea88ff2f84d74ad","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
{"contentHash":"ef4d5d011283052e9b24d4bf57fba52e38b48aef38e1be322273eaf290f3eb85","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
+1 -1
View File
@@ -1 +1 @@
{"contentHash":"c489a3d36e88b55b29c9019df733662acb67ec95e2fd0a99d2b208ac123801f5","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
{"contentHash":"a72d078274268d0e5b2c1a18a4787980c55e61479d3efb7a11dfc7303ac28d28","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
@@ -1 +1 @@
{"contentHash":"73b1700f912dfb34554f7a9e72bca0ff9e1ea08360f32c981519488a25023f2c","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
{"contentHash":"9d8a7eec9dba85091301963980960ddb8993aaae52972fb245f25c5bd608b150","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
+4 -1
View File
@@ -67,7 +67,10 @@ const sessionStoreRuntimeFileBackedCompatNames = new Set([
"updateSessionStore",
]);
const embeddedAgentSessionFileRuntimeNames = new Set(["resolveSessionFilePath"]);
const materializingSessionEntryAccessorNames = new Set(["listSessionEntries", "loadSessionEntry"]);
const materializingSessionEntryAccessorNames = new Set([
"listSessionEntriesCore",
"loadSessionEntry",
]);
// Shipped beta.5 official plugins import these deprecated helpers during
// doctor migrations. Remove this ratchet with the compatibility bridge once
@@ -1,400 +1,4 @@
[
{
"name": "cleanupSessionLifecycleArtifacts",
"files": [
"src/config/sessions/session-accessor.sqlite-lifecycle.ts",
"src/plugin-sdk/session-store-runtime.ts"
],
"sdk": true
},
{
"name": "createPluginLoaderLogger",
"files": [
"src/plugins/loader-shared.ts",
"src/plugins/logger.ts"
]
},
{
"name": "listMemoryEmbeddingProviders",
"files": [
"src/plugins/memory-embedding-provider-runtime.ts",
"src/plugins/memory-embedding-providers.ts"
],
"sdk": true
},
{
"name": "listSessionEntries",
"files": [
"src/config/sessions/session-accessor.entry.ts",
"src/plugin-sdk/session-store-runtime.ts"
],
"sdk": true
},
{
"name": "loadBundledPluginPublicSurface",
"files": [
"src/plugin-sdk/test-helpers/public-surface-loader.ts",
"src/test-utils/bundled-plugin-public-surface.ts"
],
"sdk": true
},
{
"name": "loadBundledPluginPublicSurfaceModuleSync",
"files": [
"src/plugin-sdk/facade-loader.ts",
"src/plugin-sdk/facade-runtime.ts"
],
"sdk": true
},
{
"name": "loadCodexBundleMcpThreadConfig",
"files": [
"src/agents/codex-mcp-config.ts",
"src/plugin-sdk/agent-harness-runtime.ts"
],
"sdk": true
},
{
"name": "loadCombinedSessionStoreForGateway",
"files": [
"src/config/sessions/combined-store-gateway.ts",
"src/plugin-sdk/session-transcript-hit.ts"
],
"sdk": true
},
{
"name": "loadConfig",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/config/io.runtime.ts"
],
"sdk": true
},
{
"name": "loadJsonFile",
"files": [
"src/infra/json-file.ts",
"src/plugin-sdk/json-store.ts"
],
"sdk": true
},
{
"name": "loadPluginManifestRegistry",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/plugins/manifest-registry.ts"
],
"sdk": true
},
{
"name": "loadQaRuntimeModule",
"files": [
"src/plugin-sdk/qa-runner-runtime.ts",
"src/plugin-sdk/qa-runtime.ts"
],
"sdk": true
},
{
"name": "loadSessionStore",
"files": [
"src/library.ts",
"src/plugin-sdk/session-store-runtime.ts"
],
"sdk": true
},
{
"name": "loadWebMedia",
"files": [
"src/media/web-media.ts",
"src/plugins/runtime/runtime-web-channel-plugin.ts"
],
"sdk": true
},
{
"name": "loadWebMediaRaw",
"files": [
"src/media/web-media.ts",
"src/plugins/runtime/runtime-web-channel-plugin.ts"
],
"sdk": true
},
{
"name": "materializeRequesterScopedMcpToolsForHarnessRun",
"files": [
"src/agents/agent-bundle-mcp-harness.ts",
"src/plugin-sdk/agent-harness-runtime.ts"
],
"sdk": true
},
{
"name": "materializeStaticMcpToolsForScheduledHarnessRun",
"files": [
"src/agents/agent-bundle-mcp-harness.ts",
"src/plugin-sdk/codex-mcp-projection.ts"
],
"sdk": true
},
{
"name": "maybeApplyTtsToPayload",
"files": [
"src/tts/tts-payload.ts",
"src/tts/tts.ts"
],
"sdk": true
},
{
"name": "mergeSessionEntry",
"files": [
"src/config/sessions/types.ts",
"src/infra/state-migrations.session-store.ts"
]
},
{
"name": "normalizeCronRunDiagnostics",
"files": [
"src/cron/run-diagnostics-normalize.ts",
"src/cron/run-diagnostics.ts"
]
},
{
"name": "normalizeStringRecord",
"files": [
"src/agents/bundle-mcp-adapter.ts",
"src/plugins/manifest-capability-normalizers.ts"
]
},
{
"name": "normalizeToolName",
"files": [
"src/agents/tool-display-common.ts",
"src/agents/tool-policy-shared.ts",
"src/cron/run-diagnostics-normalize.ts"
]
},
{
"name": "optimizeImageToJpeg",
"files": [
"src/media/web-media.ts",
"src/plugins/runtime/runtime-web-channel-plugin.ts"
],
"sdk": true
},
{
"name": "pad",
"files": [
"src/agents/bash-tools.shared.ts",
"src/commands/models/list.format.ts"
]
},
{
"name": "parseClawHubPluginSpec",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/infra/clawhub-spec.ts"
]
},
{
"name": "parseCsvFilter",
"files": [
"src/image-generation/live-test-helpers.ts",
"src/video-generation/live-test-helpers.ts"
]
},
{
"name": "parseFrontmatter",
"files": [
"src/agents/utils/frontmatter.ts",
"src/hooks/frontmatter.ts",
"src/skills/loading/frontmatter.ts"
]
},
{
"name": "parseInlineDirectives",
"files": [
"src/auto-reply/reply/directive-handling.parse.ts",
"src/utils/directive-tags.ts"
],
"sdk": true
},
{
"name": "parseModelRef",
"files": [
"src/agents/model-selection-normalize.ts",
"src/commands/doctor/shared/codex-route-model-ref.ts"
],
"sdk": true
},
{
"name": "parseQaTarget",
"files": [
"src/plugin-sdk/qa-channel-protocol.ts",
"src/plugin-sdk/qa-channel.ts"
],
"sdk": true
},
{
"name": "parseTimeoutMs",
"files": [
"src/cli/parse-timeout.ts",
"src/commands/gateway-status/helpers.ts"
]
},
{
"name": "patchSessionEntry",
"files": [
"src/config/sessions/session-accessor.sqlite-entry.ts",
"src/plugin-sdk/session-store-runtime.ts"
],
"sdk": true
},
{
"name": "pathExists",
"files": [
"src/agents/worktrees/git.ts",
"src/utils.ts"
],
"sdk": true
},
{
"name": "pathsEqual",
"files": [
"src/commands/doctor/shared/missing-configured-plugin-install.records.ts",
"src/plugins/update-config.ts"
]
},
{
"name": "peekSessionMcpRuntime",
"files": [
"src/agents/agent-bundle-mcp-manager-api.ts",
"src/gateway/server-methods/__mocks__/tools-effective.runtime.ts"
]
},
{
"name": "planPluginUninstall",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/plugins/uninstall.ts"
]
},
{
"name": "readAmbientTranscriptWatermark",
"files": [
"src/config/sessions/ambient-transcript-watermark.ts",
"src/plugin-sdk/session-store-runtime.ts"
],
"sdk": true
},
{
"name": "readAskUserQuestionId",
"files": [
"src/auto-reply/reply/dispatch-from-config.payloads.ts",
"src/infra/question-reaction-runtime.ts"
]
},
{
"name": "readConfigFileSnapshot",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/config/io.runtime.ts"
],
"sdk": true
},
{
"name": "readConfigFileSnapshotForWrite",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/config/io.runtime.ts"
],
"sdk": true
},
{
"name": "readPersistedInstalledPluginIndex",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/plugins/installed-plugin-index-store.ts"
]
},
{
"name": "readSessionEntry",
"files": [
"src/agents/subagents/announce/subagent-announce.runtime.ts",
"src/cron/isolated-agent.turn-test-helpers.ts"
]
},
{
"name": "readSessionTranscriptVisibleMessageDelta",
"files": [
"src/config/sessions/session-accessor.sqlite-active-events.ts",
"src/plugin-sdk/session-transcript-runtime.ts"
],
"sdk": true
},
{
"name": "readSessionUpdatedAt",
"files": [
"src/config/sessions/session-accessor.sqlite-entry.ts",
"src/plugin-sdk/session-store-runtime.ts"
],
"sdk": true
},
{
"name": "recordHookInstall",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/hooks/installs.ts"
]
},
{
"name": "recordPluginInstall",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/plugins/installs.ts"
]
},
{
"name": "redactSecrets",
"files": [
"src/commands/status-all/format.ts",
"src/logging/redact.ts"
],
"sdk": true
},
{
"name": "refreshPluginRegistry",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/plugins/plugin-registry-snapshot.ts"
]
},
{
"name": "replaceConfigFile",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/config/mutate.ts"
],
"sdk": true
},
{
"name": "reportClawHubPluginInstallTelemetry",
"files": [
"src/cli/plugins-cli-test-helpers.ts",
"src/infra/clawhub-packages.ts"
]
},
{
"name": "requestSafeGatewayRestart",
"files": [
"src/cli/daemon-cli/lifecycle-safe-restart.ts",
"src/infra/restart-coordinator.ts"
]
},
{
"name": "requireRecord",
"files": [
"src/acp/translator.bridge-test-helpers.ts",
"src/gateway/test-helpers.assertions.ts"
]
},
{
"name": "resolveAdvertisedLanHost",
"files": [
@@ -2,7 +2,6 @@
"embeddedAgentSessionTarget": {},
"memoryHostSessionCorpus": {},
"sessionAccessorRead": {
"src/agents/subagents/announce/subagent-announce-output.ts": 3,
"src/agents/subagents/announce/subagent-announce.test-support.ts": 2,
"src/agents/tools/transcripts-tool.ts": 2,
"src/auto-reply/reply/commands-session-store.ts": 2,
@@ -1,39 +1,9 @@
[
{
"name": "loadBundledPluginPublicSurfaceModuleSync",
"wrapped": "src/plugin-sdk/facade-loader.ts",
"wrapper": "src/plugin-sdk/facade-runtime.ts"
},
{
"name": "loadCombinedSessionStoreForGateway",
"wrapped": "src/config/sessions/combined-store-gateway.ts",
"wrapper": "src/plugin-sdk/session-transcript-hit.ts"
},
{
"name": "loadPluginManifestRegistry",
"wrapped": "src/plugins/manifest-registry.ts",
"wrapper": "src/config/doc-baseline.runtime.ts"
},
{
"name": "loadWebMediaRaw",
"wrapped": "src/media/web-media.ts",
"wrapper": "src/plugins/runtime/runtime-web-channel-plugin.ts"
},
{
"name": "loadWebMedia",
"wrapped": "src/media/web-media.ts",
"wrapper": "src/plugins/runtime/runtime-web-channel-plugin.ts"
},
{
"name": "maybeApplyTtsToPayload",
"wrapped": "src/tts/tts-payload.ts",
"wrapper": "src/tts/tts.ts"
},
{
"name": "normalizeCronRunDiagnostics",
"wrapped": "src/cron/run-diagnostics-normalize.ts",
"wrapper": "src/cron/run-diagnostics.ts"
},
{
"name": "normalizeOutboundReplyPayload",
"wrapped": "src/infra/outbound/reply-payload-normalize.ts",
@@ -44,32 +14,16 @@
"wrapped": "src/plugins/config-normalization-shared.ts",
"wrapper": "src/plugins/config-policy.ts"
},
{
"name": "optimizeImageToJpeg",
"wrapped": "src/media/web-media.ts",
"wrapper": "src/plugins/runtime/runtime-web-channel-plugin.ts"
},
{
"name": "pruneStaleCommandPolls",
"wrapped": "src/agents/command-poll-backoff.ts",
"wrapper": "src/agents/command-poll-backoff.runtime.ts"
},
{
"name": "readAmbientTranscriptWatermark",
"wrapped": "src/config/sessions/ambient-transcript-watermark.ts",
"wrapper": "src/plugin-sdk/session-store-runtime.ts"
},
{
"name": "readBooleanParam",
"wrapped": "src/plugin-sdk/boolean-param.ts",
"wrapper": "src/infra/outbound/message-action-params.ts"
},
{
"name": "readSessionTranscriptVisibleMessageDelta",
"wrapped": "src/config/sessions/session-accessor.sqlite-active-events.ts",
"wrapper": "src/plugin-sdk/session-transcript-runtime.ts",
"via": "src/config/sessions/session-accessor.ts"
},
{
"name": "resolveAllowedModelRef",
"wrapped": "src/agents/model-selection-resolve.ts",
+4 -4
View File
@@ -63,7 +63,7 @@ function readFirstStringValue(
return readTrimmedStringAlias(source, keys);
}
function normalizeToolName(value: string): string | undefined {
function normalizeToolPolicyName(value: string): string | undefined {
const normalized = normalizeLowercaseStringOrEmpty(value);
if (!normalized || normalized.length > 128) {
return undefined;
@@ -76,7 +76,7 @@ function parseToolNameFromTitle(title: string | undefined | null): string | unde
return undefined;
}
const head = normalizeOptionalString(title.split(":", 1)[0]);
return head ? normalizeToolName(head) : undefined;
return head ? normalizeToolPolicyName(head) : undefined;
}
function resolveToolNameForPermission(params: {
@@ -93,8 +93,8 @@ function resolveToolNameForPermission(params: {
const fromMeta = readFirstStringValue(toolMeta, ["toolName", "tool_name", "name"]);
const fromRawInput = readFirstStringValue(rawInput, ["tool", "toolName", "tool_name", "name"]);
const fromTitle = parseToolNameFromTitle(toolCall?.title);
const metaName = fromMeta ? normalizeToolName(fromMeta) : undefined;
const rawInputName = fromRawInput ? normalizeToolName(fromRawInput) : undefined;
const metaName = fromMeta ? normalizeToolPolicyName(fromMeta) : undefined;
const rawInputName = fromRawInput ? normalizeToolPolicyName(fromRawInput) : undefined;
const titleName = fromTitle;
if ((fromMeta && !metaName) || (fromRawInput && !rawInputName)) {
return undefined;
+3 -3
View File
@@ -133,7 +133,7 @@ export async function expectOversizedPromptRejected(params: { sessionId: string;
export type MockCallSource = { mock: { calls: Array<Array<unknown>> } };
export function requireRecord(value: unknown, label: string): Record<string, unknown> {
export function requireAcpObject(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object") {
throw new Error(`expected ${label}`);
}
@@ -157,10 +157,10 @@ export function expectConfigOption(options: unknown, id: string, fields: Record<
export function sessionUpdatePayloads(source: MockCallSource, updateType?: string) {
const payloads = source.mock.calls.map((call, index) => {
const envelope = requireRecord(call[0], `session update envelope ${index}`);
const envelope = requireAcpObject(call[0], `session update envelope ${index}`);
return {
sessionId: envelope.sessionId,
update: requireRecord(envelope.update, `session update ${index}`),
update: requireAcpObject(envelope.update, `session update ${index}`),
};
});
if (!updateType) {
+4 -4
View File
@@ -7,7 +7,7 @@ import {
createSetSessionModeRequest,
createSetSessionConfigOptionRequest,
type MockCallSource,
requireRecord,
requireAcpObject,
expectConfigOption,
expectSessionUpdate,
} from "./translator.bridge-test-helpers.js";
@@ -352,7 +352,7 @@ describe("acp setSessionConfigOption bridge behavior", () => {
(request as unknown as MockCallSource).mock.calls.some(
([method, params]) =>
method === "sessions.patch" &&
requireRecord(params, "sessions.patch params").key === "bool-config-session",
requireAcpObject(params, "sessions.patch params").key === "bool-config-session",
),
).toBe(false);
@@ -383,7 +383,7 @@ describe("acp setSessionConfigOption bridge behavior", () => {
};
}
if (method === "sessions.patch") {
expect(requireRecord(_params, "sessions.patch params")).toMatchObject({
expect(requireAcpObject(_params, "sessions.patch params")).toMatchObject({
key: "usage-inherit-session",
responseUsage: null,
});
@@ -434,7 +434,7 @@ describe("acp setSessionConfigOption bridge behavior", () => {
};
}
if (method === "sessions.patch") {
expect(requireRecord(_params, "sessions.patch params")).toMatchObject({
expect(requireAcpObject(_params, "sessions.patch params")).toMatchObject({
key: "usage-off-session",
responseUsage: "off",
});
+22 -22
View File
@@ -74,8 +74,8 @@ vi.mock("./agent-bundle-mcp-runtime.js", async (importOriginal) => {
});
import {
materializeRequesterScopedMcpToolsForHarnessRun,
materializeStaticMcpToolsForScheduledHarnessRun,
materializeRequesterScopedMcpToolsForHarnessRunCore,
materializeStaticMcpToolsForScheduledHarnessRunCore,
} from "./agent-bundle-mcp-harness.js";
function makeRuntime(params: { sessionId: string; requesterSenderId: string }): SessionMcpRuntime {
@@ -152,14 +152,14 @@ beforeEach(() => {
mocks.getAdvertisedScopedMcpCatalog.mockClear();
});
describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
describe("materializeStaticMcpToolsForScheduledHarnessRunCore", () => {
it("materializes static tools without carrying requester identity and applies the stored cap", async () => {
const runtime = makeRuntime({ sessionId: "scheduled", requesterSenderId: "unused" });
delete runtime.requesterScope;
runtime.peekCatalog()!.servers["user-mail"]!.codexApprovalMode = "approve";
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled",
workspaceDir: "/workspace",
toolsAllow: ["user-mail__inbox"],
@@ -181,7 +181,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
delete runtime.requesterScope;
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-denied",
workspaceDir: "/workspace",
toolsAllow: ["read"],
@@ -228,7 +228,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
const callTool = vi.spyOn(runtime, "callTool");
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-app",
workspaceDir: "/workspace",
toolsAllow: ["user-mail__show", "user-mail__app-only"],
@@ -299,7 +299,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
const callTool = vi.spyOn(runtime, "callTool");
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-app-approval",
workspaceDir: "/workspace",
toolsAllow: ["*"],
@@ -363,7 +363,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
});
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-app-yolo",
workspaceDir: "/workspace",
toolsAllow: ["*"],
@@ -386,7 +386,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
runtime.getCatalog = async () => emptyCatalog;
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-empty",
workspaceDir: "/workspace",
toolsAllow: ["*"],
@@ -417,7 +417,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
runtime.getCatalog = async () => failedCatalog;
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-diagnostic",
workspaceDir: "/workspace",
toolsAllow: ["*"],
@@ -436,7 +436,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const callTool = vi.spyOn(runtime, "callTool");
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-prompt",
workspaceDir: "/workspace",
toolsAllow: ["user-mail__inbox"],
@@ -456,7 +456,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const callTool = vi.spyOn(runtime, "callTool");
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-yolo",
workspaceDir: "/workspace",
toolsAllow: ["user-mail__inbox"],
@@ -482,7 +482,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const callTool = vi.spyOn(runtime, "callTool");
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: `scheduled-${mode}`,
workspaceDir: "/workspace",
toolsAllow: ["user-mail__inbox"],
@@ -499,7 +499,7 @@ describe("materializeStaticMcpToolsForScheduledHarnessRun", () => {
mocks.getOrCreateSessionMcpRuntime.mockResolvedValue(runtime);
const callTool = vi.spyOn(runtime, "callTool");
const result = await materializeStaticMcpToolsForScheduledHarnessRun({
const result = await materializeStaticMcpToolsForScheduledHarnessRunCore({
sessionId: "scheduled-unknown",
workspaceDir: "/workspace",
toolsAllow: ["user-mail__inbox"],
@@ -518,10 +518,10 @@ afterEach(() => {
mcpUiResourceTesting.clearViewStore();
});
describe("materializeRequesterScopedMcpToolsForHarnessRun", () => {
describe("materializeRequesterScopedMcpToolsForHarnessRunCore", () => {
it("returns undefined before any requester resolves", async () => {
mocks.setResolveImpl(async () => undefined);
const result = await materializeRequesterScopedMcpToolsForHarnessRun({
const result = await materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-empty",
workspaceDir: "/workspace",
requesterSenderId: "guest",
@@ -538,7 +538,7 @@ describe("materializeRequesterScopedMcpToolsForHarnessRun", () => {
});
await expect(
materializeRequesterScopedMcpToolsForHarnessRun({
materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-cleanup",
workspaceDir: "/workspace",
requesterSenderId: "authed",
@@ -559,7 +559,7 @@ describe("materializeRequesterScopedMcpToolsForHarnessRun", () => {
});
});
const authed = await materializeRequesterScopedMcpToolsForHarnessRun({
const authed = await materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-stable",
workspaceDir: "/workspace",
requesterSenderId: "authed",
@@ -575,7 +575,7 @@ describe("materializeRequesterScopedMcpToolsForHarnessRun", () => {
});
await authed!.dispose();
const guest = await materializeRequesterScopedMcpToolsForHarnessRun({
const guest = await materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-stable",
workspaceDir: "/workspace",
requesterSenderId: "guest",
@@ -602,7 +602,7 @@ describe("materializeRequesterScopedMcpToolsForHarnessRun", () => {
}),
);
const result = await materializeRequesterScopedMcpToolsForHarnessRun({
const result = await materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-policy",
workspaceDir: "/workspace",
requesterSenderId: "authed",
@@ -630,12 +630,12 @@ describe("materializeRequesterScopedMcpToolsForHarnessRun", () => {
});
});
const alice = await materializeRequesterScopedMcpToolsForHarnessRun({
const alice = await materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-route",
workspaceDir: "/workspace",
requesterSenderId: "alice",
});
const bob = await materializeRequesterScopedMcpToolsForHarnessRun({
const bob = await materializeRequesterScopedMcpToolsForHarnessRunCore({
sessionId: "session-route",
workspaceDir: "/workspace",
requesterSenderId: "bob",
+2 -2
View File
@@ -160,7 +160,7 @@ function buildCatalogTools(
* Materialize only static configured MCP for an authenticated scheduled turn.
* No requester identity is accepted here, so requester resolvers stay unreachable.
*/
export async function materializeStaticMcpToolsForScheduledHarnessRun(
export async function materializeStaticMcpToolsForScheduledHarnessRunCore(
params: Omit<
MaterializeRequesterScopedMcpToolsForHarnessRunParams,
"requesterSenderId" | "agentAccountId" | "messageChannel"
@@ -252,7 +252,7 @@ export async function materializeStaticMcpToolsForScheduledHarnessRun(
* Updates the session advertised-catalog cache when a requester resolves a catalog.
* Before any requester resolves in the session, returns undefined (nothing to advertise).
*/
export async function materializeRequesterScopedMcpToolsForHarnessRun(
export async function materializeRequesterScopedMcpToolsForHarnessRunCore(
params: MaterializeRequesterScopedMcpToolsForHarnessRunParams,
): Promise<RequesterScopedHarnessMcpTools | undefined> {
const scopedRuntime = await getOrCreateRequesterScopedMcpRuntime({
@@ -6,7 +6,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
import type { SessionEntry } from "../config/sessions.js";
import { formatSqliteSessionFileMarker } from "../config/sessions/legacy-sqlite-marker.js";
import {
listSessionEntries,
listSessionEntriesCore,
loadTranscriptEvents,
replaceSessionEntry,
} from "../config/sessions/session-accessor.js";
@@ -304,7 +304,7 @@ function requireStorePath(): string {
}
function findStoredSessionEntry(sessionKey: string): SessionEntry | undefined {
return listSessionEntries({ storePath: requireStorePath() }).find(
return listSessionEntriesCore({ storePath: requireStorePath() }).find(
(candidate) => candidate.sessionKey === sessionKey,
)?.entry;
}
@@ -443,7 +443,7 @@ describe("agentCommand compaction transcript rotation", () => {
});
const storeAfterRotation = Object.fromEntries(
listSessionEntries({ storePath }).map(({ entry, sessionKey }) => [sessionKey, entry]),
listSessionEntriesCore({ storePath }).map(({ entry, sessionKey }) => [sessionKey, entry]),
);
const entriesAfterRotation = Object.entries(storeAfterRotation);
expect(entriesAfterRotation).toHaveLength(1);
@@ -977,7 +977,7 @@ describe("agentCommand compaction transcript rotation", () => {
sessionId: "rotated-session",
});
const persisted = Object.fromEntries(
listSessionEntries({ storePath }).map(({ entry, sessionKey: key }) => [key, entry]),
listSessionEntriesCore({ storePath }).map(({ entry, sessionKey: key }) => [key, entry]),
);
expect(persisted[sessionKey]).toMatchObject({
sessionId: "rotated-session",
+4 -4
View File
@@ -38,7 +38,7 @@ import {
getInternalToolExecutionPreparer,
} from "./runtime/internal-hooks.js";
import type { ToolDefinition } from "./sessions/index.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import { jsonResult, payloadTextResult, ToolInputError } from "./tools/common.js";
type AnyAgentTool = AgentTool;
@@ -357,7 +357,7 @@ export function findClientToolNameConflicts(params: {
for (const name of params.existingToolNames ?? []) {
const trimmed = name.trim();
if (trimmed) {
existingNormalized.add(normalizeToolName(trimmed));
existingNormalized.add(normalizeToolPolicyName(trimmed));
}
}
@@ -368,7 +368,7 @@ export function findClientToolNameConflicts(params: {
if (!rawName) {
continue;
}
const normalizedName = normalizeToolName(rawName);
const normalizedName = normalizeToolPolicyName(rawName);
if (existingNormalized.has(normalizedName)) {
conflicts.add(rawName);
}
@@ -400,7 +400,7 @@ export function toToolDefinitions(
): ToolDefinition[] {
return tools.map((tool) => {
const name = tool.name || "tool";
const normalizedName = normalizeToolName(name);
const normalizedName = normalizeToolPolicyName(name);
const beforeHookWrapped = isToolWrappedWithBeforeToolCallHook(tool);
const sourcePreparer = getInternalToolExecutionPreparer(tool);
const definition = {
@@ -48,7 +48,7 @@ import { normalizeFileToolPathParam } from "./agent-tools.params.js";
import { BEFORE_TOOL_CALL_SOURCE_TOOL } from "./before-tool-call-metadata.js";
import { getChannelAgentToolMeta } from "./channel-tools.js";
import { resolveAgentRunAbortLifecycleFields } from "./run-termination.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import {
resolveToolExecutionErrorKind,
resolveToolResultFailureKind,
@@ -391,7 +391,7 @@ export function findSkillUsageMatch(params: {
}): SkillUsageMatch | undefined {
const command = params.ctx?.skillCommand;
if (command) {
const commandToolName = normalizeToolName(command.toolName ?? params.toolName);
const commandToolName = normalizeToolPolicyName(command.toolName ?? params.toolName);
if (!commandToolName || commandToolName === params.toolName) {
const skillSource = resolveSkillTelemetrySourceValue(command.skillSource);
const snapshotMatch = findResolvedSkillUsageMatch({
@@ -51,7 +51,7 @@ import {
normalizeCodeModeExecBeforeHookParamsForToolKind,
} from "./code-mode-control-tools.js";
import { admitSingleToolCallLoop } from "./tool-loop-admission.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
const BEFORE_TOOL_CALL_HOOK_FAILURE_REASON =
"Tool call blocked because before_tool_call hook failed";
@@ -81,7 +81,7 @@ export function consumeFinalClientVoiceToolConfirmation(args: {
agentId: voiceRun?.agentId,
voiceSessionId: voiceRun?.voiceSessionId,
runId: args.ctx?.runId,
toolName: normalizeToolName(args.toolName || "tool"),
toolName: normalizeToolPolicyName(args.toolName || "tool"),
toolParams: args.params,
...(voiceRun ? { isConfirmable: () => isClientVoiceSessionConfirmable(voiceRun) } : {}),
});
@@ -97,7 +97,7 @@ export async function runBeforeToolCallHook(args: {
signal?: AbortSignal;
approvalMode?: "request" | "report" | "deny" | "defer";
}): Promise<HookOutcome> {
const toolName = normalizeToolName(args.toolName || "tool");
const toolName = normalizeToolPolicyName(args.toolName || "tool");
const params = args.params;
let releaseArgumentChurnPolicyWait: (() => void) | undefined;
@@ -73,7 +73,7 @@ import {
} from "./code-mode-control-tools.js";
import { attachInternalToolExecutionPreparer } from "./runtime/internal-hooks.js";
import { buildToolMutationState } from "./tool-mutation.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import {
formatToolExecutionErrorMessage,
isTrustedToolExecutionPreflightError,
@@ -303,7 +303,7 @@ export function wrapToolWithBeforeToolCallHook(
}
const toolCallOrdinal = ctx?.allocateToolOutcomeOrdinal?.(toolCallId);
const preExecutionStartedAt = Date.now();
const normalizedToolName = normalizeToolName(toolName || "tool");
const normalizedToolName = normalizeToolPolicyName(toolName || "tool");
const trace =
hookOptions.emitDiagnostics && ctx?.trace
? freezeDiagnosticTraceContext(createChildDiagnosticTraceContext(ctx.trace))
@@ -55,7 +55,7 @@ import { createAgentToolsSandboxContext } from "./test-helpers/agent-tools-sandb
import { stubTool } from "./test-helpers/fast-tool-stubs.js";
import { createHostSandboxFsBridge } from "./test-helpers/host-sandbox-fs-bridge.js";
import { buildEmptyExplicitToolAllowlistError } from "./tool-allowlist-guard.js";
import { DEFAULT_PLUGIN_TOOLS_ALLOWLIST_ENTRY, normalizeToolName } from "./tool-policy.js";
import { DEFAULT_PLUGIN_TOOLS_ALLOWLIST_ENTRY, normalizeToolPolicyName } from "./tool-policy.js";
import { replaceWithEffectiveCronCreatorToolAllowlist } from "./tools/cron-tool.js";
import { getGatewayToolCallerIdentity } from "./tools/gateway-caller-context.js";
@@ -127,8 +127,8 @@ function expectNoSubagentControlTools(tools: ReturnType<typeof createOpenClawCod
}
function applyRuntimeToolsAllow<T extends { name: string }>(tools: T[], toolsAllow: string[]) {
const allowSet = new Set(toolsAllow.map((name) => normalizeToolName(name)));
return tools.filter((tool) => allowSet.has(normalizeToolName(tool.name)));
const allowSet = new Set(toolsAllow.map((name) => normalizeToolPolicyName(name)));
return tools.filter((tool) => allowSet.has(normalizeToolPolicyName(tool.name)));
}
type OpenClawCodingTool = ReturnType<typeof createOpenClawCodingTools>[number];
+2 -2
View File
@@ -86,7 +86,7 @@ import { applyToolPolicyPipeline } from "./tool-policy-pipeline.js";
import {
expandToolGroups,
hasRestrictiveAllowPolicy,
normalizeToolName,
normalizeToolPolicyName,
replaceWithEffectiveToolAllowlist,
} from "./tool-policy.js";
import {
@@ -466,7 +466,7 @@ function createOpenClawCodingToolsInternal(options?: OpenClawCodingToolsOptions)
const runtimeToolAllowlistIncludesMessage = expandToolGroups(
options?.runtimeToolAllowlist ?? [],
).some((toolName) => {
const normalized = normalizeToolName(toolName);
const normalized = normalizeToolPolicyName(toolName);
return normalized === "*" || normalized === "message";
});
// The verified requester profile owns completion authority; its delivery grant
@@ -9,7 +9,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import {
deleteSessionEntryLifecycle,
loadSessionEntry,
patchSessionEntry,
patchSessionEntryCore,
replaceSessionEntry,
} from "../../config/sessions/session-accessor.js";
import type { SessionEntry } from "../../config/sessions/types.js";
@@ -643,7 +643,7 @@ describe("resolveSessionAuthProfileOverride", () => {
expect(sessionEntry).toBeDefined();
const sessionStore = { [sessionKey]: sessionEntry! };
await patchSessionEntry(scope, () => ({ label: "renamed", pinnedAt: undefined }));
await patchSessionEntryCore(scope, () => ({ label: "renamed", pinnedAt: undefined }));
await clearSessionAuthProfileOverride({
sessionEntry: sessionEntry!,
sessionStore,
@@ -700,7 +700,7 @@ describe("resolveSessionAuthProfileOverride", () => {
expect(sessionEntry).toBeDefined();
const sessionStore = { [sessionKey]: sessionEntry! };
await patchSessionEntry(scope, () => ({ label: "renamed", pinnedAt: undefined }));
await patchSessionEntryCore(scope, () => ({ label: "renamed", pinnedAt: undefined }));
const resolved = await resolveOpenAiSession({
agentDir,
sessionEntry: sessionEntry!,
@@ -740,7 +740,7 @@ describe("resolveSessionAuthProfileOverride", () => {
const sessionEntry = loadSessionEntry({ ...scope, readConsistency: "latest" });
expect(sessionEntry).toBeDefined();
const sessionStore = { [sessionKey]: sessionEntry! };
await patchSessionEntry(scope, () => ({ label: "renamed", pinnedAt: undefined }));
await patchSessionEntryCore(scope, () => ({ label: "renamed", pinnedAt: undefined }));
const resolved = await resolveOpenAiSession({
agentDir,
@@ -803,7 +803,7 @@ describe("resolveSessionAuthProfileOverride", () => {
if (persisted) {
await replaceSessionEntry(scope, sessionEntry);
sessionEntry = loadSessionEntry({ ...scope, readConsistency: "latest" })!;
await patchSessionEntry(scope, () => ({
await patchSessionEntryCore(scope, () => ({
...latestEntry,
authProfileOverrideSource: source,
pinnedAt: undefined,
+1 -1
View File
@@ -113,7 +113,7 @@ async function persistSessionAuthProfileOverrideState(params: {
}
const persisted = await (
await loadSessionAccessor()
).patchSessionEntry(
).patchSessionEntryCore(
{ storePath, sessionKey },
(current) => {
// Compare inside the canonical SQLite writer so a concurrent /model pin
+2 -2
View File
@@ -33,7 +33,7 @@ import { processSchema } from "./bash-tools.schemas.js";
import {
clampWithDefault,
deriveSessionName,
pad,
padProcessStatus,
readEnvInt,
sliceLogLines,
truncateMiddle,
@@ -356,7 +356,7 @@ export function createProcessTool(
.map((s) => {
const label = s.name ? truncateMiddle(s.name, 80) : truncateMiddle(s.command, 120);
const marker = "waitingForInput" in s && s.waitingForInput ? " [input-wait]" : "";
return `${s.sessionId} ${pad(s.status, 9)} ${
return `${s.sessionId} ${padProcessStatus(s.status, 9)} ${
formatDurationCompact(s.runtimeMs) ?? "n/a"
}${marker} :: ${label}`;
});
+1 -1
View File
@@ -231,7 +231,7 @@ function stripQuotes(value: string): string {
}
/** Right-pads a string for aligned plain-text process output. */
export function pad(str: string, width: number) {
export function padProcessStatus(str: string, width: number) {
if (str.length >= width) {
return str;
}
+2 -2
View File
@@ -8,7 +8,7 @@ import {
} from "../config/sessions.js";
import { parseSqliteSessionFileMarker } from "../config/sessions/legacy-sqlite-marker.js";
import {
listSessionEntries,
listSessionEntriesCore,
loadSessionEntry,
loadTranscriptEvents,
} from "../config/sessions/session-accessor.js";
@@ -125,7 +125,7 @@ export async function readBtwTranscriptMessages(params: {
const storePath = completeTarget ? params.storePath : (params.storePath ?? marker?.storePath);
const markerMatches =
marker && !completeTarget
? listSessionEntries({
? listSessionEntriesCore({
agentId: marker.agentId,
storePath: marker.storePath,
}).filter(({ entry }) => entry.sessionId === marker.sessionId)
+2 -2
View File
@@ -3,7 +3,7 @@ import { isRecord } from "../../packages/normalization-core/src/record-coerce.js
import type { BundleMcpServerConfig } from "../plugins/bundle-mcp.js";
export { isRecord } from "../../packages/normalization-core/src/record-coerce.js";
export function normalizeStringRecord(value: unknown): Record<string, string> | undefined {
export function normalizeMcpStringRecord(value: unknown): Record<string, string> | undefined {
if (!isRecord(value)) {
return undefined;
}
@@ -47,7 +47,7 @@ export function normalizeBundleMcpServerConfig(
if (args) {
next.args = args;
}
const env = normalizeStringRecord(server.env);
const env = normalizeMcpStringRecord(server.env);
if (env) {
next.env = env;
}
+8 -8
View File
@@ -11,7 +11,7 @@ import {
resolveExpiresAtMsFromDurationMs,
} from "@openclaw/normalization-core/number-coercion";
import { resolveOsHomeRelativePath } from "../infra/home-dir.js";
import { loadJsonFile } from "../infra/json-file.js";
import { loadJsonFileThroughSymlink } from "../infra/json-file.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import type { OAuthProvider } from "./auth-profiles/types.js";
@@ -415,7 +415,7 @@ function readPortalCliOauthCredentials<TProvider extends string>(
credPath: string,
provider: TProvider,
): { type: "oauth"; provider: TProvider; access: string; refresh: string; expires: number } | null {
const raw = loadJsonFile(credPath);
const raw = loadJsonFileThroughSymlink(credPath);
if (!raw || typeof raw !== "object") {
return null;
}
@@ -430,7 +430,7 @@ function readMiniMaxCliCredentials(options?: { homeDir?: string }): MiniMaxCliCr
function readGeminiCliCredentials(options?: { homeDir?: string }): GeminiCliCredential | null {
const credPath = resolveGeminiCliCredentialsPath(options?.homeDir);
const raw = loadJsonFile(credPath);
const raw = loadJsonFileThroughSymlink(credPath);
if (!raw || typeof raw !== "object") {
return null;
}
@@ -477,7 +477,7 @@ function readClaudeCliKeychainCredentials(
}
function readClaudeCliUserApiKeyHelperCredential(homeDir?: string): ClaudeCliCredential | null {
const raw = loadJsonFile(resolveClaudeCliUserSettingsPath(homeDir));
const raw = loadJsonFileThroughSymlink(resolveClaudeCliUserSettingsPath(homeDir));
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
return null;
}
@@ -497,7 +497,7 @@ function readClaudeCliUserApiKeyHelperCredential(homeDir?: string): ClaudeCliCre
// later account switch could mislabel another credential's quota.
function readClaudeCliAccountEmail(homeDir?: string): string | undefined {
const baseDir = resolveOsHomeRelativePath(homeDir ?? "~");
const raw = loadJsonFile(path.join(baseDir, ".claude.json"));
const raw = loadJsonFileThroughSymlink(path.join(baseDir, ".claude.json"));
if (!raw || typeof raw !== "object") {
return undefined;
}
@@ -547,7 +547,7 @@ function readClaudeCliCredentials(options?: {
}
const credPath = resolveClaudeCliCredentialsPath(options?.homeDir);
const raw = loadJsonFile(credPath);
const raw = loadJsonFileThroughSymlink(credPath);
if (!raw || typeof raw !== "object") {
return null;
}
@@ -624,7 +624,7 @@ export function readCodexCliActiveApiKey(options?: {
const candidates: CodexCliApiKeyCredential[] = [];
const authPath = path.join(codexHome, CODEX_CLI_AUTH_FILENAME);
const raw = loadJsonFile(authPath);
const raw = loadJsonFileThroughSymlink(authPath);
if (raw && typeof raw === "object") {
const fileCredential = parseCodexApiKeyCredential(raw as Record<string, unknown>);
if (fileCredential) {
@@ -684,7 +684,7 @@ function readCodexCliCredentials(options?: {
}
const authPath = path.join(resolveCodexHomePath(options?.codexHome), CODEX_CLI_AUTH_FILENAME);
const raw = loadJsonFile(authPath);
const raw = loadJsonFileThroughSymlink(authPath);
if (!raw || typeof raw !== "object") {
return null;
}
+2 -2
View File
@@ -4,7 +4,7 @@
import { setReplyPayloadMetadata, type ReplyPayload } from "../auto-reply/reply-payload.js";
import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import { resolveStorePath } from "../config/sessions/paths.js";
import { patchSessionEntry } from "../config/sessions/session-accessor.js";
import { patchSessionEntryCore } from "../config/sessions/session-accessor.js";
import { appendExactAssistantMessageToSessionTranscript } from "../config/sessions/transcript.js";
import { buildGenericCliContextEngineHostSupport } from "../context-engine/host-compat.js";
import {
@@ -1108,7 +1108,7 @@ export async function runPreparedCliAgent(
agentId,
}),
};
const persistedEntry = await patchSessionEntry(
const persistedEntry = await patchSessionEntryCore(
sessionTarget,
(entry, patchContext) => {
if (patchContext.existingEntry && entry.sessionId !== sessionTarget.sessionId) {
+2 -2
View File
@@ -8,7 +8,7 @@ import {
decodeHeaderEnvPlaceholder,
isRecord,
normalizeBundleMcpServerConfig,
normalizeStringRecord,
normalizeMcpStringRecord,
} from "../bundle-mcp-adapter.js";
import { withOpenClawMcpCaptureHeader, writeTemporaryBundleMcpJson } from "./bundle-mcp-runtime.js";
@@ -81,7 +81,7 @@ function normalizeGeminiServerConfig(
deniedTools: readonly string[] | undefined,
): Record<string, unknown> {
const next = normalizeBundleMcpServerConfig(server, GEMINI_MCP_SERVER_FIELDS);
const headers = normalizeStringRecord(server.headers);
const headers = normalizeMcpStringRecord(server.headers);
if (headers) {
next.headers = Object.fromEntries(
Object.entries(headers).map(([name, value]) => [
+5 -5
View File
@@ -114,7 +114,7 @@ import { collectRuntimeChannelCapabilities } from "../runtime-capabilities.js";
import { ensureSandboxWorkspaceForSession } from "../sandbox.js";
import { buildSystemPromptReport } from "../system-prompt-report.js";
import { appendModelIdentitySystemPrompt, buildModelIdentityPromptLine } from "../system-prompt.js";
import { expandToolGroups, normalizeToolName } from "../tool-policy.js";
import { expandToolGroups, normalizeToolPolicyName } from "../tool-policy.js";
import { redactRunIdentifier, resolveRunWorkspaceDir } from "../workspace-run.js";
import {
DEFAULT_BOOTSTRAP_FILENAME,
@@ -479,13 +479,13 @@ export async function prepareCliRunContext(
`CLI backend ${backendResolved.id} received conflicting runtime tool policies`,
);
}
if (params.toolsAllow.some((toolName) => normalizeToolName(toolName) === "*")) {
if (params.toolsAllow.some((toolName) => normalizeToolPolicyName(toolName) === "*")) {
params = { ...params, toolsAllow: undefined };
} else {
runtimeToolsAllowPolicy = [...params.toolsAllow];
const fallbackOpenClawTools = uniqueStrings(
expandToolGroups(params.toolsAllow)
.map((toolName) => normalizeToolName(toolName))
.map((toolName) => normalizeToolPolicyName(toolName))
.filter(Boolean),
);
if (
@@ -795,7 +795,7 @@ export async function prepareCliRunContext(
);
const promptBuildRestrictsTools =
promptBuildToolsAllow !== undefined &&
!promptBuildToolsAllow.some((toolName) => normalizeToolName(toolName) === "*");
!promptBuildToolsAllow.some((toolName) => normalizeToolPolicyName(toolName) === "*");
const isClaudeCli = isClaudeCliBackendId(params.provider);
const requestedContextModelId = isClaudeCli ? resolveClaudeCliContextModelId(modelId) : modelId;
const normalizedContextModelId = isClaudeCli
@@ -1055,7 +1055,7 @@ export async function prepareCliRunContext(
: hookFilteredProjectedTools;
const promptTools = bundleMcpEnabled ? projectedTools : [];
const messageToolAvailable = promptTools.some(
(tool) => normalizeToolName(tool.name) === "message",
(tool) => normalizeToolPolicyName(tool.name) === "message",
);
const resultContentSourceByToolName = new Map(
promptTools.flatMap((tool) =>
+2 -2
View File
@@ -1,5 +1,5 @@
import type { CliBackendToolAvailability } from "../../plugins/cli-backend.types.js";
import { normalizeToolName } from "../tool-policy.js";
import { normalizeToolPolicyName } from "../tool-policy.js";
/** Transport prefix CLI harnesses use for loopback OpenClaw MCP tool names. */
const OPENCLAW_MCP_TOOL_PREFIX = "mcp__openclaw__";
@@ -31,7 +31,7 @@ export function resolveCliRuntimeToolsAllow(
if (toolsAllow === undefined) {
return undefined;
}
return toolsAllow.some((toolName) => normalizeToolName(toolName) === "*")
return toolsAllow.some((toolName) => normalizeToolPolicyName(toolName) === "*")
? undefined
: toolsAllow;
}
+4 -2
View File
@@ -3,7 +3,7 @@
* exec-compatible before-tool-call surface.
*/
import { isPlainObject } from "../utils.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import type { AnyAgentTool } from "./tools/common.js";
/** Model-visible Code Mode exec tool name. */
@@ -44,7 +44,9 @@ export function isCodeModeControlTool(tool: object): boolean {
}
function isCodeModeExecTool(tool: AnyAgentTool): boolean {
return isCodeModeControlTool(tool) && normalizeToolName(tool.name) === CODE_MODE_EXEC_TOOL_NAME;
return (
isCodeModeControlTool(tool) && normalizeToolPolicyName(tool.name) === CODE_MODE_EXEC_TOOL_NAME
);
}
function resolveCodeModeExecToolInputKind(params: unknown): CodeModeExecToolInputKind | undefined {
+18 -15
View File
@@ -4,7 +4,10 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { buildCodexMcpServersConfig, loadCodexBundleMcpThreadConfig } from "./codex-mcp-config.js";
import {
buildCodexMcpServersConfig,
loadCodexBundleMcpThreadConfigCore,
} from "./codex-mcp-config.js";
import { testing as resolverTesting } from "./mcp-connection-resolver.js";
const mocks = vi.hoisted(() => ({
@@ -94,11 +97,11 @@ describe("buildCodexMcpServersConfig", () => {
});
});
describe("loadCodexBundleMcpThreadConfig", () => {
describe("loadCodexBundleMcpThreadConfigCore", () => {
it("forwards a prepared manifest registry to bundle loading", () => {
const manifestRegistry = { plugins: [] };
loadCodexBundleMcpThreadConfig({ workspaceDir: "/workspace", manifestRegistry });
loadCodexBundleMcpThreadConfigCore({ workspaceDir: "/workspace", manifestRegistry });
expect(mocks.loadCalls).toEqual([
expect.objectContaining({ workspaceDir: "/workspace", manifestRegistry }),
@@ -128,7 +131,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
},
});
const loaded = loadCodexBundleMcpThreadConfig({ workspaceDir: "/workspace" });
const loaded = loadCodexBundleMcpThreadConfigCore({ workspaceDir: "/workspace" });
expect((await fs.stat(dataDir)).isDirectory()).toBe(true);
expect(loaded.configPatch?.mcp_servers.weather).toMatchObject({ command: "node" });
@@ -154,7 +157,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
diagnostics: [],
};
const loaded = loadCodexBundleMcpThreadConfig({
const loaded = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {
plugins: {
@@ -192,7 +195,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
diagnostics: [],
};
const loaded = loadCodexBundleMcpThreadConfig({
const loaded = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {},
toolOverrides: {
@@ -232,10 +235,10 @@ describe("loadCodexBundleMcpThreadConfig", () => {
};
expect(
loadCodexBundleMcpThreadConfig({ workspaceDir: "/workspace", cfg }).configPatch,
loadCodexBundleMcpThreadConfigCore({ workspaceDir: "/workspace", cfg }).configPatch,
).toBeUndefined();
expect(
loadCodexBundleMcpThreadConfig({
loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg,
toolOverrides: { mcpServers: { docs: true } },
@@ -250,7 +253,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
it("leaves user mcp.servers to the Codex user MCP projection path", () => {
// User MCP config is projected elsewhere; this loader only injects bundled
// MCP servers so the same server does not appear twice in Codex.
const loaded = loadCodexBundleMcpThreadConfig({
const loaded = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {
mcp: {
@@ -290,7 +293,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
{ toolsEnabled: true, toolsAllow: [] },
{ toolsEnabled: true, toolsAllow: ["memory_search"] },
]) {
const loaded = loadCodexBundleMcpThreadConfig({
const loaded = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg,
...params,
@@ -304,7 +307,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
});
it("omits the config patch when no MCP servers are configured", () => {
const loaded = loadCodexBundleMcpThreadConfig({
const loaded = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {},
toolsEnabled: true,
@@ -338,7 +341,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
diagnostics: [],
};
const loaded = loadCodexBundleMcpThreadConfig({
const loaded = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {},
toolsEnabled: true,
@@ -355,7 +358,7 @@ describe("loadCodexBundleMcpThreadConfig", () => {
},
diagnostics: [],
};
const withoutScopedConfig = loadCodexBundleMcpThreadConfig({
const withoutScopedConfig = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {},
toolsEnabled: true,
@@ -388,12 +391,12 @@ describe("loadCodexBundleMcpThreadConfig", () => {
diagnostics: [],
};
const a = loadCodexBundleMcpThreadConfig({
const a = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {},
toolsEnabled: true,
});
const b = loadCodexBundleMcpThreadConfig({
const b = loadCodexBundleMcpThreadConfigCore({
workspaceDir: "/workspace",
cfg: {},
toolsEnabled: true,
+3 -3
View File
@@ -16,7 +16,7 @@ import { isRecord } from "../utils.js";
import {
decodeHeaderEnvPlaceholder,
normalizeBundleMcpServerConfig,
normalizeStringRecord,
normalizeMcpStringRecord,
} from "./bundle-mcp-adapter.js";
import { prepareOwnedBundleMcpDataDirs } from "./bundle-mcp-config.js";
import type {
@@ -106,7 +106,7 @@ export function normalizeCodexMcpServerConfig(
if (defaultToolsApprovalMode) {
next.default_tools_approval_mode = defaultToolsApprovalMode;
}
const httpHeaders = normalizeStringRecord(server.headers);
const httpHeaders = normalizeMcpStringRecord(server.headers);
if (httpHeaders) {
const staticHeaders: Record<string, string> = {};
const envHeaders: Record<string, string> = {};
@@ -170,7 +170,7 @@ function fingerprintCodexMcpServersConfig(config: CodexMcpServersConfig): string
}
/** Load bundle MCP config for one Codex app-server thread. */
export function loadCodexBundleMcpThreadConfig(
export function loadCodexBundleMcpThreadConfigCore(
params: LoadCodexBundleMcpThreadConfigParams,
): CodexBundleMcpThreadConfig {
const shouldCreateRuntime = shouldCreateBundleMcpRuntimeForAttempt({
@@ -6,7 +6,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
import { setReplyPayloadMetadata } from "../../auto-reply/reply-payload.js";
import type { SessionEntry } from "../../config/sessions.js";
import {
listSessionEntries,
listSessionEntriesCore,
loadTranscriptEvents,
} from "../../config/sessions/session-accessor.js";
import type { appendExactAssistantMessageToSessionTranscript } from "../../config/sessions/transcript.runtime.js";
@@ -384,7 +384,7 @@ function requireStorePath(): string {
}
function findStoredSessionEntry(sessionKey: string): SessionEntry | undefined {
return listSessionEntries({ storePath: requireStorePath() }).find(
return listSessionEntriesCore({ storePath: requireStorePath() }).find(
(candidate) => candidate.sessionKey === sessionKey,
)?.entry;
}
@@ -12,7 +12,7 @@ import {
import {
appendTranscriptEvent,
appendTranscriptMessage,
listSessionEntries,
listSessionEntriesCore,
loadTranscriptEvents,
replaceSessionEntry,
} from "../../config/sessions/session-accessor.js";
@@ -710,7 +710,7 @@ describe("CLI attempt execution", () => {
function readSessionStore(): Record<string, SessionEntry> {
return Object.fromEntries(
listSessionEntries({ storePath }).map(({ entry, sessionKey }) => [sessionKey, entry]),
listSessionEntriesCore({ storePath }).map(({ entry, sessionKey }) => [sessionKey, entry]),
);
}
@@ -2,7 +2,7 @@
* Shared session persistence and prompt-body helpers for agent attempt
* execution paths.
*/
import { patchSessionEntry } from "../../config/sessions/session-accessor.js";
import { patchSessionEntryCore } from "../../config/sessions/session-accessor.js";
import { mergeSessionSnapshotChanges } from "../../config/sessions/session-snapshot-merge.js";
import type { SessionEntry } from "../../config/sessions/types.js";
import {
@@ -30,7 +30,7 @@ export async function persistAgentSession(
params: PersistSessionEntryParams,
): Promise<SessionEntry | undefined> {
let rejectedMissingEntry = false;
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{ sessionKey: params.sessionKey, storePath: params.storePath },
(_entry, context) => {
const shouldPersistCurrent = params.shouldPersist?.(context.existingEntry);
+2 -2
View File
@@ -7,7 +7,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js";
import {
listSessionEntries,
listSessionEntriesCore,
loadSessionEntry,
replaceSessionEntry,
} from "../../config/sessions/session-accessor.js";
@@ -111,7 +111,7 @@ async function seedSessionStore(
function loadPersistedSessionStore(storePath: string): Record<string, SessionEntry> {
return Object.fromEntries(
listSessionEntries({ storePath }).map(({ sessionKey, entry }) => [sessionKey, entry]),
listSessionEntriesCore({ storePath }).map(({ sessionKey, entry }) => [sessionKey, entry]),
);
}
+7 -7
View File
@@ -7,7 +7,7 @@ import {
setSessionRuntimeModel,
type SessionEntry,
} from "../../config/sessions.js";
import { patchSessionEntry } from "../../config/sessions/session-accessor.js";
import { patchSessionEntryCore } from "../../config/sessions/session-accessor.js";
import { projectSessionSnapshotChanges } from "../../config/sessions/session-snapshot-merge.js";
import { resolveMaintenanceConfigFromInput } from "../../config/sessions/store-maintenance.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
@@ -286,7 +286,7 @@ export async function updateSessionStoreAfterAgentRun(params: {
}
: next;
const maintenanceConfig = resolveMaintenanceConfigFromInput(cfg.session?.maintenance);
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{
storePath,
sessionKey,
@@ -338,7 +338,7 @@ export async function clearCliSessionInStore(params: {
}
let didClear = false;
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{
storePath,
sessionKey,
@@ -385,7 +385,7 @@ export async function consumeCliSessionForkInStore(params: {
if (!entry || binding?.sessionId !== expectedCliSessionId || binding.forkNextResume !== true) {
return undefined;
}
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{ storePath, sessionKey },
(currentEntry) => {
const currentBinding = currentEntry.cliSessionBindings?.[provider];
@@ -422,7 +422,7 @@ export async function restoreCliSessionForkInStore(params: {
if (!entry || binding?.sessionId !== expectedCliSessionId || binding.forkNextResume === true) {
return undefined;
}
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{ storePath, sessionKey },
(currentEntry) => {
const currentBinding = currentEntry.cliSessionBindings?.[provider];
@@ -465,7 +465,7 @@ export async function persistCliSessionForkSuccessorInStore(params: {
if (!entry || successorCliSessionId === expectedCliSessionId) {
return undefined;
}
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{ storePath, sessionKey },
(currentEntry) => {
const currentBinding = currentEntry.cliSessionBindings?.[provider];
@@ -540,7 +540,7 @@ export async function recordCliCompactionInStore(params: {
next.cacheWrite = undefined;
}
const persisted = await patchSessionEntry(
const persisted = await patchSessionEntryCore(
{
storePath,
sessionKey,
@@ -8,7 +8,7 @@ const hoisted = vi.hoisted(() => ({
}));
vi.mock("../../config/sessions/session-accessor.js", () => ({
listSessionEntries: () =>
listSessionEntriesCore: () =>
Object.entries(hoisted.store).map(([sessionKey, entry]) => ({
sessionKey,
entry,
@@ -14,7 +14,7 @@ const hoisted = vi.hoisted(() => ({
}));
vi.mock("../../config/sessions/session-accessor.js", () => ({
listSessionEntries: (scope?: { storePath?: string; clone?: boolean }) =>
listSessionEntriesCore: (scope?: { storePath?: string; clone?: boolean }) =>
hoisted.listSessionEntriesMock(scope),
}));
+2 -2
View File
@@ -25,7 +25,7 @@ import {
resolveSessionResetPolicy,
} from "../../config/sessions/reset-policy.js";
import { resolveChannelResetConfig, resolveSessionResetType } from "../../config/sessions/reset.js";
import { listSessionEntries } from "../../config/sessions/session-accessor.js";
import { listSessionEntriesCore } from "../../config/sessions/session-accessor.js";
import { resolveSessionKey } from "../../config/sessions/session-key.js";
import type { InternalSessionEntry as SessionEntry } from "../../config/sessions/types.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
@@ -112,7 +112,7 @@ function loadCommandSessionStore(params: {
storePath: string;
}): Record<string, SessionEntry> {
return Object.fromEntries(
listSessionEntries({
listSessionEntriesCore({
storePath: params.storePath,
...(params.agentId ? { agentId: params.agentId } : {}),
...(params.clone === false ? { clone: false } : {}),
+2 -2
View File
@@ -1,6 +1,6 @@
import { isCompletionReportInputProvenance } from "../sessions/input-provenance.js";
import { isRuntimeToolAllowed } from "./tool-policy-match.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import { AUTOMATIONS_TOOL_NAME } from "./tools/automations-tool-name.js";
import type { AnyAgentTool } from "./tools/common.js";
import { ToolAuthorizationError } from "./tools/common.js";
@@ -96,7 +96,7 @@ export function applyDelegationCapability(
return tools;
}
return tools.flatMap((tool) => {
const name = normalizeToolName(tool.name);
const name = normalizeToolPolicyName(tool.name);
if (NEW_DELEGATION_TOOL_NAMES.has(name)) {
return [];
}
@@ -11,7 +11,7 @@ import {
isMessagingToolDeliveryAction,
} from "./embedded-agent-messaging.js";
import { isToolResultError } from "./embedded-agent-subscribe.tools.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
const MESSAGE_TOOL_NAME = "message";
const SESSIONS_SEND_TOOL_NAME = "sessions_send";
@@ -535,7 +535,7 @@ export function isDeliveredMessagingToolResult(params: {
if (params.isError || isToolResultError(params.result) || isToolResultError(params.hookResult)) {
return false;
}
const normalizedToolName = normalizeToolName(params.toolName ?? MESSAGE_TOOL_NAME);
const normalizedToolName = normalizeToolPolicyName(params.toolName ?? MESSAGE_TOOL_NAME);
const mutationHasBareOk =
isMessagingToolDeliveryAction(normalizedToolName, args) &&
action !== "broadcast" &&
@@ -590,7 +590,7 @@ export function isDeliveredMessageToolOnlySourceReplyResult(params: {
if (params.sourceReplyDeliveryMode !== "message_tool_only" && !confirmedCurrentSourceRoute) {
return false;
}
if (normalizeToolName(params.toolName) !== MESSAGE_TOOL_NAME) {
if (normalizeToolPolicyName(params.toolName) !== MESSAGE_TOOL_NAME) {
return false;
}
const args = asOptionalRecord(params.args) ?? {};
@@ -16,7 +16,7 @@ import { onAgentEvent } from "../../infra/agent-events.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { resolvePreparedRunAdmission } from "../admitted-run-context.js";
import { stripOpenClawMcpToolPrefix } from "../cli-runner/tool-policy.js";
import { normalizeToolName } from "../tool-policy.js";
import { normalizeToolPolicyName } from "../tool-policy.js";
import { isToolResultError } from "../tool-result-error.js";
import { resolveEmbeddedCliBackendDispatchEligibility } from "./cli-backend-dispatch-eligibility.js";
import { createCliDispatchTranscriptRecorder } from "./cli-backend-dispatch-transcript.js";
@@ -84,7 +84,7 @@ function resolveDispatchableToolsAllow(params: RunEmbeddedAgentParams): string[]
if (!params.toolsAllow || params.toolsAllow.length === 0) {
return undefined;
}
const names = params.toolsAllow.map((name) => normalizeToolName(name));
const names = params.toolsAllow.map((name) => normalizeToolPolicyName(name));
if (names.some((name) => !name || name === "*" || name.includes("*"))) {
return undefined;
}
@@ -159,7 +159,7 @@ async function runEmbeddedAgentViaCliBackend(
if (!rawName) {
return;
}
const toolName = normalizeToolName(stripOpenClawMcpToolPrefix(rawName));
const toolName = normalizeToolPolicyName(stripOpenClawMcpToolPrefix(rawName));
const toolCallId = typeof evt.data.toolCallId === "string" ? evt.data.toolCallId : undefined;
if (phase === "start") {
transcript.noteToolEvent({
@@ -4,7 +4,7 @@ import {
parseSqliteSessionFileMarker,
} from "../../config/sessions/legacy-sqlite-marker.js";
import {
listSessionEntries,
listSessionEntriesCore,
loadSessionEntry,
type SessionTranscriptRuntimeTarget,
} from "../../config/sessions/session-accessor.js";
@@ -85,7 +85,7 @@ export async function resolveContextEngineCompactionSuccessor(params: {
})
: undefined;
const markerMatches = marker
? listSessionEntries({
? listSessionEntriesCore({
agentId: marker.agentId,
storePath: marker.storePath,
}).filter(({ entry }) => entry.sessionId === marker.sessionId)
@@ -4,14 +4,14 @@ import { buildContextEngineCompactionSessionTarget } from "./session-bootstrap.j
import { createEmbeddedRunSessionPromptState } from "./session-prompt-state.js";
const sessionAccessorMocks = vi.hoisted(() => ({
listSessionEntries: vi.fn(() => []),
listSessionEntriesCore: vi.fn(() => []),
loadSessionEntry: vi.fn(),
}));
vi.mock("../../../config/sessions/session-accessor.js", () => sessionAccessorMocks);
beforeEach(() => {
sessionAccessorMocks.listSessionEntries.mockReset().mockReturnValue([]);
sessionAccessorMocks.listSessionEntriesCore.mockReset().mockReturnValue([]);
sessionAccessorMocks.loadSessionEntry.mockReset();
});
@@ -178,7 +178,7 @@ describe("applyEmbeddedAttemptSessionIdentity", () => {
sessionId: "session-before",
updatedAt: 1,
});
sessionAccessorMocks.listSessionEntries.mockReturnValue([
sessionAccessorMocks.listSessionEntriesCore.mockReturnValue([
{
sessionKey: "agent:main:other",
entry: { sessionId: "session-after", updatedAt: 2 },
@@ -34,7 +34,7 @@ import {
appendModelIdentitySystemPrompt,
buildModelIdentityPromptLine,
} from "../../system-prompt.js";
import { normalizeToolName } from "../../tool-policy.js";
import { normalizeToolPolicyName } from "../../tool-policy.js";
import { log } from "../logger.js";
import {
beginPromptCacheObservation,
@@ -170,7 +170,7 @@ export async function prepareEmbeddedAttemptPromptAssembly(input: {
bootstrapContextRunKind: attempt.bootstrapContextRunKind,
});
const promptCacheToolNames = input.applyPromptBuildToolsAllow(hookResult?.toolsAllow);
const promptCacheToolNameSet = new Set(promptCacheToolNames.map(normalizeToolName));
const promptCacheToolNameSet = new Set(promptCacheToolNames.map(normalizeToolPolicyName));
const promptBeforeResolvedToolFinalization = effectivePrompt;
effectivePrompt = applyResolvedToolPromptFinalizer({
prompt: effectivePrompt,
@@ -182,7 +182,7 @@ export async function prepareEmbeddedAttemptPromptAssembly(input: {
? promptBeforeResolvedToolFinalization
: attempt.transcriptPrompt;
const promptCacheTools = input.cache.tools.filter((tool) =>
promptCacheToolNameSet.has(normalizeToolName(tool.name)),
promptCacheToolNameSet.has(normalizeToolPolicyName(tool.name)),
);
const promptBeforePromptBuildHooks = effectivePrompt;
const promptBuildPrependContext = hookResult?.prependContext;
@@ -26,7 +26,7 @@ import {
} from "../../code-mode-control-tools.js";
import type { AgentMessage } from "../../runtime/index.js";
import type { AgentSession } from "../../sessions/index.js";
import { normalizeToolName } from "../../tool-policy.js";
import { normalizeToolPolicyName } from "../../tool-policy.js";
import { TOOL_SEARCH_CONTROL_TOOL_NAMES } from "../../tool-search-types.js";
import {
restrictToolSearchCatalog,
@@ -63,7 +63,7 @@ export function applyResolvedToolPromptFinalizer(params: {
return params.finalize({
prompt: params.prompt,
messageToolAvailable: params.activeToolNames.some(
(toolName) => normalizeToolName(toolName) === "message",
(toolName) => normalizeToolPolicyName(toolName) === "message",
),
});
}
@@ -136,17 +136,17 @@ export function applyPromptBuildToolsAllow<
applyToolsAllow(
params.baseline.activeToolNames.map((name) => ({ name })),
toolsAllow,
).map((tool) => normalizeToolName(tool.name)),
).map((tool) => normalizeToolPolicyName(tool.name)),
);
for (const tool of [...allowedEffectiveTools, ...allowedUncompactedTools, ...allowedTools]) {
allowedActiveNames.add(normalizeToolName(tool.name));
allowedActiveNames.add(normalizeToolPolicyName(tool.name));
}
const catalogControlNames = params.codeModeControlsEnabled
? new Set([CODE_MODE_EXEC_TOOL_NAME, CODE_MODE_WAIT_TOOL_NAME])
: TOOL_SEARCH_CONTROL_TOOL_NAMES;
const keepVisibleTool = (tool: NamedTool) => {
const normalized = normalizeToolName(tool.name);
const normalized = normalizeToolPolicyName(tool.name);
return (
allowedActiveNames.has(normalized) ||
(catalogToolCount > 0 && catalogControlNames.has(normalized))
@@ -3,7 +3,10 @@ import {
formatSqliteSessionFileMarker,
parseSqliteSessionFileMarker,
} from "../../../config/sessions/legacy-sqlite-marker.js";
import { listSessionEntries, loadSessionEntry } from "../../../config/sessions/session-accessor.js";
import {
listSessionEntriesCore,
loadSessionEntry,
} from "../../../config/sessions/session-accessor.js";
import { resolveAgentIdFromSessionKey } from "../../../routing/session-key.js";
import { resolvePreferredSessionKeyForSessionIdMatches } from "../../../sessions/session-id-resolution.js";
import type { createEmbeddedRunSessionPromptState } from "./session-prompt-state.js";
@@ -36,7 +39,7 @@ export function applyEmbeddedAttemptSessionIdentity(params: {
storePath: marker.storePath,
})
: undefined;
const markerMatches = listSessionEntries({
const markerMatches = listSessionEntriesCore({
agentId: marker.agentId,
storePath: marker.storePath,
}).filter(({ entry }) => entry.sessionId === marker.sessionId);
@@ -14,7 +14,7 @@ import {
expandPolicyWithPluginGroups,
expandToolGroups,
normalizeToolList,
normalizeToolName,
normalizeToolPolicyName,
readToolAllowlistIntersection,
} from "../../tool-policy.js";
@@ -50,7 +50,7 @@ function isPluginGroupAllowlistName(normalized: string): boolean {
}
function hasWildcardToolAllowlist(toolsAllow: string[]): boolean {
return toolsAllow.some((entry) => normalizeToolName(entry) === "*");
return toolsAllow.some((entry) => normalizeToolPolicyName(entry) === "*");
}
/**
@@ -104,8 +104,8 @@ export function mergeForcedEmbeddedAttemptToolsAllow(
if (required.length === 0) {
return toolsAllow;
}
const normalized = new Set(toolsAllow.map((entry) => normalizeToolName(entry)));
const missing = required.filter((name) => !normalized.has(normalizeToolName(name)));
const normalized = new Set(toolsAllow.map((entry) => normalizeToolPolicyName(entry)));
const missing = required.filter((name) => !normalized.has(normalizeToolPolicyName(name)));
if (missing.length === 0) {
return toolsAllow;
}
@@ -232,7 +232,7 @@ function shouldCreateBundleRuntimeForAttempt(
if (hasWildcardToolAllowlist(params.toolsAllow)) {
return true;
}
return params.toolsAllow.some((toolName) => matchesAllowlist(normalizeToolName(toolName)));
return params.toolsAllow.some((toolName) => matchesAllowlist(normalizeToolPolicyName(toolName)));
}
/**
@@ -3,7 +3,7 @@
*/
import { getPluginToolMeta } from "../../../plugins/tools.js";
import { isToolAllowedByPolicyName } from "../../tool-policy-match.js";
import { normalizeToolName } from "../../tool-policy.js";
import { normalizeToolPolicyName } from "../../tool-policy.js";
import {
collectUniqueCatalogToolNames,
TOOL_CALL_RAW_TOOL_NAME,
@@ -108,14 +108,16 @@ export function buildToolSearchRunPlan(params: {
}
const explicitControlAllowlistNames = new Set(
params.explicitAllowlistSources.flatMap((source) =>
source.entries.map((entry) => normalizeToolName(entry)),
source.entries.map((entry) => normalizeToolPolicyName(entry)),
),
);
const autoAddedControlNames = new Set(
(params.controlsEnabled
? (params.controlNames ?? TOOL_SEARCH_CONTROL_ALLOWLIST_NAMES)
: []
).filter((controlName) => !explicitControlAllowlistNames.has(normalizeToolName(controlName))),
).filter(
(controlName) => !explicitControlAllowlistNames.has(normalizeToolPolicyName(controlName)),
),
);
const explicitlyAllowedClientToolNames = collectExplicitlyAllowedClientToolNames({
clientTools: params.clientTools,
@@ -33,7 +33,10 @@ import {
sanitizeToolCallIdsForCloudCodeAssist,
type ToolCallIdMode,
} from "../../tool-call-id.js";
import { couldNormalizeToolNamePrefixToAllowedTool, normalizeToolName } from "../../tool-policy.js";
import {
couldNormalizeToolNamePrefixToAllowedTool,
normalizeToolPolicyName,
} from "../../tool-policy.js";
import { shouldAllowProviderOwnedThinkingReplay } from "../../transcript-policy.js";
import type { TranscriptPolicy } from "../../transcript-policy.js";
import { isRunnerToolCallBlockType } from "./attempt-tool-call-block-type.js";
@@ -79,7 +82,7 @@ function resolveExactAllowedToolName(
if (allowedToolNames.has(rawName)) {
return rawName;
}
const normalized = normalizeToolName(rawName);
const normalized = normalizeToolPolicyName(rawName);
if (allowedToolNames.has(normalized)) {
return normalized;
}
@@ -107,7 +110,7 @@ function buildStructuredToolNameCandidates(rawName: string): string[] {
};
addCandidate(trimmed);
addCandidate(normalizeToolName(trimmed));
addCandidate(normalizeToolPolicyName(trimmed));
const structuredSeeds = [trimmed];
const xmlFragmentOffset = ['"', "'", "<"]
@@ -120,21 +123,21 @@ function buildStructuredToolNameCandidates(rawName: string): string[] {
if (xmlFragmentOffset !== undefined) {
const prefix = trimmed.slice(0, xmlFragmentOffset);
addCandidate(prefix);
addCandidate(normalizeToolName(prefix));
addCandidate(normalizeToolPolicyName(prefix));
structuredSeeds.push(prefix);
}
for (const seed of structuredSeeds) {
const normalizedDelimiter = seed.replace(/\//g, ".");
addCandidate(normalizedDelimiter);
addCandidate(normalizeToolName(normalizedDelimiter));
addCandidate(normalizeToolPolicyName(normalizedDelimiter));
const segments = normalizeStringEntries(normalizedDelimiter.split("."));
if (segments.length > 1) {
for (let index = 1; index < segments.length; index += 1) {
const suffix = segments.slice(index).join(".");
addCandidate(suffix);
addCandidate(normalizeToolName(suffix));
addCandidate(normalizeToolPolicyName(suffix));
}
}
}
@@ -769,7 +772,7 @@ function classifyToolCallMessage(
sawAllowedToolCall = true;
continue;
}
const normalizedUnknownToolName = normalizeToolName(rawName);
const normalizedUnknownToolName = normalizeToolPolicyName(rawName);
if (!unknownToolName) {
unknownToolName = normalizedUnknownToolName;
continue;
@@ -4,7 +4,7 @@ import { sanitizeForLog } from "../../../../packages/terminal-core/src/ansi.js";
import { resolveStorePath, SESSION_TOTAL_TOKENS_VERSION } from "../../../config/sessions.js";
import { parseSqliteSessionFileMarker } from "../../../config/sessions/legacy-sqlite-marker.js";
import {
listSessionEntries,
listSessionEntriesCore,
loadSessionEntry,
updateSessionEntry,
} from "../../../config/sessions/session-accessor.js";
@@ -63,7 +63,7 @@ export function buildContextEngineCompactionSessionTarget(params: {
})
: undefined;
const markerMatches = marker
? listSessionEntries({
? listSessionEntriesCore({
agentId: marker.agentId,
storePath: marker.storePath,
}).filter(({ entry }) => entry.sessionId === marker.sessionId)
@@ -95,7 +95,7 @@ import {
summarizeToolValidationError,
} from "./tool-error-summary.js";
import { resolveFileMutationToolName } from "./tool-mutation-names.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import { cancelAskUserPromptDelivery } from "./tools/ask-user-tool.js";
import { isAutomationsToolName } from "./tools/automations-tool-name.js";
@@ -105,7 +105,7 @@ export async function handleToolExecutionEnd(
evt: Extract<AgentEvent, { type: "tool_execution_end" }>,
) {
const rawToolName = evt.toolName;
const toolName = normalizeToolName(rawToolName);
const toolName = normalizeToolPolicyName(rawToolName);
const hideFromChannelProgress = evt.hideFromChannelProgress === true;
const toolCallId = evt.toolCallId;
ctx.state.liveEditDiffStateById.delete(toolCallId);
@@ -26,7 +26,7 @@ import {
truncateLiveExecOutput,
} from "./embedded-agent-subscribe.tools.js";
import type { AgentEvent } from "./runtime/index.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
type ChannelToolProgress = {
text: string;
@@ -69,7 +69,7 @@ export function handleToolExecutionUpdate(
hideFromChannelProgress?: boolean;
},
) {
const toolName = normalizeToolName(evt.toolName);
const toolName = normalizeToolPolicyName(evt.toolName);
const toolCallId = evt.toolCallId;
const hideFromChannelProgress = evt.hideFromChannelProgress === true;
const partial = evt.partialResult;
@@ -34,7 +34,7 @@ import type { AgentEvent } from "./runtime/index.js";
import { inferToolMetaFromArgsCore, isCommandBearingToolCall } from "./tool-display.js";
import { resolveFileMutationToolName } from "./tool-mutation-names.js";
import { buildToolMutationState } from "./tool-mutation.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import {
cancelAskUserPromptDelivery,
normalizeAskUserParams,
@@ -322,7 +322,7 @@ export function handleToolExecutionStart(
hideFromChannelProgress?: boolean;
},
): void | Promise<void> {
const startToolName = normalizeToolName(evt.toolName);
const startToolName = normalizeToolPolicyName(evt.toolName);
ctx.state.liveEditDiffStateById.delete(evt.toolCallId);
const askUserPromptReservation =
startToolName === "ask_user" && ctx.params.onToolResult
@@ -358,7 +358,7 @@ export function handleToolExecutionStart(
const continueToolExecutionStart = (): void | Promise<void> => {
const rawToolName = evt.toolName;
const toolName = normalizeToolName(rawToolName);
const toolName = normalizeToolPolicyName(rawToolName);
const hideFromChannelProgress = evt.hideFromChannelProgress === true;
const toolCallId = evt.toolCallId;
const args = evt.args;
@@ -7,7 +7,7 @@ import { extractTextFromChatContent } from "../shared/chat-content.js";
import { detectAssistantTranscriptRoleHeaderText } from "../shared/text/assistant-transcript-role-headers.js";
import { detectToolCallShapedText } from "../shared/text/tool-call-shaped-text.js";
import type { EmbeddedAgentSubscribeContext } from "./embedded-agent-subscribe.handlers.types.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
// Detect provider/model bugs where a reply serializes a tool call as plain
// assistant text instead of emitting a structured invocation block.
@@ -51,9 +51,9 @@ function isRegisteredToolName(
if (!toolName || !registeredToolNames) {
return undefined;
}
const normalized = normalizeToolName(toolName);
const normalized = normalizeToolPolicyName(toolName);
for (const registeredToolName of registeredToolNames) {
if (normalizeToolName(registeredToolName) === normalized) {
if (normalizeToolPolicyName(registeredToolName) === normalized) {
return true;
}
}
+3 -3
View File
@@ -28,7 +28,7 @@ import type {
MessagingToolSend,
MessagingToolSourceReplyPayload,
} from "./embedded-agent-messaging.types.js";
import { normalizeToolName } from "./tool-policy.js";
import { normalizeToolPolicyName } from "./tool-policy.js";
import {
isToolResultError,
readToolResultDetails,
@@ -636,7 +636,7 @@ function isCoreToolResultMediaTrustedName(toolName?: string): boolean {
if (!toolName) {
return false;
}
return TRUSTED_TOOL_RESULT_MEDIA.has(normalizeToolName(toolName));
return TRUSTED_TOOL_RESULT_MEDIA.has(normalizeToolPolicyName(toolName));
}
function isExternalToolResult(result: unknown): boolean {
@@ -676,7 +676,7 @@ function isTrustedOwnedTtsLocalMedia(
if (
!toolName ||
!isToolResultMediaTrusted(toolName, result, trustedLocalMediaToolNames) ||
normalizeToolName(toolName) !== "tts"
normalizeToolPolicyName(toolName) !== "tts"
) {
return false;
}
@@ -1,5 +1,5 @@
import { stableStringify } from "@openclaw/normalization-core";
import { normalizeToolName } from "../tool-policy.js";
import { normalizeToolPolicyName } from "../tool-policy.js";
import { codexNativeHookRelayResponseCodec } from "./native-hook-relay-response-codec.js";
import type {
JsonValue,
@@ -186,6 +186,6 @@ export function readNativeHookRelayApprovalMode(rawPayload: JsonValue): "report"
}
export function normalizeNativeHookToolName(toolName: string | undefined): string {
const normalized = normalizeToolName(toolName ?? "tool");
const normalized = normalizeToolPolicyName(toolName ?? "tool");
return CODEX_NATIVE_HOOK_TOOL_NAME_ALIASES[normalized] ?? normalized;
}
+6 -4
View File
@@ -33,7 +33,7 @@ import { resolveSandboxRuntimeStatus } from "../sandbox/runtime-status.js";
import {
expandToolGroups,
mergeAlsoAllowPolicy,
normalizeToolName,
normalizeToolPolicyName,
toolPolicyRestrictsTools,
} from "../tool-policy.js";
import type { SystemAgentToolOptions } from "../tools/system-agent-tool.js";
@@ -681,7 +681,7 @@ async function runAgentHarnessOperation<T>(
}
function isSystemAgentOnlyAllowlist(toolsAllow: readonly string[] | undefined): boolean {
return toolsAllow?.length === 1 && normalizeToolName(toolsAllow[0] ?? "") === "openclaw";
return toolsAllow?.length === 1 && normalizeToolPolicyName(toolsAllow[0] ?? "") === "openclaw";
}
function withoutHarnessSetupAuthority(
@@ -816,7 +816,7 @@ function applyPluginHarnessDenyAllToolPolicy(
if (
isHostScopedAgentToolActive("openclaw") &&
params.toolsAllow?.length === 1 &&
normalizeToolName(params.toolsAllow[0] ?? "") === "openclaw"
normalizeToolPolicyName(params.toolsAllow[0] ?? "") === "openclaw"
) {
return params;
}
@@ -983,7 +983,9 @@ function appendPluginHarnessToolPolicyPrompt(existing: string | undefined, promp
}
function policyDeniesAllTools(policy?: { deny?: string[] }): boolean {
return expandToolGroups(policy?.deny ?? []).some((entry) => normalizeToolName(entry) === "*");
return expandToolGroups(policy?.deny ?? []).some(
(entry) => normalizeToolPolicyName(entry) === "*",
);
}
function listHarnessCandidates(harnesses: AgentHarness[]): AgentHarnessSelectionCandidate[] {
+2 -2
View File
@@ -3,7 +3,7 @@
*/
import { uniqueStrings } from "@openclaw/normalization-core/string-normalization";
import { isToolAllowedByPolicyName } from "./tool-policy-match.js";
import { normalizeToolName } from "./tool-policy-shared.js";
import { normalizeToolPolicyName } from "./tool-policy-shared.js";
const ACP_UNSUPPORTED_INHERITED_TOOL_DENY = [
"apply_patch",
@@ -37,7 +37,7 @@ export function normalizeInheritedToolDenylist(value: unknown): string[] {
}
return uniqueStrings(
value.flatMap((entry) => {
const normalized = typeof entry === "string" ? normalizeToolName(entry) : "";
const normalized = typeof entry === "string" ? normalizeToolPolicyName(entry) : "";
return normalized ? [normalized] : [];
}),
);
+3 -3
View File
@@ -3,7 +3,7 @@ import path from "node:path";
import { describe, expect, it } from "vitest";
import {
appendTranscriptMessage,
listSessionEntries,
listSessionEntriesCore,
loadExactSessionEntry,
loadTranscriptEvents,
persistSessionResetLifecycle,
@@ -114,7 +114,7 @@ describe("internal session effects", () => {
delivery: { kind: "internal" },
createdAt: expect.any(Number),
});
expect(listSessionEntries({ agentId: "main", storePath })).toEqual([]);
expect(listSessionEntriesCore({ agentId: "main", storePath })).toEqual([]);
await expect(loadTranscriptEvents(target)).resolves.toEqual([
expect.objectContaining({ id: target.sessionId, type: "session" }),
]);
@@ -173,7 +173,7 @@ describe("internal session effects", () => {
type: "message",
}),
);
expect(listSessionEntries({ agentId: "main", storePath })).toEqual([
expect(listSessionEntriesCore({ agentId: "main", storePath })).toEqual([
expect.objectContaining({ sessionKey: source.sessionKey }),
]);
});
+1 -1
View File
@@ -35,7 +35,7 @@ vi.mock("../config/sessions/session-accessor.js", () => {
return {
loadSessionEntry,
loadSessionEntryReadOnly: loadSessionEntry,
patchSessionEntry: (...args: unknown[]) => state.updateSessionStoreMock(...args),
patchSessionEntryCore: (...args: unknown[]) => state.updateSessionStoreMock(...args),
};
});
+3 -3
View File
@@ -8,7 +8,7 @@ import { resolveStorePath } from "../config/sessions/paths.js";
import {
loadSessionEntry,
loadSessionEntryReadOnly,
patchSessionEntry,
patchSessionEntryCore,
} from "../config/sessions/session-accessor.js";
import type { SessionEntry } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
@@ -275,7 +275,7 @@ export async function consolidateLiveModelSwitchAfterRun(params: {
if (!storePath) {
return;
}
await patchSessionEntry(
await patchSessionEntryCore(
{ storePath, sessionKey },
(entry) => {
if (!entry.liveModelSwitchPending) {
@@ -325,7 +325,7 @@ export async function clearLiveModelSwitchPending(params: {
if (!storePath) {
return;
}
await patchSessionEntry(
await patchSessionEntryCore(
{ storePath, sessionKey },
(entry) => {
const next = { ...entry };
+4 -4
View File
@@ -9,7 +9,7 @@ import { normalizeAgentId, parseAgentSessionKey } from "../routing/session-key.j
import { resolveAgentConfig, resolveDefaultAgentId } from "./agent-scope-config.js";
import type { AnyAgentTool } from "./agent-tools.types.js";
import { compileGlobPatterns, matchesAnyGlobPattern } from "./glob-pattern.js";
import { expandToolGroups, normalizeToolName } from "./tool-policy.js";
import { expandToolGroups, normalizeToolPolicyName } from "./tool-policy.js";
import { AUTOMATIONS_TOOL_NAME } from "./tools/automations-tool-name.js";
const LOCAL_MODEL_LEAN_DENY_TOOL_NAMES = new Set([
@@ -34,8 +34,8 @@ function resolvePreservedLocalModelLeanToolNames(names?: Iterable<string>) {
return [];
}
return compileGlobPatterns({
raw: expandToolGroups([...names]).filter((name) => normalizeToolName(name) !== "*"),
normalize: normalizeToolName,
raw: expandToolGroups([...names]).filter((name) => normalizeToolPolicyName(name) !== "*"),
normalize: normalizeToolPolicyName,
});
}
@@ -101,7 +101,7 @@ export function filterLocalModelLeanTools(params: {
}
const preservedToolNames = resolvePreservedLocalModelLeanToolNames(params.preserveToolNames);
return params.tools.filter((tool) => {
const normalizedName = normalizeToolName(tool.name);
const normalizedName = normalizeToolPolicyName(tool.name);
return (
matchesAnyGlobPattern(normalizedName, preservedToolNames) ||
!LOCAL_MODEL_LEAN_DENY_TOOL_NAMES.has(normalizedName)
@@ -5,7 +5,7 @@ import type { InternalSessionEntry as SessionEntry } from "../../config/sessions
import * as sessionAccessor from "../../config/sessions/session-accessor.js";
import {
applySessionEntryLifecycleMutation,
listSessionEntries,
listSessionEntriesCore,
} from "../../config/sessions/session-accessor.js";
import {
getAgentEventLifecycleGeneration,
@@ -58,7 +58,7 @@ describe("main session recovery store", () => {
function readStore(): Record<string, SessionEntry> {
return Object.fromEntries(
listSessionEntries({ storePath }).map(({ sessionKey: key, entry }) => [key, entry]),
listSessionEntriesCore({ storePath }).map(({ sessionKey: key, entry }) => [key, entry]),
);
}
@@ -13,7 +13,7 @@ import type { InternalSessionEntry as SessionEntry } from "../../config/sessions
import * as sessionAccessor from "../../config/sessions/session-accessor.js";
import {
appendTranscriptMessage,
listSessionEntries,
listSessionEntriesCore,
loadSessionEntry as loadSessionEntryRaw,
loadTranscriptEvents,
replaceSessionEntry,
@@ -363,7 +363,7 @@ async function writeMainSession({
function readStore(storePath: string): Record<string, SessionEntry> {
return Object.fromEntries(
listSessionEntries({ storePath }).map(({ sessionKey, entry }) => [sessionKey, entry]),
listSessionEntriesCore({ storePath }).map(({ sessionKey, entry }) => [sessionKey, entry]),
);
}
+10 -10
View File
@@ -10,7 +10,7 @@ import { setPluginToolMeta } from "../plugins/tools.js";
import { sanitizeServerName } from "./agent-bundle-mcp-names.js";
import { compileGlobPatterns, matchesAnyGlobPattern } from "./glob-pattern.js";
import type { AgentToolResult } from "./runtime/index.js";
import { DEFAULT_PLUGIN_TOOLS_ALLOWLIST_ENTRY, normalizeToolName } from "./tool-policy.js";
import { DEFAULT_PLUGIN_TOOLS_ALLOWLIST_ENTRY, normalizeToolPolicyName } from "./tool-policy.js";
import { jsonResult } from "./tools/common.js";
import type { AnyAgentTool } from "./tools/common.js";
import { callGatewayTool } from "./tools/gateway.js";
@@ -65,7 +65,7 @@ function mapMcpPayloadToAgentToolResult(payload: unknown): AgentToolResult<unkno
}
function normalizePolicyNames(values: readonly string[] | undefined): Set<string> {
return new Set((values ?? []).map((value) => normalizeToolName(value)).filter(Boolean));
return new Set((values ?? []).map((value) => normalizeToolPolicyName(value)).filter(Boolean));
}
function toolPolicyAllows(params: {
@@ -76,9 +76,9 @@ function toolPolicyAllows(params: {
denylist: ReturnType<typeof compileGlobPatterns>;
registered: boolean;
}): boolean {
const pluginId = normalizeToolName(params.pluginId);
const toolName = normalizeToolName(params.toolName);
const exposedToolName = normalizeToolName(params.exposedToolName ?? params.toolName);
const pluginId = normalizeToolPolicyName(params.pluginId);
const toolName = normalizeToolPolicyName(params.toolName);
const exposedToolName = normalizeToolPolicyName(params.exposedToolName ?? params.toolName);
if (
matchesAnyGlobPattern(pluginId, params.denylist) ||
matchesAnyGlobPattern(toolName, params.denylist) ||
@@ -152,7 +152,7 @@ function resolveUniqueToolName(params: {
for (let index = 0; index < 100; index += 1) {
const suffix = index === 0 ? "" : `_${index + 1}`;
const candidate = prependToolNameFragment(params.baseName, nodeFragment, suffix);
const normalized = normalizeToolName(candidate);
const normalized = normalizeToolPolicyName(candidate);
if (
isProviderSafeToolName(candidate) &&
normalized &&
@@ -171,19 +171,19 @@ export function createNodePluginTools(params: {
agentSessionKey?: string;
}): AnyAgentTool[] {
const existingNormalized = new Set(
[...(params.existingToolNames ?? [])].map((name) => normalizeToolName(name)),
[...(params.existingToolNames ?? [])].map((name) => normalizeToolPolicyName(name)),
);
const allowlist = normalizePolicyNames(params.toolAllowlist);
const denylist = compileGlobPatterns({
raw: params.toolDenylist,
normalize: normalizeToolName,
normalize: normalizeToolPolicyName,
});
const entries: MaterializedNodeToolEntry[] = [];
const nameCounts = new Map<string, number>();
for (const entry of listConnectedNodePluginTools()) {
const descriptor = entry.descriptor;
const command = descriptor.command?.trim();
const normalizedName = normalizeToolName(descriptor.name);
const normalizedName = normalizeToolPolicyName(descriptor.name);
if (!command || !normalizedName) {
continue;
}
@@ -216,7 +216,7 @@ export function createNodePluginTools(params: {
) {
continue;
}
existingNormalized.add(normalizeToolName(toolName));
existingNormalized.add(normalizeToolPolicyName(toolName));
const mcpTool = descriptor.command === NODE_MCP_TOOLS_CALL_COMMAND ? descriptor.mcp : undefined;
const tool: AnyAgentTool = {
name: toolName,
+2 -2
View File
@@ -4,7 +4,7 @@ import { getRuntimeConfig } from "../config/io.js";
import { parseSqliteSessionFileMarker } from "../config/sessions/legacy-sqlite-marker.js";
import { resolveStorePath } from "../config/sessions/paths.js";
import {
listSessionEntries,
listSessionEntriesCore,
resolveTranscriptSessionKeyBySessionId,
resolveSessionTranscriptRuntimeTarget,
type SessionTranscriptRuntimeTarget,
@@ -104,7 +104,7 @@ export async function resolveAgentRunSessionTarget(params: {
(params.missingSessionKey === "create" ? plainCompatibilitySessionKey : undefined);
const markerEntries =
legacyMarker && !hasCompleteTypedTarget
? listSessionEntries({
? listSessionEntriesCore({
agentId: legacyMarker.agentId,
storePath: legacyMarker.storePath,
})
+6 -6
View File
@@ -8,7 +8,7 @@ import { uniqueStrings } from "@openclaw/normalization-core/string-normalization
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { resolveAgentConfig } from "../agent-scope.js";
import { compileGlobPatterns, matchesAnyGlobPattern } from "../glob-pattern.js";
import { expandToolGroups, normalizeToolName } from "../tool-policy.js";
import { expandToolGroups, normalizeToolPolicyName } from "../tool-policy.js";
import { DEFAULT_TOOL_ALLOW, DEFAULT_TOOL_DENY } from "./constants.js";
import type {
SandboxToolPolicy,
@@ -157,13 +157,13 @@ function filterDefaultDenyForExplicitAllows(params: {
}
const allowPatterns = compileGlobPatterns({
raw: expandToolGroups(params.explicitAllowPatterns),
normalize: normalizeToolName,
normalize: normalizeToolPolicyName,
});
if (allowPatterns.length === 0) {
return [...params.deny];
}
return params.deny.filter(
(toolName) => !matchesAnyGlobPattern(normalizeToolName(toolName), allowPatterns),
(toolName) => !matchesAnyGlobPattern(normalizeToolPolicyName(toolName), allowPatterns),
);
}
@@ -197,15 +197,15 @@ export function classifyToolAgainstSandboxToolPolicy(name: string, policy?: Sand
};
}
const normalized = normalizeToolName(name);
const normalized = normalizeToolPolicyName(name);
const deny = compileGlobPatterns({
raw: expandToolGroups(policy.deny ?? []),
normalize: normalizeToolName,
normalize: normalizeToolPolicyName,
});
const blockedByDeny = matchesAnyGlobPattern(normalized, deny);
const allow = compileGlobPatterns({
raw: expandToolGroups(policy.allow ?? []),
normalize: normalizeToolName,
normalize: normalizeToolPolicyName,
});
const blockedByAllow =
!blockedByDeny && allow.length > 0 && !matchesAnyGlobPattern(normalized, allow);
+4 -4
View File
@@ -15,7 +15,7 @@ import { isToolAllowedByPolicies } from "../tool-policy-match.js";
import {
expandToolGroups,
mergeAlsoAllowPolicy,
normalizeToolName,
normalizeToolPolicyName,
resolveToolProfilePolicy,
} from "../tool-policy.js";
import { resolveSandboxConfigForAgent } from "./config.js";
@@ -54,7 +54,7 @@ function findUnconfinedAllowedTool(
}
for (const entry of candidatePolicy.allow) {
for (const candidate of expandToolGroups([entry])) {
const normalized = normalizeToolName(candidate);
const normalized = normalizeToolPolicyName(candidate);
if (!isToolAllowedByPolicies(normalized, policies)) {
continue;
}
@@ -216,14 +216,14 @@ export function resolveSandboxWorkspaceAuthority(params: {
sandboxPolicy: sandbox.tools,
});
const unavailableTool = (params.requiredToolNames ?? [])
.map(normalizeToolName)
.map(normalizeToolPolicyName)
.find((name) => !isToolAllowedByPolicies(name, policies));
if (unavailableTool) {
confinementError = `target tool policy blocks required tool ${unavailableTool}.`;
} else {
const unsafeTool = findUnconfinedAllowedTool(
policies,
new Set((params.confinedToolNames ?? []).map(normalizeToolName)),
new Set((params.confinedToolNames ?? []).map(normalizeToolPolicyName)),
);
if (unsafeTool) {
confinementError = `target sandbox allows unclassified tool surface ${unsafeTool}.`;
+2 -2
View File
@@ -2,7 +2,7 @@
import {
appendTranscriptMessage,
loadSessionEntry,
patchSessionEntry,
patchSessionEntryCore,
} from "../config/sessions/session-accessor.js";
import {
createAgentPatchedSessionModelFallback,
@@ -47,7 +47,7 @@ async function reconcileAgentPatchedSessionModel(params: {
let note: string | undefined;
let sessionId: string | undefined;
let result: "cleared" | "promoted" | "reverted" | "none" = "none";
await patchSessionEntry(
await patchSessionEntryCore(
{
agentId: params.agentId,
sessionKey: params.sessionKey,
+11 -11
View File
@@ -6,7 +6,7 @@ import { CommandLane } from "../process/lanes.js";
import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js";
const sessionAccessorMocks = vi.hoisted(() => ({
patchSessionEntry: vi.fn(),
patchSessionEntryCore: vi.fn(),
}));
const commandQueueMocks = vi.hoisted(() => ({
@@ -50,7 +50,7 @@ describe("session suspension", () => {
const { resetSessionSuspensionStateForTest } =
await import("./session-suspension.test-support.js");
resetSessionSuspensionStateForTest();
sessionAccessorMocks.patchSessionEntry.mockClear();
sessionAccessorMocks.patchSessionEntryCore.mockClear();
commandQueueMocks.setCommandLaneConcurrency.mockClear();
});
@@ -183,7 +183,7 @@ describe("session suspension", () => {
vi.useFakeTimers();
const { setGatewayLaneResumeConcurrencies } = await import("./session-suspension.js");
let resolvePatch: (() => void) | undefined;
sessionAccessorMocks.patchSessionEntry.mockImplementationOnce(async (_scope, update) => {
sessionAccessorMocks.patchSessionEntryCore.mockImplementationOnce(async (_scope, update) => {
await new Promise<void>((resolve) => {
resolvePatch = resolve;
});
@@ -222,7 +222,7 @@ describe("session suspension", () => {
await suspendLane(Number.MAX_SAFE_INTEGER, {} as OpenClawConfig, CommandLane.Main);
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS);
const buildPatch = sessionAccessorMocks.patchSessionEntry.mock.calls[0]?.[1] as (_entry: {
const buildPatch = sessionAccessorMocks.patchSessionEntryCore.mock.calls[0]?.[1] as (_entry: {
quotaSuspension?: unknown;
}) => {
quotaSuspension?: { expectedResumeBy?: number };
@@ -261,12 +261,12 @@ describe("session suspension", () => {
expect(commandQueueMocks.setCommandLaneConcurrency).toHaveBeenCalledWith(CommandLane.Nested, 0);
expect(clearSessionSuspensionTimers()).toBe(1);
commandQueueMocks.setCommandLaneConcurrency.mockClear();
sessionAccessorMocks.patchSessionEntry.mockClear();
sessionAccessorMocks.patchSessionEntryCore.mockClear();
await suspendLane(100, {} as OpenClawConfig, CommandLane.Nested);
expect(commandQueueMocks.setCommandLaneConcurrency).not.toHaveBeenCalled();
expect(sessionAccessorMocks.patchSessionEntry).not.toHaveBeenCalled();
expect(sessionAccessorMocks.patchSessionEntryCore).not.toHaveBeenCalled();
enableSessionSuspensionTimersForGatewayStart();
await suspendLane(100, {} as OpenClawConfig, CommandLane.Nested);
@@ -378,7 +378,7 @@ describe("session suspension", () => {
laneId?: string;
}
| undefined;
sessionAccessorMocks.patchSessionEntry.mockImplementationOnce(async (_scope, update) => {
sessionAccessorMocks.patchSessionEntryCore.mockImplementationOnce(async (_scope, update) => {
await new Promise<void>((resolve) => {
resolvePatch = resolve;
});
@@ -400,7 +400,7 @@ describe("session suspension", () => {
expect(commandQueueMocks.setCommandLaneConcurrency).not.toHaveBeenCalled();
expect(writtenQuotaSuspension).toBeUndefined();
expect(sessionAccessorMocks.patchSessionEntry).toHaveBeenCalledOnce();
expect(sessionAccessorMocks.patchSessionEntryCore).toHaveBeenCalledOnce();
await vi.advanceTimersByTimeAsync(100);
@@ -410,7 +410,7 @@ describe("session suspension", () => {
it("does not let a pending suspension regain ownership after test state resets", async () => {
let resolvePatch: (() => void) | undefined;
let writtenQuotaSuspension: unknown;
sessionAccessorMocks.patchSessionEntry.mockImplementationOnce(async (_scope, update) => {
sessionAccessorMocks.patchSessionEntryCore.mockImplementationOnce(async (_scope, update) => {
await new Promise<void>((resolve) => {
resolvePatch = resolve;
});
@@ -452,7 +452,7 @@ describe("session suspension", () => {
const initialWritesReleased = new Promise<void>((resolve) => {
releaseInitialWrites = resolve;
});
sessionAccessorMocks.patchSessionEntry.mockImplementation(async (_scope, update) => {
sessionAccessorMocks.patchSessionEntryCore.mockImplementation(async (_scope, update) => {
const patch = update(storeEntry) as typeof storeEntry | null;
if (patch && "quotaSuspension" in patch) {
storeEntry =
@@ -481,7 +481,7 @@ describe("session suspension", () => {
it("still throttles the lane when persistence fails while gateway is active", async () => {
vi.useFakeTimers();
sessionAccessorMocks.patchSessionEntry.mockRejectedValueOnce(new Error("disk busy"));
sessionAccessorMocks.patchSessionEntryCore.mockRejectedValueOnce(new Error("disk busy"));
await suspendLane(
100,
+3 -3
View File
@@ -6,7 +6,7 @@
import { AsyncLocalStorage } from "node:async_hooks";
import { resolveAgentMaxConcurrent, resolveSubagentMaxConcurrent } from "../config/agent-limits.js";
import { resolveCronMaxConcurrentRuns } from "../config/cron-limits.js";
import { patchSessionEntry } from "../config/sessions/session-accessor.js";
import { patchSessionEntryCore } from "../config/sessions/session-accessor.js";
import type { QuotaSuspension } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
@@ -374,7 +374,7 @@ async function suspendSessionQueued(params: SessionSuspensionParams, queuedGener
let persistedSuspension: boolean;
try {
const patchedEntry = await patchSessionEntry(
const patchedEntry = await patchSessionEntryCore(
{ storePath, sessionKey },
(entry) => {
if (getSessionSuspensionState().cleanupGeneration !== suspensionGeneration) {
@@ -423,7 +423,7 @@ async function suspendSessionQueued(params: SessionSuspensionParams, queuedGener
(postPatchState.cleanupActive || suspensionGeneration !== postPatchState.cleanupGeneration)
) {
try {
await patchSessionEntry(
await patchSessionEntryCore(
{ storePath, sessionKey },
(entry) =>
entry.quotaSuspension?.suspendedAt === now &&
+2 -2
View File
@@ -12,7 +12,7 @@ import {
*/
import { expandTildePath } from "../../shared/tilde-path.js";
import { CONFIG_DIR_NAME } from "../config.js";
import { parseFrontmatter } from "../utils/frontmatter.js";
import { parsePromptFrontmatter } from "../utils/frontmatter.js";
import { createSyntheticSourceInfo, type SourceInfo } from "./source-info.js";
/**
@@ -30,7 +30,7 @@ export interface PromptTemplate {
function loadTemplateFromFile(filePath: string, sourceInfo: SourceInfo): PromptTemplate | null {
try {
const rawContent = readFileSync(filePath, "utf-8");
const { frontmatter, body } = parseFrontmatter<Record<string, string>>(rawContent);
const { frontmatter, body } = parsePromptFrontmatter<Record<string, string>>(rawContent);
const name = basename(filePath).replace(/\.md$/, "");
@@ -5,7 +5,7 @@ type OutputDeps = Pick<
OutputRuntime,
| "callGateway"
| "getRuntimeConfig"
| "readSessionEntry"
| "readSubagentSessionEntry"
| "readSessionMessagesAsync"
| "resolveAgentIdFromSessionKey"
| "resolveStorePath"
@@ -12,7 +12,7 @@ import {
type CallGateway = typeof import("../../../gateway/call.js").callGateway;
type GetRuntimeConfig = typeof import("./subagent-announce.runtime.js").getRuntimeConfig;
type ReadSessionEntry = typeof import("./subagent-announce.runtime.js").readSessionEntry;
type ReadSessionEntry = typeof import("./subagent-announce.runtime.js").readSubagentSessionEntry;
type ReadSessionMessagesAsync =
typeof import("./subagent-announce.runtime.js").readSessionMessagesAsync;
type ResolveAgentIdFromSessionKey =
@@ -89,7 +89,7 @@ describe("buildCompactAnnounceStatsLine", () => {
it("rolls one-decimal thousand token stats over to the million unit", async () => {
testing.setDepsForTest({
getRuntimeConfig: (() => ({ session: { store: "memory" } })) as GetRuntimeConfig,
readSessionEntry: (() => ({
readSubagentSessionEntry: (() => ({
sessionId: "child-session",
updatedAt: 0,
inputTokens: 999_999,
@@ -25,7 +25,7 @@ import {
import {
callGateway,
getRuntimeConfig,
readSessionEntry,
readSubagentSessionEntry,
readSessionMessagesAsync,
resolveAgentIdFromSessionKey,
resolveStorePath,
@@ -47,7 +47,7 @@ const ASSISTANT_TOOL_CALL_BLOCK_TYPES = new Set([
type SubagentAnnounceOutputDeps = {
callGateway: typeof callGateway;
getRuntimeConfig: typeof getRuntimeConfig;
readSessionEntry: typeof readSessionEntry;
readSubagentSessionEntry: typeof readSubagentSessionEntry;
readSessionMessagesAsync: typeof readSessionMessagesAsync;
resolveAgentIdFromSessionKey: typeof resolveAgentIdFromSessionKey;
resolveStorePath: typeof resolveStorePath;
@@ -56,7 +56,7 @@ type SubagentAnnounceOutputDeps = {
const defaultSubagentAnnounceOutputDeps: SubagentAnnounceOutputDeps = {
callGateway,
getRuntimeConfig,
readSessionEntry,
readSubagentSessionEntry,
readSessionMessagesAsync,
resolveAgentIdFromSessionKey,
resolveStorePath,
@@ -650,7 +650,7 @@ export async function buildCompactAnnounceStatsLine(params: {
const cfg = subagentAnnounceOutputDeps.getRuntimeConfig();
const agentId = subagentAnnounceOutputDeps.resolveAgentIdFromSessionKey(params.sessionKey);
const storePath = subagentAnnounceOutputDeps.resolveStorePath(cfg.session?.store, { agentId });
let entry = subagentAnnounceOutputDeps.readSessionEntry(storePath, params.sessionKey);
let entry = subagentAnnounceOutputDeps.readSubagentSessionEntry(storePath, params.sessionKey);
const tokenWaitAttempts = isFastTestMode() ? 1 : 3;
for (let attempt = 0; attempt < tokenWaitAttempts; attempt += 1) {
const hasTokenData =
@@ -665,7 +665,7 @@ export async function buildCompactAnnounceStatsLine(params: {
setTimeout(resolve, 150);
});
}
entry = subagentAnnounceOutputDeps.readSessionEntry(storePath, params.sessionKey);
entry = subagentAnnounceOutputDeps.readSubagentSessionEntry(storePath, params.sessionKey);
}
const input = typeof entry?.inputTokens === "number" ? entry.inputTokens : 0;
@@ -430,7 +430,7 @@ describe("subagent announce formatting", () => {
req: Parameters<typeof gatewayCall.callGateway>[0],
) => (await callGatewaySpy(req)) as T,
getRuntimeConfig: () => configOverride,
readSessionEntry: (_storePath, sessionKey) => loadSessionStoreFixture()[sessionKey],
readSubagentSessionEntry: (_storePath, sessionKey) => loadSessionStoreFixture()[sessionKey],
resolveAgentIdFromSessionKey: () => "main",
resolveStorePath: () => "/tmp/sessions.json",
});
@@ -44,7 +44,7 @@ vi.mock("./subagent-announce.runtime.js", () => ({
getRuntimeConfig: () => ({ session: { mainKey: "main", scope: "per-sender" } }),
loadSessionStore: vi.fn(() => ({})),
readSessionMessagesAsync: vi.fn(async () => []),
readSessionEntry: vi.fn(() => undefined),
readSubagentSessionEntry: vi.fn(() => undefined),
resolveAgentIdFromSessionKey: vi.fn(() => "main"),
resolveMainSessionKey: vi.fn(() => "agent:main:main"),
resolveStorePath: vi.fn(() => "/tmp/sessions.json"),
@@ -8,7 +8,7 @@ export { getRuntimeConfig } from "../../../config/config.js";
export { resolveAgentIdFromSessionKey, resolveStorePath } from "../../../config/sessions.js";
import { loadSessionEntry } from "../../../config/sessions/session-accessor.js";
export function readSessionEntry(storePath: string, sessionKey: string) {
export function readSubagentSessionEntry(storePath: string, sessionKey: string) {
return loadSessionEntry({ storePath, sessionKey });
}
export { callGateway } from "../../../gateway/call.js";
@@ -71,7 +71,7 @@ vi.mock("./subagent-announce.runtime.js", () => ({
getRuntimeConfig: () => mockConfig,
loadSessionStore: (storePath: string) => loadSessionStoreMock(storePath),
readSessionMessagesAsync: vi.fn(async () => []),
readSessionEntry: (storePath: string, sessionKey: string) =>
readSubagentSessionEntry: (storePath: string, sessionKey: string) =>
(loadSessionStoreMock(storePath) as Record<string, unknown>)[sessionKey],
resolveAgentIdFromSessionKey: (sessionKey: string) =>
resolveAgentIdFromSessionKeyMock(sessionKey),
@@ -188,7 +188,7 @@ vi.mock("./subagent-announce.runtime.js", () => ({
getRuntimeConfig: () => configOverride,
loadSessionStore: vi.fn(() => sessionStore),
readSessionMessagesAsync: vi.fn(async () => []),
readSessionEntry: (_storePath: string, sessionKey: string) => sessionStore[sessionKey],
readSubagentSessionEntry: (_storePath: string, sessionKey: string) => sessionStore[sessionKey],
resolveAgentIdFromSessionKey: () => "main",
resolveStorePath: () => "/tmp/sessions-main.json",
resolveMainSessionKey: () => "agent:main:main",
@@ -3,7 +3,7 @@ export * from "./subagent-control.js";
type ControlRuntime = typeof import("./subagent-control.runtime.js");
type ControlDeps = {
callGateway: typeof import("../../../gateway/call.js").callGateway;
patchSessionEntry: typeof import("../../../config/sessions/session-accessor.js").patchSessionEntry;
patchSessionEntryCore: typeof import("../../../config/sessions/session-accessor.js").patchSessionEntryCore;
abortEmbeddedAgentRun: ControlRuntime["abortEmbeddedAgentRun"];
isEmbeddedAgentRunActive: ControlRuntime["isEmbeddedAgentRunActive"];
clearSessionQueues: ControlRuntime["clearSessionQueues"];
@@ -167,7 +167,7 @@ function setSubagentControlDepsForTest(
abortEmbeddedAgentRun: () => false,
isEmbeddedAgentRunActive: () => false,
clearSessionQueues: () => ({ followupCleared: 0, laneCleared: 0, keys: [] }),
patchSessionEntry: async (
patchSessionEntryCore: async (
scope: SessionAccessScope,
patcher: (
entry: SessionEntry,
@@ -811,7 +811,7 @@ describe("killSubagentRunAdmin", () => {
});
return true;
},
patchSessionEntry: async (_scope, patcher) => {
patchSessionEntryCore: async (_scope, patcher) => {
const current = { sessionId: "sess-abort-lifecycle-race", updatedAt: Date.now() };
const patch = await patcher(current, { existingEntry: { ...current } });
abortedLastRunWrites.push(patch?.abortedLastRun === true);
@@ -878,7 +878,7 @@ describe("killSubagentRunAdmin", () => {
});
return true;
},
patchSessionEntry: async (_scope, patcher) => {
patchSessionEntryCore: async (_scope, patcher) => {
const current = { sessionId: "sess-completion-race", updatedAt: Date.now() };
const patch = await patcher(current, { existingEntry: { ...current } });
abortedLastRunWrites.push(patch?.abortedLastRun === true);
@@ -953,7 +953,7 @@ describe("killSubagentRunAdmin", () => {
setSubagentControlDepsForTest({
isEmbeddedAgentRunActive: () => true,
abortEmbeddedAgentRun: () => true,
patchSessionEntry: async (scope, patcher) => {
patchSessionEntryCore: async (scope, patcher) => {
if (!scope.storePath) {
return null;
}
@@ -1032,7 +1032,7 @@ describe("killSubagentRunAdmin", () => {
run.pauseReason = "sessions_yield";
return true;
},
patchSessionEntry: async () => {
patchSessionEntryCore: async () => {
return null;
},
});
@@ -1471,7 +1471,7 @@ describe("killControlledSubagentRun", () => {
isEmbeddedAgentRunActive: () => false,
abortEmbeddedAgentRun: abort,
clearSessionQueues: clearQueues,
patchSessionEntry: async (_scope, patcher) => {
patchSessionEntryCore: async (_scope, patcher) => {
markPersistenceStarted();
await persistenceRelease;
const current = { sessionId: "sess-persist-generation-race", updatedAt: Date.now() };
@@ -1624,7 +1624,7 @@ describe("killControlledSubagentRun", () => {
addSubagentRunForTests(entry);
const patches: Array<Partial<SessionEntry> | null> = [];
setSubagentControlDepsForTest({
patchSessionEntry: async (_scope, patcher) => {
patchSessionEntryCore: async (_scope, patcher) => {
const replacement: SessionEntry = {
sessionId: "sess-kill-session-patch-reset",
lifecycleRevision: "revision-after-reset",
@@ -2079,7 +2079,7 @@ describe("killControlledSubagentRun", () => {
const abortedLastRunWrites: boolean[] = [];
let persistenceWrites = 0;
setSubagentControlDepsForTest({
patchSessionEntry: async (_scope, patcher) => {
patchSessionEntryCore: async (_scope, patcher) => {
const current = { sessionId, updatedAt: 1, abortedLastRun: true };
const patch = await patcher(current, { existingEntry: { ...current } });
if (patch) {

Some files were not shown because too many files have changed in this diff Show More