fix(regression): preserve spawned metadata across auto-reply reset

This commit is contained in:
Tak Hoffman 2026-03-27 19:55:24 -05:00
parent 3ec1df86fa
commit 8a687bdbd7
No known key found for this signature in database
2 changed files with 78 additions and 1 deletions

View File

@ -1405,6 +1405,60 @@ describe("initSessionState preserves behavior overrides across /new and /reset",
}
});
it("preserves spawned session ownership metadata across /new and /reset", async () => {
const storePath = await createStorePath("openclaw-reset-spawned-metadata-");
const sessionKey = "subagent:owned-child";
const existingSessionId = "existing-session-owned-child";
const overrides = {
spawnedBy: "agent:main:main",
spawnedWorkspaceDir: "/tmp/child-workspace",
parentSessionKey: "agent:main:main",
forkedFromParent: true,
spawnDepth: 2,
subagentRole: "orchestrator",
subagentControlScope: "children",
displayName: "Ops Child",
} as const;
const cases = [
{ name: "new preserves spawned session ownership metadata", body: "/new" },
{ name: "reset preserves spawned session ownership metadata", body: "/reset" },
] as const;
for (const testCase of cases) {
await seedSessionStoreWithOverrides({
storePath,
sessionKey,
sessionId: existingSessionId,
overrides: { ...overrides },
});
const cfg = {
session: { store: storePath, idleMinutes: 999 },
} as OpenClawConfig;
const result = await initSessionState({
ctx: {
Body: testCase.body,
RawBody: testCase.body,
CommandBody: testCase.body,
From: "user-owned-child",
To: "bot",
ChatType: "direct",
SessionKey: sessionKey,
Provider: "telegram",
Surface: "telegram",
},
cfg,
commandAuthorized: true,
});
expect(result.isNewSession, testCase.name).toBe(true);
expect(result.resetTriggered, testCase.name).toBe(true);
expect(result.sessionId, testCase.name).not.toBe(existingSessionId);
expect(result.sessionEntry).toMatchObject(overrides);
}
});
it("requires operator.admin when Provider is internal even if Surface carries external metadata", async () => {
const storePath = await createStorePath("openclaw-internal-reset-provider-authoritative-");
const sessionKey = "agent:main:telegram:dm:provider-authoritative";

View File

@ -263,6 +263,14 @@ export async function initSessionState(params: {
let persistedCliSessionBindings: SessionEntry["cliSessionBindings"];
let persistedClaudeCliSessionId: string | undefined;
let persistedLabel: string | undefined;
let persistedSpawnedBy: SessionEntry["spawnedBy"];
let persistedSpawnedWorkspaceDir: SessionEntry["spawnedWorkspaceDir"];
let persistedParentSessionKey: SessionEntry["parentSessionKey"];
let persistedForkedFromParent: SessionEntry["forkedFromParent"];
let persistedSpawnDepth: SessionEntry["spawnDepth"];
let persistedSubagentRole: SessionEntry["subagentRole"];
let persistedSubagentControlScope: SessionEntry["subagentControlScope"];
let persistedDisplayName: SessionEntry["displayName"];
const normalizedChatType = normalizeChatType(ctx.ChatType);
const isGroup =
@ -424,6 +432,14 @@ export async function initSessionState(params: {
persistedCliSessionBindings = entry.cliSessionBindings;
persistedClaudeCliSessionId = entry.claudeCliSessionId;
persistedLabel = entry.label;
persistedSpawnedBy = entry.spawnedBy;
persistedSpawnedWorkspaceDir = entry.spawnedWorkspaceDir;
persistedParentSessionKey = entry.parentSessionKey;
persistedForkedFromParent = entry.forkedFromParent;
persistedSpawnDepth = entry.spawnDepth;
persistedSubagentRole = entry.subagentRole;
persistedSubagentControlScope = entry.subagentControlScope;
persistedDisplayName = entry.displayName;
}
}
@ -483,12 +499,19 @@ export async function initSessionState(params: {
cliSessionBindings: persistedCliSessionBindings ?? baseEntry?.cliSessionBindings,
claudeCliSessionId: persistedClaudeCliSessionId ?? baseEntry?.claudeCliSessionId,
label: persistedLabel ?? baseEntry?.label,
spawnedBy: persistedSpawnedBy ?? baseEntry?.spawnedBy,
spawnedWorkspaceDir: persistedSpawnedWorkspaceDir ?? baseEntry?.spawnedWorkspaceDir,
parentSessionKey: persistedParentSessionKey ?? baseEntry?.parentSessionKey,
forkedFromParent: persistedForkedFromParent ?? baseEntry?.forkedFromParent,
spawnDepth: persistedSpawnDepth ?? baseEntry?.spawnDepth,
subagentRole: persistedSubagentRole ?? baseEntry?.subagentRole,
subagentControlScope: persistedSubagentControlScope ?? baseEntry?.subagentControlScope,
sendPolicy: baseEntry?.sendPolicy,
queueMode: baseEntry?.queueMode,
queueDebounceMs: baseEntry?.queueDebounceMs,
queueCap: baseEntry?.queueCap,
queueDrop: baseEntry?.queueDrop,
displayName: baseEntry?.displayName,
displayName: persistedDisplayName ?? baseEntry?.displayName,
chatType: baseEntry?.chatType,
channel: baseEntry?.channel,
groupId: baseEntry?.groupId,