






















@@ -404,8 +404,122 @@ describe("buildGatewayCronService", () => {
404404reason: "cron:test",
405405agentId: "main",
406406sessionKey: "agent:main:discord:channel:ops",
407+heartbeat: { target: "last", to: undefined, accountId: undefined },
408+});
409+} finally {
410+state.cron.stop();
411+}
412+});
413+414+it("does not inherit explicit heartbeat destinations for direct target-last wakes", async () => {
415+const cfg = {
416+ ...createCronConfig("server-cron-direct-heartbeat-route"),
417+agents: {
418+defaults: {
419+heartbeat: {
420+every: "1h",
421+prompt: "Default heartbeat prompt",
422+target: "none",
423+directPolicy: "block",
424+to: "telegram:dm",
425+accountId: "default",
426+},
427+},
428+},
429+} as OpenClawConfig;
430+loadConfigMock.mockReturnValue(cfg);
431+432+const state = buildGatewayCronService({
433+ cfg,
434+deps: {} as CliDeps,
435+broadcast: () => {},
436+});
437+try {
438+const cronDeps = (
439+state.cron as unknown as {
440+state?: {
441+deps?: {
442+runHeartbeatOnce?: (opts?: {
443+agentId?: string;
444+sessionKey?: string | null;
445+reason?: string;
446+heartbeat?: { target?: string };
447+}) => Promise<unknown>;
448+};
449+};
450+}
451+).state?.deps;
452+453+await cronDeps?.runHeartbeatOnce?.({
454+reason: "cron:test",
455+sessionKey: "telegram:group:123:topic:456",
407456heartbeat: { target: "last" },
408457});
458+459+const call = requireRecord(
460+callArg(runHeartbeatOnceMock, 0, 0, "heartbeat run options"),
461+"heartbeat run options",
462+);
463+expect(call.sessionKey).toBe("agent:main:telegram:group:123:topic:456");
464+expect(call.heartbeat).toEqual({
465+every: "1h",
466+prompt: "Default heartbeat prompt",
467+target: "last",
468+directPolicy: "block",
469+to: undefined,
470+accountId: undefined,
471+});
472+} finally {
473+state.cron.stop();
474+}
475+});
476+477+it("does not inherit explicit heartbeat destinations for queued target-last wakes", async () => {
478+const cfg = {
479+ ...createCronConfig("server-cron-queued-heartbeat-route"),
480+agents: {
481+defaults: {
482+heartbeat: {
483+every: "1h",
484+prompt: "Default heartbeat prompt",
485+target: "none",
486+directPolicy: "block",
487+to: "telegram:dm",
488+accountId: "default",
489+},
490+},
491+},
492+} as OpenClawConfig;
493+loadConfigMock.mockReturnValue(cfg);
494+495+const state = buildGatewayCronService({
496+ cfg,
497+deps: {} as CliDeps,
498+broadcast: () => {},
499+});
500+try {
501+const job = await state.cron.add({
502+name: "queued-heartbeat-route",
503+enabled: true,
504+schedule: { kind: "at", at: new Date(1).toISOString() },
505+sessionTarget: "main",
506+wakeMode: "next-heartbeat",
507+sessionKey: "telegram:group:123:topic:456",
508+payload: { kind: "systemEvent", text: "hello" },
509+});
510+511+await state.cron.run(job.id, "force");
512+513+const call = requireRecord(
514+callArg(requestHeartbeatMock, 0, 0, "heartbeat request"),
515+"heartbeat request",
516+);
517+expect(call.sessionKey).toBe("agent:main:telegram:group:123:topic:456");
518+expect(call.heartbeat).toEqual({
519+target: "last",
520+to: undefined,
521+accountId: undefined,
522+});
409523} finally {
410524state.cron.stop();
411525}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。