feat: mirror delivered outbound messages (#1031)

Co-authored-by: T Savo <TSavo@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-01-17 01:48:02 +00:00
parent 3fb699a84b
commit fdaeada3ec
26 changed files with 697 additions and 29 deletions

View File

@@ -25,6 +25,14 @@ export function pickSummaryFromPayloads(payloads: Array<{ text?: string | undefi
return undefined;
}
export function pickLastNonEmptyTextFromPayloads(payloads: Array<{ text?: string | undefined }>) {
for (let i = payloads.length - 1; i >= 0; i--) {
const clean = (payloads[i]?.text ?? "").trim();
if (clean) return clean;
}
return undefined;
}
/**
* Check if all payloads are just heartbeat ack responses (HEARTBEAT_OK).
* Returns true if delivery should be skipped because there's no real content.

View File

@@ -41,6 +41,7 @@ import type { CronJob } from "../types.js";
import { resolveDeliveryTarget } from "./delivery-target.js";
import {
isHeartbeatOnlyResponse,
pickLastNonEmptyTextFromPayloads,
pickSummaryFromOutput,
pickSummaryFromPayloads,
resolveHeartbeatAckMaxChars,
@@ -50,6 +51,8 @@ import { resolveCronSession } from "./session.js";
export type RunCronAgentTurnResult = {
status: "ok" | "error" | "skipped";
summary?: string;
/** Last non-empty agent text output (not truncated). */
outputText?: string;
error?: string;
};
@@ -333,6 +336,7 @@ export async function runCronIsolatedAgentTurn(params: {
}
const firstText = payloads[0]?.text ?? "";
const summary = pickSummaryFromPayloads(payloads) ?? pickSummaryFromOutput(firstText);
const outputText = pickLastNonEmptyTextFromPayloads(payloads);
// Skip delivery for heartbeat-only responses (HEARTBEAT_OK with no real content).
const ackMaxChars = resolveHeartbeatAckMaxChars(agentCfg);
@@ -346,12 +350,14 @@ export async function runCronIsolatedAgentTurn(params: {
return {
status: "error",
summary,
outputText,
error: reason,
};
}
return {
status: "skipped",
summary: `Delivery skipped (${reason}).`,
outputText,
};
}
try {
@@ -366,11 +372,11 @@ export async function runCronIsolatedAgentTurn(params: {
});
} catch (err) {
if (!bestEffortDeliver) {
return { status: "error", summary, error: String(err) };
return { status: "error", summary, outputText, error: String(err) };
}
return { status: "ok", summary };
return { status: "ok", summary, outputText };
}
}
return { status: "ok", summary };
return { status: "ok", summary, outputText };
}