Allow ACP sessions.patch lineage fields on ACP session keys (#40995)

Merged via squash.

Prepared head SHA: c1191edc08618dec1826c57b75556c4e35ccccaf
Co-authored-by: xaeon2026 <264572156+xaeon2026@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
xaeon2026
2026-03-09 12:08:11 -04:00
committed by GitHub
parent 54be30ef89
commit 425bd89b48
3 changed files with 33 additions and 4 deletions

View File

@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
- Models/Kimi Coding: send `anthropic-messages` tools in native Anthropic format again so `kimi-coding` stops degrading tool calls into XML/plain-text pseudo invocations instead of real `tool_use` blocks. (#38669, #39907, #40552) Thanks @opriz.
- Context engine/tests: add bundled-registry regression coverage for cross-chunk resolution, plugin-sdk re-exports, and concurrent chunk registration. (#40460) thanks @dsantoreis.
- Agents/embedded runner: bound compaction retry waiting and drain embedded runs during SIGUSR1 restart so session lanes recover instead of staying blocked behind compaction. (#40324) thanks @cgdusek.
- ACP/sessions.patch: allow `spawnedBy` and `spawnDepth` lineage fields on ACP session keys so `sessions_spawn` with `runtime: "acp"` no longer fails during child-session setup. Fixes #40971. (#40995) thanks @xaeon2026.
## 2026.3.8

View File

@@ -252,6 +252,29 @@ describe("gateway sessions patch", () => {
expect(entry.spawnDepth).toBe(2);
});
test("sets spawnedBy for ACP sessions", async () => {
const entry = expectPatchOk(
await runPatch({
storeKey: "agent:main:acp:child",
patch: {
key: "agent:main:acp:child",
spawnedBy: "agent:main:main",
},
}),
);
expect(entry.spawnedBy).toBe("agent:main:main");
});
test("sets spawnDepth for ACP sessions", async () => {
const entry = expectPatchOk(
await runPatch({
storeKey: "agent:main:acp:child",
patch: { key: "agent:main:acp:child", spawnDepth: 2 },
}),
);
expect(entry.spawnDepth).toBe(2);
});
test("rejects spawnDepth on non-subagent sessions", async () => {
const result = await runPatch({
patch: { key: MAIN_SESSION_KEY, spawnDepth: 1 },

View File

@@ -19,6 +19,7 @@ import {
import type { OpenClawConfig } from "../config/config.js";
import type { SessionEntry } from "../config/sessions.js";
import {
isAcpSessionKey,
isSubagentSessionKey,
normalizeAgentId,
parseAgentSessionKey,
@@ -62,6 +63,10 @@ function normalizeExecAsk(raw: string): "off" | "on-miss" | "always" | undefined
return undefined;
}
function supportsSpawnLineage(storeKey: string): boolean {
return isSubagentSessionKey(storeKey) || isAcpSessionKey(storeKey);
}
export async function applySessionsPatchToStore(params: {
cfg: OpenClawConfig;
store: Record<string, SessionEntry>;
@@ -97,8 +102,8 @@ export async function applySessionsPatchToStore(params: {
if (!trimmed) {
return invalid("invalid spawnedBy: empty");
}
if (!isSubagentSessionKey(storeKey)) {
return invalid("spawnedBy is only supported for subagent:* sessions");
if (!supportsSpawnLineage(storeKey)) {
return invalid("spawnedBy is only supported for subagent:* or acp:* sessions");
}
if (existing?.spawnedBy && existing.spawnedBy !== trimmed) {
return invalid("spawnedBy cannot be changed once set");
@@ -114,8 +119,8 @@ export async function applySessionsPatchToStore(params: {
return invalid("spawnDepth cannot be cleared once set");
}
} else if (raw !== undefined) {
if (!isSubagentSessionKey(storeKey)) {
return invalid("spawnDepth is only supported for subagent:* sessions");
if (!supportsSpawnLineage(storeKey)) {
return invalid("spawnDepth is only supported for subagent:* or acp:* sessions");
}
const numeric = Number(raw);
if (!Number.isInteger(numeric) || numeric < 0) {