Skip to content

Commit f12b845

Browse files
committed
fix(cron): preserve isolated delivery awareness policy
1 parent 64c4462 commit f12b845

2 files changed

Lines changed: 37 additions & 7 deletions

File tree

src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,18 @@ describe("dispatchCronDelivery — double-announce guard", () => {
459459
});
460460

461461
it("applies TTS directives before direct cron announce delivery and mirrors spoken text", async () => {
462+
vi.mocked(deliverOutboundPayloads).mockImplementationOnce(async (deliveryParams) => {
463+
deliveryParams.onPayload?.({
464+
text: "Morning briefing complete.",
465+
mediaUrls: [
466+
"file:///tmp/chart.png",
467+
"file:///tmp/narration.ogg",
468+
"file:///tmp/cron-tts.mp3",
469+
],
470+
audioAsVoice: true,
471+
});
472+
return [{ ok: true } as never];
473+
});
462474
maybeApplyTtsToPayloadMock.mockImplementation(async (params: { payload: unknown }) => {
463475
const payload = params.payload as { text?: string };
464476
expect(payload.text).toBe("[[tts]] Morning briefing complete.");
@@ -637,14 +649,14 @@ describe("dispatchCronDelivery — double-announce guard", () => {
637649
);
638650
});
639651

640-
it("keeps media filenames in main-session awareness before suppressing the mirror", async () => {
652+
it("keeps effective media-only payloads in main-session awareness before suppressing the mirror", async () => {
641653
mockResolvedOutboundRoute({
642654
sessionKey: "agent:main:main",
643655
baseSessionKey: "agent:main:main",
644656
});
645657
vi.mocked(deliverOutboundPayloads).mockImplementationOnce(async (params) => {
646658
params.onPayload?.({
647-
text: "Main session briefing.",
659+
text: "",
648660
mediaUrls: ["https://example.com/main-chart.png"],
649661
});
650662
return [{ channel: "telegram", messageId: "tg-main-media" }];
@@ -663,7 +675,7 @@ describe("dispatchCronDelivery — double-announce guard", () => {
663675
expect(state.result).toBeUndefined();
664676
expect(state.delivered).toBe(true);
665677
expect(appendAssistantMessageToSessionTranscript).not.toHaveBeenCalled();
666-
expect(enqueueSystemEvent).toHaveBeenCalledWith("Main session briefing.\nmain-chart.png", {
678+
expect(enqueueSystemEvent).toHaveBeenCalledWith("main-chart.png", {
667679
sessionKey: "agent:main:main",
668680
contextKey: "cron-direct-delivery:v1:cron:test-job:1000:telegram::123456:",
669681
forceSenderIsOwnerFalse: true,
@@ -814,6 +826,10 @@ describe("dispatchCronDelivery — double-announce guard", () => {
814826
});
815827

816828
it("skips main-session awareness for isolated cron jobs with implicit delivery targets", async () => {
829+
mockResolvedOutboundRoute({
830+
sessionKey: "agent:main:main",
831+
baseSessionKey: "agent:main:main",
832+
});
817833
const params = makeBaseParams({
818834
synthesizedText: "Implicit cron update.",
819835
resolvedDeliveryMode: "implicit",
@@ -825,6 +841,7 @@ describe("dispatchCronDelivery — double-announce guard", () => {
825841
expect(state.deliveryAttempted).toBe(true);
826842
expect(deliverOutboundPayloads).toHaveBeenCalledTimes(1);
827843
expect(enqueueSystemEvent).not.toHaveBeenCalled();
844+
expect(appendAssistantMessageToSessionTranscript).not.toHaveBeenCalled();
828845
});
829846

830847
it("skips awareness text when direct delivery strips a silent caption", async () => {

src/cron/isolated-agent/delivery-dispatch.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,9 @@ function resolveCronAwarenessText(params: {
429429
}): string | undefined {
430430
if (params.outboundPayloads?.length) {
431431
const projection = projectDeliveredDirectCronPayloadsForMirror(params.outboundPayloads);
432-
if (normalizeOptionalString(projection.text)) {
433-
return resolveDirectCronTranscriptMirrorText(projection);
432+
const projectedText = resolveDirectCronTranscriptMirrorText(projection);
433+
if (projectedText) {
434+
return projectedText;
434435
}
435436
}
436437
return params.deliveryPayloads
@@ -525,7 +526,10 @@ function isTtsAudioMirrorOnly(params: {
525526
payload: NormalizedOutboundPayload;
526527
mediaUrl: string;
527528
}): boolean {
528-
return !!params.payload.hookContent && isAudioFileName(params.mediaUrl);
529+
return (
530+
(params.payload.audioAsVoice === true || !!params.payload.hookContent) &&
531+
isAudioFileName(params.mediaUrl)
532+
);
529533
}
530534

531535
function projectDeliveredDirectCronPayloadsForMirror(
@@ -1007,7 +1011,16 @@ export async function dispatchCronDelivery(
10071011
: undefined;
10081012
const deliveryWillReachAwarenessMainSession =
10091013
mirrorTargetsAwarenessMainSession && shouldQueueAwarenessForDelivery && !!awarenessText;
1010-
if (delivered && !deliveryWillReachAwarenessMainSession) {
1014+
// Implicit/default isolated delivery must not create main-session awareness.
1015+
const mirrorWouldBypassIsolatedAwarenessPolicy =
1016+
mirrorTargetsAwarenessMainSession &&
1017+
params.job.sessionTarget === "isolated" &&
1018+
delivery.mode !== "explicit";
1019+
if (
1020+
delivered &&
1021+
!deliveryWillReachAwarenessMainSession &&
1022+
!mirrorWouldBypassIsolatedAwarenessPolicy
1023+
) {
10111024
const mirrorProjection =
10121025
attemptedPayloadsForMirror.length > 0
10131026
? projectDeliveredDirectCronPayloadsForMirror(attemptedPayloadsForMirror)

0 commit comments

Comments
 (0)