refactor(runtime): remove deprecated timing aliases

This commit is contained in:
Peter Steinberger
2026-07-13 04:40:52 +01:00
parent 3302c3f5f9
commit 4638b06454
10 changed files with 26 additions and 102 deletions

View File

@@ -402,7 +402,6 @@ type EmbeddedAgentParams = {
tool?: string;
toolCallId?: string;
itemId?: string;
firstModelCallStarted?: boolean;
}) => void;
onBlockReply?: (payload: { text?: string; mediaUrls?: string[] }) => Promise<void> | void;
onPartialReply?: (payload: { text?: string; mediaUrls?: string[] }) => Promise<void> | void;
@@ -1718,7 +1717,6 @@ describe("runAgentTurnWithFallback", () => {
phase: "model_call_started",
provider: "openai",
model: "gpt-5.4",
firstModelCallStarted: true,
});
return { payloads: [{ text: "final" }], meta: {} };
});

View File

@@ -194,7 +194,6 @@ describe("runCronIsolatedAgentTurn — cron model override forwarding (#58065)",
phase: "model_call_started",
provider: "google",
model: "gemini-2.0-flash",
firstModelCallStarted: true,
});
return {
payloads: [{ text: "summary done" }],
@@ -216,7 +215,6 @@ describe("runCronIsolatedAgentTurn — cron model override forwarding (#58065)",
phase: "model_call_started",
provider: "google",
model: "gemini-2.0-flash",
firstModelCallStarted: true,
}),
).toBe(true);
});
@@ -258,7 +256,6 @@ describe("runCronIsolatedAgentTurn — cron model override forwarding (#58065)",
phase: "model_call_started",
provider: "google",
model: "gemini-2.0-flash",
firstModelCallStarted: true,
});
return {
payloads: [{ text: "summary done" }],
@@ -278,7 +275,6 @@ describe("runCronIsolatedAgentTurn — cron model override forwarding (#58065)",
expect(
hasPhaseWithFields(phases, {
phase: "model_call_started",
firstModelCallStarted: true,
}),
).toBe(false);
@@ -302,7 +298,6 @@ describe("runCronIsolatedAgentTurn — cron model override forwarding (#58065)",
expect(
hasPhaseWithFields(phases, {
phase: "model_call_started",
firstModelCallStarted: true,
}),
).toBe(true);
});

View File

@@ -129,7 +129,7 @@ export function createCronAgentWatchdog(params: {
startPreExecutionTimeout();
return;
}
if (stage === "execution" || info.firstModelCallStarted) {
if (stage === "execution") {
state = "executing";
clearPreExecutionTimeout();
}

View File

@@ -212,8 +212,6 @@ export type CronAgentExecutionStarted = {
tool?: string;
toolCallId?: string;
itemId?: string;
/** @deprecated Use phase-specific execution milestones for watchdog progress. */
firstModelCallStarted?: boolean;
};
/** Watchdog update that requires the new execution phase. */

View File

@@ -62,8 +62,8 @@ function startDefaultMonitor(
return startChannelHealthMonitor({
channelManager: manager,
checkIntervalMs: DEFAULT_CHECK_INTERVAL_MS,
startupGraceMs: 0,
...overrides,
timing: { monitorStartupGraceMs: 0, ...overrides.timing },
});
}
@@ -72,7 +72,7 @@ async function startAndRunCheck(
overrides: Partial<Omit<Parameters<typeof startChannelHealthMonitor>[0], "channelManager">> = {},
) {
const monitor = startDefaultMonitor(manager, overrides);
const startupGraceMs = overrides.timing?.monitorStartupGraceMs ?? overrides.startupGraceMs ?? 0;
const startupGraceMs = overrides.timing?.monitorStartupGraceMs ?? 0;
const checkIntervalMs = overrides.checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS;
await vi.advanceTimersByTimeAsync(startupGraceMs + checkIntervalMs + 1);
return monitor;
@@ -201,7 +201,7 @@ describe("channel-health-monitor", () => {
it("does not run before the grace period", async () => {
const manager = createMockChannelManager();
const monitor = startDefaultMonitor(manager, { startupGraceMs: 60_000 });
const monitor = startDefaultMonitor(manager, { timing: { monitorStartupGraceMs: 60_000 } });
await vi.advanceTimersByTimeAsync(5_001);
expect(manager.getRuntimeSnapshot).not.toHaveBeenCalled();
monitor.stop();
@@ -209,7 +209,9 @@ describe("channel-health-monitor", () => {
it("runs health check after grace period", async () => {
const manager = createMockChannelManager();
const monitor = await startAndRunCheck(manager, { startupGraceMs: 1_000 });
const monitor = await startAndRunCheck(manager, {
timing: { monitorStartupGraceMs: 1_000 },
});
expect(manager.getRuntimeSnapshot).toHaveBeenCalled();
monitor.stop();
});
@@ -456,7 +458,9 @@ describe("channel-health-monitor", () => {
},
},
});
const monitor = await startAndRunCheck(manager, { channelStartupGraceMs: 60_000 });
const monitor = await startAndRunCheck(manager, {
timing: { channelConnectGraceMs: 60_000 },
});
expect(manager.stopChannel).not.toHaveBeenCalled();
expect(manager.startChannel).not.toHaveBeenCalled();
monitor.stop();
@@ -845,7 +849,7 @@ describe("channel-health-monitor", () => {
}),
);
const monitor = await startAndRunCheck(manager, {
staleEventThresholdMs: customThreshold,
timing: { staleEventThresholdMs: customThreshold },
});
expect(manager.stopChannel).toHaveBeenCalledWith("slack", "default", { manual: false });
expect(manager.startChannel).toHaveBeenCalledWith("slack", "default");

View File

@@ -36,12 +36,6 @@ type ChannelHealthTimingPolicy = {
type ChannelHealthMonitorDeps = {
channelManager: ChannelManager;
checkIntervalMs?: number;
/** @deprecated use timing.monitorStartupGraceMs */
startupGraceMs?: number;
/** @deprecated use timing.channelConnectGraceMs */
channelStartupGraceMs?: number;
/** @deprecated use timing.staleEventThresholdMs */
staleEventThresholdMs?: number;
timing?: Partial<ChannelHealthTimingPolicy>;
cooldownCycles?: number;
maxRestartsPerHour?: number;
@@ -60,22 +54,15 @@ type RestartRecord = {
};
function resolveTimingPolicy(
deps: Pick<
ChannelHealthMonitorDeps,
"startupGraceMs" | "channelStartupGraceMs" | "staleEventThresholdMs" | "timing"
>,
deps: Pick<ChannelHealthMonitorDeps, "timing">,
): ChannelHealthTimingPolicy {
return {
monitorStartupGraceMs:
deps.timing?.monitorStartupGraceMs ?? deps.startupGraceMs ?? DEFAULT_MONITOR_STARTUP_GRACE_MS,
deps.timing?.monitorStartupGraceMs ?? DEFAULT_MONITOR_STARTUP_GRACE_MS,
channelConnectGraceMs:
deps.timing?.channelConnectGraceMs ??
deps.channelStartupGraceMs ??
DEFAULT_CHANNEL_CONNECT_GRACE_MS,
deps.timing?.channelConnectGraceMs ?? DEFAULT_CHANNEL_CONNECT_GRACE_MS,
staleEventThresholdMs:
deps.timing?.staleEventThresholdMs ??
deps.staleEventThresholdMs ??
DEFAULT_CHANNEL_STALE_EVENT_THRESHOLD_MS,
deps.timing?.staleEventThresholdMs ?? DEFAULT_CHANNEL_STALE_EVENT_THRESHOLD_MS,
};
}

View File

@@ -30,7 +30,7 @@ export function startGatewayChannelHealthMonitor(params: {
channelManager: params.channelManager,
checkIntervalMs: (healthCheckMinutes ?? 5) * 60_000,
...(staleEventThresholdMinutes != null && {
staleEventThresholdMs: staleEventThresholdMinutes * 60_000,
timing: { staleEventThresholdMs: staleEventThresholdMinutes * 60_000 },
}),
...(maxRestartsPerHour != null && { maxRestartsPerHour }),
});

View File

@@ -9,7 +9,7 @@ import { type LogLevel, normalizeLogLevel } from "./levels.js";
import { getLogger } from "./logger.js";
import { redactSensitiveText } from "./redact.js";
import { loggingState } from "./state.js";
import { formatLocalIsoWithOffset, formatTimestamp } from "./timestamps.js";
import { formatTimestamp } from "./timestamps.js";
import type { ConsoleStyle, LoggerSettings } from "./types.js";
export type { ConsoleStyle } from "./types.js";
@@ -182,7 +182,7 @@ export function formatConsoleTimestamp(style: ConsoleStyle): string {
if (style === "pretty") {
return formatTimestamp(now, { style: "short" }).replace(/[+-]\d{2}:\d{2}$/, "");
}
return formatLocalIsoWithOffset(now);
return formatTimestamp(now, { style: "long" });
}
function hasTimestampPrefix(value: string): boolean {

View File

@@ -1,55 +1,6 @@
// Timestamp tests cover timezone validation and timestamp formatting.
import * as fs from "node:fs";
import * as path from "node:path";
import { describe, expect, it } from "vitest";
import { formatLocalIsoWithOffset, formatTimestamp, isValidTimeZone } from "./timestamps.js";
describe("formatLocalIsoWithOffset", () => {
const testDate = new Date("2025-01-01T04:00:00.000Z");
it("produces +00:00 offset for UTC", () => {
const result = formatLocalIsoWithOffset(testDate, "UTC");
expect(result).toBe("2025-01-01T04:00:00.000+00:00");
});
it("produces +08:00 offset for Asia/Shanghai", () => {
const result = formatLocalIsoWithOffset(testDate, "Asia/Shanghai");
expect(result).toBe("2025-01-01T12:00:00.000+08:00");
});
it("produces correct offset for America/New_York", () => {
const result = formatLocalIsoWithOffset(testDate, "America/New_York");
// January is EST = UTC-5
expect(result).toBe("2024-12-31T23:00:00.000-05:00");
});
it("produces correct offset for America/New_York in summer (EDT)", () => {
const summerDate = new Date("2025-07-01T12:00:00.000Z");
const result = formatLocalIsoWithOffset(summerDate, "America/New_York");
// July is EDT = UTC-4
expect(result).toBe("2025-07-01T08:00:00.000-04:00");
});
it("outputs a valid ISO 8601 string with offset", () => {
const result = formatLocalIsoWithOffset(testDate, "Asia/Shanghai");
// ISO 8601 with offset: YYYY-MM-DDTHH:MM:SS.mmm±HH:MM
const iso8601WithOffset = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{2}:\d{2}$/;
expect(result).toMatch(iso8601WithOffset);
});
it("falls back gracefully for an invalid timezone", () => {
const result = formatLocalIsoWithOffset(testDate, "not-a-tz");
const iso8601WithOffset = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{2}:\d{2}$/;
expect(result).toMatch(iso8601WithOffset);
});
it("does NOT use getHours, getMinutes, getTimezoneOffset in the implementation", () => {
const source = fs.readFileSync(path.resolve(__dirname, "timestamps.ts"), "utf-8");
expect(source).not.toMatch(/\.getHours\s*\(/);
expect(source).not.toMatch(/\.getMinutes\s*\(/);
expect(source).not.toMatch(/\.getTimezoneOffset\s*\(/);
});
});
import { formatTimestamp, isValidTimeZone } from "./timestamps.js";
describe("formatTimestamp", () => {
const testDate = new Date("2024-01-15T14:30:45.123Z");
@@ -64,14 +15,13 @@ describe("formatTimestamp", () => {
);
});
it.each(["UTC", "America/New_York", "Europe/Paris"])(
"matches formatLocalIsoWithOffset for long style in %s",
(timeZone) => {
expect(formatTimestamp(testDate, { style: "long", timeZone })).toBe(
formatLocalIsoWithOffset(testDate, timeZone),
);
},
);
it.each([
["UTC", "2024-01-15T14:30:45.123+00:00"],
["America/New_York", "2024-01-15T09:30:45.123-05:00"],
["Europe/Paris", "2024-01-15T15:30:45.123+01:00"],
])("formats long style in %s", (timeZone, expected) => {
expect(formatTimestamp(testDate, { style: "long", timeZone })).toBe(expected);
});
it("falls back to a valid offset when the timezone is invalid", () => {
expect(formatTimestamp(testDate, { style: "short", timeZone: "not-a-tz" })).toMatch(

View File

@@ -85,11 +85,3 @@ export function formatTimestamp(date: Date, options?: FormatTimestampOptions): s
}
throw new Error("Unsupported timestamp style");
}
/**
* @deprecated Use formatTimestamp from "./timestamps.js" instead.
* This function will be removed in a future version.
*/
export function formatLocalIsoWithOffset(now: Date, timeZone?: string): string {
return formatTimestamp(now, { style: "long", timeZone });
}