mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 03:03:24 -04:00
Fix cron announce fallback to use origin session context
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import "./isolated-agent.mocks.js";
|
||||
import fs from "node:fs/promises";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { runSubagentAnnounceFlow } from "../agents/subagent-announce.js";
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import { runCronIsolatedAgentTurn } from "./isolated-agent.js";
|
||||
import {
|
||||
makeCfg,
|
||||
@@ -184,9 +184,10 @@ describe("runCronIsolatedAgentTurn", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the agent main session key when announce delivery is not pinned", async () => {
|
||||
it("uses cron origin session for unpinned announce fallback and implicit delivery resolution", async () => {
|
||||
await withTempCronHome(async (home) => {
|
||||
const storePath = await writeSessionStore(home, { lastProvider: "webchat", lastTo: "" });
|
||||
const originSessionKey = "agent:main:bluebubbles:direct:+19257864429";
|
||||
await fs.writeFile(
|
||||
storePath,
|
||||
JSON.stringify(
|
||||
@@ -195,6 +196,12 @@ describe("runCronIsolatedAgentTurn", () => {
|
||||
sessionId: "main-session",
|
||||
updatedAt: Date.now(),
|
||||
lastChannel: "telegram",
|
||||
lastTo: "999",
|
||||
},
|
||||
[originSessionKey]: {
|
||||
sessionId: "origin-session",
|
||||
updatedAt: Date.now(),
|
||||
lastChannel: "telegram",
|
||||
lastTo: "123",
|
||||
},
|
||||
},
|
||||
@@ -220,6 +227,7 @@ describe("runCronIsolatedAgentTurn", () => {
|
||||
deps,
|
||||
job: {
|
||||
...makeJob({ kind: "agentTurn", message: "do it" }),
|
||||
sessionKey: originSessionKey,
|
||||
delivery: { mode: "announce" },
|
||||
},
|
||||
message: "do it",
|
||||
@@ -235,7 +243,7 @@ describe("runCronIsolatedAgentTurn", () => {
|
||||
requesterOrigin?: { channel?: string; to?: string };
|
||||
}
|
||||
| undefined;
|
||||
expect(announceArgs?.requesterSessionKey).toBe("agent:main:main");
|
||||
expect(announceArgs?.requesterSessionKey).toBe(originSessionKey);
|
||||
expect(announceArgs?.requesterOrigin?.channel).toBe("telegram");
|
||||
expect(announceArgs?.requesterOrigin?.to).toBe("123");
|
||||
});
|
||||
|
||||
@@ -128,4 +128,31 @@ describe("resolveDeliveryTarget", () => {
|
||||
|
||||
expect(result.accountId).toBeUndefined();
|
||||
});
|
||||
|
||||
it("prefers origin session context for implicit last-target resolution", async () => {
|
||||
vi.mocked(loadSessionStore).mockReturnValue({
|
||||
"agent:test:main": {
|
||||
sessionId: "main-session",
|
||||
updatedAt: 1000,
|
||||
lastChannel: "telegram",
|
||||
lastTo: "main-target",
|
||||
lastAccountId: "main-account",
|
||||
},
|
||||
"agent:test:bluebubbles:direct:+19257864429": {
|
||||
sessionId: "origin-session",
|
||||
updatedAt: 1001,
|
||||
lastChannel: "telegram",
|
||||
lastTo: "origin-target",
|
||||
lastAccountId: "origin-account",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await resolveDeliveryTarget(makeCfg(), "agent-b", {
|
||||
channel: "last",
|
||||
sessionKey: "agent:test:bluebubbles:direct:+19257864429",
|
||||
});
|
||||
|
||||
expect(result.channel).toBe("telegram");
|
||||
expect(result.accountId).toBe("origin-account");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ export async function resolveDeliveryTarget(
|
||||
jobPayload: {
|
||||
channel?: "last" | ChannelId;
|
||||
to?: string;
|
||||
sessionKey?: string;
|
||||
},
|
||||
): Promise<{
|
||||
channel: Exclude<OutboundChannel, "none">;
|
||||
@@ -32,6 +33,8 @@ export async function resolveDeliveryTarget(
|
||||
}> {
|
||||
const requestedChannel = typeof jobPayload.channel === "string" ? jobPayload.channel : "last";
|
||||
const explicitTo = typeof jobPayload.to === "string" ? jobPayload.to : undefined;
|
||||
const originSessionKey =
|
||||
typeof jobPayload.sessionKey === "string" ? jobPayload.sessionKey.trim() : "";
|
||||
const allowMismatchedLastTo = requestedChannel === "last";
|
||||
|
||||
const sessionCfg = cfg.session;
|
||||
@@ -39,14 +42,32 @@ export async function resolveDeliveryTarget(
|
||||
const storePath = resolveStorePath(sessionCfg?.store, { agentId });
|
||||
const store = loadSessionStore(storePath);
|
||||
const main = store[mainSessionKey];
|
||||
const origin = originSessionKey ? store[originSessionKey] : undefined;
|
||||
|
||||
const preliminary = resolveSessionDeliveryTarget({
|
||||
const preliminaryFromOrigin = origin
|
||||
? resolveSessionDeliveryTarget({
|
||||
entry: origin,
|
||||
requestedChannel,
|
||||
explicitTo,
|
||||
allowMismatchedLastTo,
|
||||
})
|
||||
: undefined;
|
||||
const preliminaryFromMain = resolveSessionDeliveryTarget({
|
||||
entry: main,
|
||||
requestedChannel,
|
||||
explicitTo,
|
||||
allowMismatchedLastTo,
|
||||
});
|
||||
|
||||
const hasResolvedTarget = (value?: { channel?: string; to?: string }) =>
|
||||
Boolean(value?.channel && value?.to);
|
||||
const useMainContext =
|
||||
hasResolvedTarget(preliminaryFromMain) && !hasResolvedTarget(preliminaryFromOrigin);
|
||||
const contextEntry = useMainContext ? main : (origin ?? main);
|
||||
const preliminary = useMainContext
|
||||
? preliminaryFromMain
|
||||
: (preliminaryFromOrigin ?? preliminaryFromMain);
|
||||
|
||||
let fallbackChannel: Exclude<OutboundChannel, "none"> | undefined;
|
||||
if (!preliminary.channel) {
|
||||
try {
|
||||
@@ -59,7 +80,7 @@ export async function resolveDeliveryTarget(
|
||||
|
||||
const resolved = fallbackChannel
|
||||
? resolveSessionDeliveryTarget({
|
||||
entry: main,
|
||||
entry: contextEntry,
|
||||
requestedChannel,
|
||||
explicitTo,
|
||||
fallbackChannel,
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import type { MessagingToolSend } from "../../agents/pi-embedded-messaging.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { AgentDefaultsConfig } from "../../config/types.js";
|
||||
import type { CronJob, CronRunOutcome, CronRunTelemetry } from "../types.js";
|
||||
import {
|
||||
resolveAgentConfig,
|
||||
resolveAgentDir,
|
||||
@@ -24,6 +20,7 @@ import {
|
||||
resolveHooksGmailModel,
|
||||
resolveThinkingDefault,
|
||||
} from "../../agents/model-selection.js";
|
||||
import type { MessagingToolSend } from "../../agents/pi-embedded-messaging.js";
|
||||
import { runEmbeddedPiAgent } from "../../agents/pi-embedded.js";
|
||||
import { runSubagentAnnounceFlow } from "../../agents/subagent-announce.js";
|
||||
import { countActiveDescendantRuns } from "../../agents/subagent-registry.js";
|
||||
@@ -37,11 +34,13 @@ import {
|
||||
} from "../../auto-reply/thinking.js";
|
||||
import { SILENT_REPLY_TOKEN } from "../../auto-reply/tokens.js";
|
||||
import { createOutboundSendDeps, type CliDeps } from "../../cli/outbound-send-deps.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import {
|
||||
resolveAgentMainSessionKey,
|
||||
resolveSessionTranscriptPath,
|
||||
updateSessionStore,
|
||||
} from "../../config/sessions.js";
|
||||
import type { AgentDefaultsConfig } from "../../config/types.js";
|
||||
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
||||
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
|
||||
import { resolveAgentOutboundIdentity } from "../../infra/outbound/identity.js";
|
||||
@@ -55,6 +54,7 @@ import {
|
||||
isExternalHookSession,
|
||||
} from "../../security/external-content.js";
|
||||
import { resolveCronDeliveryPlan } from "../delivery.js";
|
||||
import type { CronJob, CronRunOutcome, CronRunTelemetry } from "../types.js";
|
||||
import { resolveDeliveryTarget } from "./delivery-target.js";
|
||||
import {
|
||||
isHeartbeatOnlyResponse,
|
||||
@@ -368,10 +368,17 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
const agentPayload = params.job.payload.kind === "agentTurn" ? params.job.payload : null;
|
||||
const deliveryPlan = resolveCronDeliveryPlan(params.job);
|
||||
const deliveryRequested = deliveryPlan.requested;
|
||||
const cronOriginSessionKey =
|
||||
params.job.sessionKey?.trim() ||
|
||||
resolveAgentMainSessionKey({
|
||||
cfg: params.cfg,
|
||||
agentId,
|
||||
});
|
||||
|
||||
const resolvedDelivery = await resolveDeliveryTarget(cfgWithAgentDefaults, agentId, {
|
||||
channel: deliveryPlan.channel ?? "last",
|
||||
to: deliveryPlan.to,
|
||||
sessionKey: cronOriginSessionKey,
|
||||
});
|
||||
|
||||
const { formattedTime, timeLine } = resolveCronStyleNow(params.cfg, now);
|
||||
@@ -667,10 +674,6 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
}
|
||||
}
|
||||
} else if (synthesizedText) {
|
||||
const announceMainSessionKey = resolveAgentMainSessionKey({
|
||||
cfg: params.cfg,
|
||||
agentId,
|
||||
});
|
||||
const announceUsesPinnedTarget = hasPinnedCronAnnounceTarget({
|
||||
channel: deliveryPlan.channel,
|
||||
to: deliveryPlan.to,
|
||||
@@ -679,7 +682,7 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
? await resolveCronAnnounceSessionKey({
|
||||
cfg: cfgWithAgentDefaults,
|
||||
agentId,
|
||||
fallbackSessionKey: announceMainSessionKey,
|
||||
fallbackSessionKey: cronOriginSessionKey,
|
||||
delivery: {
|
||||
channel: resolvedDelivery.channel,
|
||||
to: resolvedDelivery.to,
|
||||
@@ -687,7 +690,7 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
threadId: resolvedDelivery.threadId,
|
||||
},
|
||||
})
|
||||
: announceMainSessionKey;
|
||||
: cronOriginSessionKey;
|
||||
const taskLabel =
|
||||
typeof params.job.name === "string" && params.job.name.trim()
|
||||
? params.job.name.trim()
|
||||
|
||||
Reference in New Issue
Block a user