fix: honor acp reset default account

This commit is contained in:
Tak Hoffman
2026-04-03 16:39:44 -05:00
parent 32f9a7c7bc
commit 4518b9ea7a
2 changed files with 80 additions and 2 deletions

View File

@@ -35,6 +35,25 @@ function normalizeText(value: string | undefined | null): string {
return value?.trim() ?? "";
}
function resolveResetTargetAccountId(params: {
cfg: OpenClawConfig;
channel: string;
accountId?: string | null;
}): string {
const explicit = normalizeText(params.accountId);
if (explicit) {
return explicit;
}
const channelCfg = (params.cfg.channels as Record<string, { defaultAccount?: unknown } | undefined>)[
params.channel
];
const configuredDefault = channelCfg?.defaultAccount;
return typeof configuredDefault === "string" && configuredDefault.trim()
? configuredDefault.trim()
: DEFAULT_ACCOUNT_ID;
}
function resolveRawConfiguredAcpSessionKey(params: {
cfg: OpenClawConfig;
channel: string;
@@ -102,7 +121,11 @@ export function resolveEffectiveResetTargetSessionKey(params: {
if (!channel || !conversationId) {
return activeAcpSessionKey;
}
const accountId = normalizeText(params.accountId) || DEFAULT_ACCOUNT_ID;
const accountId = resolveResetTargetAccountId({
cfg: params.cfg,
channel,
accountId: params.accountId,
});
const parentConversationId = normalizeText(params.parentConversationId) || undefined;
const allowNonAcpBindingSessionKey = Boolean(params.allowNonAcpBindingSessionKey);

View File

@@ -114,7 +114,10 @@ vi.mock("../../infra/outbound/session-binding-service.js", async () => {
const { handleAcpCommand } = await import("./commands-acp.js");
const { buildCommandTestParams } = await import("./commands-spawn.test-harness.js");
const { __testing: acpManagerTesting } = await import("../../acp/control-plane/manager.js");
const { __testing: acpResetTargetTesting } = await import("./acp-reset-target.js");
const {
__testing: acpResetTargetTesting,
resolveEffectiveResetTargetSessionKey,
} = await import("./acp-reset-target.js");
const { createTaskRecord, resetTaskRegistryForTests } =
await import("../../tasks/task-registry.js");
const { failTaskRunByRunId } = await import("../../tasks/task-executor.js");
@@ -1410,6 +1413,58 @@ describe("/acp command", () => {
expect(result?.reply?.text).toContain("Viewed diver package.");
});
it("resolves ACP reset targets through the configured default account when AccountId is omitted", () => {
const cfg = {
...baseCfg,
channels: {
...baseCfg.channels,
discord: {
...baseCfg.channels.discord,
defaultAccount: "work",
},
},
} satisfies OpenClawConfig;
hoisted.sessionBindingResolveByConversationMock.mockImplementation(
(ref: {
channel?: string;
accountId?: string;
conversationId?: string;
parentConversationId?: string;
}) =>
ref.channel === "discord" &&
ref.accountId === "work" &&
ref.conversationId === defaultThreadId &&
ref.parentConversationId === "parent-1"
? createSessionBinding({
targetSessionKey: defaultAcpSessionKey,
conversation: {
channel: "discord",
accountId: "work",
conversationId: defaultThreadId,
parentConversationId: "parent-1",
},
})
: null,
);
const result = resolveEffectiveResetTargetSessionKey({
cfg,
channel: "discord",
conversationId: defaultThreadId,
parentConversationId: "parent-1",
});
expect(hoisted.sessionBindingResolveByConversationMock).toHaveBeenCalledWith(
expect.objectContaining({
channel: "discord",
accountId: "work",
conversationId: defaultThreadId,
parentConversationId: "parent-1",
}),
);
expect(result).toBe(defaultAcpSessionKey);
});
it("blocks /acp steer when ACP dispatch is disabled by policy", async () => {
const cfg = {
...baseCfg,