feat: expose runtime version in gateway status

This commit is contained in:
Peter Steinberger
2026-03-12 02:55:25 +00:00
parent e95f2dcd6e
commit 5ca780fa78
6 changed files with 94 additions and 0 deletions

View File

@@ -22,6 +22,7 @@ function createRecentSessionRow() {
describe("redactSensitiveStatusSummary", () => {
it("removes sensitive session and path details while preserving summary structure", () => {
const input: StatusSummary = {
runtimeVersion: "2026.3.8",
heartbeat: {
defaultAgentId: "main",
agents: [{ agentId: "main", enabled: true, every: "5m", everyMs: 300_000 }],
@@ -50,6 +51,7 @@ describe("redactSensitiveStatusSummary", () => {
expect(redacted.sessions.recent).toEqual([]);
expect(redacted.sessions.byAgent[0]?.path).toBe("[redacted]");
expect(redacted.sessions.byAgent[0]?.recent).toEqual([]);
expect(redacted.runtimeVersion).toBe("2026.3.8");
expect(redacted.heartbeat).toEqual(input.heartbeat);
expect(redacted.channelSummary).toEqual(input.channelSummary);
});

View File

@@ -0,0 +1,85 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("../agents/context.js", () => ({
resolveContextTokensForModel: vi.fn(() => 200_000),
}));
vi.mock("../agents/defaults.js", () => ({
DEFAULT_CONTEXT_TOKENS: 200_000,
DEFAULT_MODEL: "gpt-5.2",
DEFAULT_PROVIDER: "openai",
}));
vi.mock("../agents/model-selection.js", () => ({
resolveConfiguredModelRef: vi.fn(() => ({
provider: "openai",
model: "gpt-5.2",
})),
}));
vi.mock("../config/config.js", () => ({
loadConfig: vi.fn(() => ({})),
}));
vi.mock("../config/sessions.js", () => ({
loadSessionStore: vi.fn(() => ({})),
resolveFreshSessionTotalTokens: vi.fn(() => undefined),
resolveMainSessionKey: vi.fn(() => "main"),
resolveStorePath: vi.fn(() => "/tmp/sessions.json"),
}));
vi.mock("../gateway/session-utils.js", () => ({
classifySessionKey: vi.fn(() => "direct"),
listAgentsForGateway: vi.fn(() => ({
defaultId: "main",
agents: [{ id: "main" }],
})),
resolveSessionModelRef: vi.fn(() => ({
provider: "openai",
model: "gpt-5.2",
})),
}));
vi.mock("../infra/channel-summary.js", () => ({
buildChannelSummary: vi.fn(async () => ["ok"]),
}));
vi.mock("../infra/heartbeat-runner.js", () => ({
resolveHeartbeatSummaryForAgent: vi.fn(() => ({
enabled: true,
every: "5m",
everyMs: 300_000,
})),
}));
vi.mock("../infra/system-events.js", () => ({
peekSystemEvents: vi.fn(() => []),
}));
vi.mock("../routing/session-key.js", () => ({
parseAgentSessionKey: vi.fn(() => null),
}));
vi.mock("../version.js", () => ({
resolveRuntimeServiceVersion: vi.fn(() => "2026.3.8"),
}));
vi.mock("./status.link-channel.js", () => ({
resolveLinkChannelContext: vi.fn(async () => undefined),
}));
describe("getStatusSummary", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("includes runtimeVersion in the status payload", async () => {
const { getStatusSummary } = await import("./status.summary.js");
const summary = await getStatusSummary();
expect(summary.runtimeVersion).toBe("2026.3.8");
expect(summary.heartbeat.defaultAgentId).toBe("main");
expect(summary.channelSummary).toEqual(["ok"]);
});
});

View File

@@ -19,6 +19,7 @@ import { buildChannelSummary } from "../infra/channel-summary.js";
import { resolveHeartbeatSummaryForAgent } from "../infra/heartbeat-runner.js";
import { peekSystemEvents } from "../infra/system-events.js";
import { parseAgentSessionKey } from "../routing/session-key.js";
import { resolveRuntimeServiceVersion } from "../version.js";
import { resolveLinkChannelContext } from "./status.link-channel.js";
import type { HeartbeatStatus, SessionStatus, StatusSummary } from "./status.types.js";
@@ -210,6 +211,7 @@ export async function getStatusSummary(
const totalSessions = allSessions.length;
const summary: StatusSummary = {
runtimeVersion: resolveRuntimeServiceVersion(process.env),
linkChannel: linkContext
? {
id: linkContext.plugin.id,

View File

@@ -34,6 +34,7 @@ export type HeartbeatStatus = {
};
export type StatusSummary = {
runtimeVersion?: string | null;
linkChannel?: {
id: ChannelId;
label: string;

View File

@@ -6,6 +6,9 @@ import type { GatewayStatusSummary } from "./tui-types.js";
export function formatStatusSummary(summary: GatewayStatusSummary) {
const lines: string[] = [];
lines.push("Gateway status");
if (summary.runtimeVersion) {
lines.push(`Version: ${summary.runtimeVersion}`);
}
if (!summary.linkChannel) {
lines.push("Link channel: unknown");

View File

@@ -49,6 +49,7 @@ export type AgentSummary = {
};
export type GatewayStatusSummary = {
runtimeVersion?: string | null;
linkChannel?: {
id?: string;
label?: string;