refactor: dedupe telemetry string readers

This commit is contained in:
Peter Steinberger
2026-04-07 04:43:53 +01:00
parent 8c7dd66a7b
commit b059328f60
14 changed files with 67 additions and 66 deletions

View File

@@ -11,6 +11,7 @@ import {
parseAgentSessionKey,
resolveAgentIdFromSessionKey,
} from "../routing/session-key.js";
import { readStringValue } from "../shared/string-coerce.js";
import { resolveUserPath } from "../utils.js";
import { resolveEffectiveAgentSkillFilter } from "./skills/agent-filter.js";
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
@@ -137,9 +138,9 @@ export function resolveAgentConfig(
}
const agentDefaults = cfg.agents?.defaults;
return {
name: typeof entry.name === "string" ? entry.name : undefined,
workspace: typeof entry.workspace === "string" ? entry.workspace : undefined,
agentDir: typeof entry.agentDir === "string" ? entry.agentDir : undefined,
name: readStringValue(entry.name),
workspace: readStringValue(entry.workspace),
agentDir: readStringValue(entry.agentDir),
model:
typeof entry.model === "string" || (entry.model && typeof entry.model === "object")
? entry.model

View File

@@ -1,4 +1,5 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { readStringValue } from "../shared/string-coerce.js";
import { extractToolCallsFromAssistant, extractToolResultId } from "./tool-call-id.js";
const TOOL_CALL_NAME_MAX_CHARS = 64;
@@ -96,7 +97,7 @@ function redactSessionsSpawnAttachmentsArgs(value: unknown): unknown {
}
function sanitizeToolCallBlock(block: RawToolCallBlock): RawToolCallBlock {
const rawName = typeof block.name === "string" ? block.name : undefined;
const rawName = readStringValue(block.name);
const trimmedName = rawName?.trim();
const hasTrimmedName = typeof trimmedName === "string" && trimmedName.length > 0;
const normalizedName = hasTrimmedName ? trimmedName : undefined;

View File

@@ -2,6 +2,7 @@ import os from "node:os";
import path from "node:path";
import { resolveStateDir } from "../config/paths.js";
import { loadJsonFile, saveJsonFile } from "../infra/json-file.js";
import { readStringValue } from "../shared/string-coerce.js";
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
import type { SubagentRunRecord } from "./subagent-registry.types.js";
@@ -84,9 +85,8 @@ export function loadSubagentRegistryFromDisk(): Map<string, SubagentRunRecord> {
: undefined;
const requesterOrigin = normalizeDeliveryContext(
typed.requesterOrigin ?? {
channel: typeof typed.requesterChannel === "string" ? typed.requesterChannel : undefined,
accountId:
typeof typed.requesterAccountId === "string" ? typed.requesterAccountId : undefined,
channel: readStringValue(typed.requesterChannel),
accountId: readStringValue(typed.requesterAccountId),
},
);
const {

View File

@@ -11,6 +11,7 @@ import {
} from "../../infra/restart-sentinel.js";
import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { readStringValue } from "../../shared/string-coerce.js";
import { stringEnum } from "../schema/typebox.js";
import { type AnyAgentTool, jsonResult, readStringParam } from "./common.js";
import { callGatewayTool, readGatewayCallOptions } from "./gateway.js";
@@ -27,8 +28,8 @@ function resolveBaseHashFromSnapshot(snapshot: unknown): string | undefined {
const hashValue = (snapshot as { hash?: unknown }).hash;
const rawValue = (snapshot as { raw?: unknown }).raw;
const hash = resolveConfigSnapshotHash({
hash: typeof hashValue === "string" ? hashValue : undefined,
raw: typeof rawValue === "string" ? rawValue : undefined,
hash: readStringValue(hashValue),
raw: readStringValue(rawValue),
});
return hash ?? undefined;
}

View File

@@ -4,6 +4,7 @@ import { callGateway } from "../../gateway/call.js";
import { capArrayByJsonBytes } from "../../gateway/session-utils.fs.js";
import { jsonUtf8Bytes } from "../../infra/json-utf8-bytes.js";
import { redactSensitiveText } from "../../logging/redact.js";
import { readStringValue } from "../../shared/string-coerce.js";
import { truncateUtf16Safe } from "../../utils.js";
import {
describeSessionsHistoryTool,
@@ -87,7 +88,7 @@ function sanitizeHistoryContentBlock(block: unknown): {
redacted ||= res.redacted;
}
if (type === "image") {
const data = typeof entry.data === "string" ? entry.data : undefined;
const data = readStringValue(entry.data);
const bytes = data ? data.length : undefined;
if ("data" in entry) {
delete entry.data;

View File

@@ -8,6 +8,7 @@ import {
} from "../../config/sessions.js";
import { callGateway } from "../../gateway/call.js";
import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
import { readStringValue } from "../../shared/string-coerce.js";
import {
describeSessionsListTool,
SESSIONS_LIST_TOOL_DISPLAY_SUMMARY,
@@ -152,23 +153,17 @@ export function createSessionsListTool(opts?: {
entry.deliveryContext && typeof entry.deliveryContext === "object"
? (entry.deliveryContext as Record<string, unknown>)
: undefined;
const deliveryChannel =
typeof deliveryContext?.channel === "string" ? deliveryContext.channel : undefined;
const deliveryTo = typeof deliveryContext?.to === "string" ? deliveryContext.to : undefined;
const deliveryAccountId =
typeof deliveryContext?.accountId === "string" ? deliveryContext.accountId : undefined;
const deliveryChannel = readStringValue(deliveryContext?.channel);
const deliveryTo = readStringValue(deliveryContext?.to);
const deliveryAccountId = readStringValue(deliveryContext?.accountId);
const deliveryThreadId =
typeof deliveryContext?.threadId === "string" ||
(typeof deliveryContext?.threadId === "number" &&
Number.isFinite(deliveryContext.threadId))
? deliveryContext.threadId
: undefined;
const lastChannel =
deliveryChannel ??
(typeof entry.lastChannel === "string" ? entry.lastChannel : undefined);
const lastAccountId =
deliveryAccountId ??
(typeof entry.lastAccountId === "string" ? entry.lastAccountId : undefined);
const lastChannel = deliveryChannel ?? readStringValue(entry.lastChannel);
const lastAccountId = deliveryAccountId ?? readStringValue(entry.lastAccountId);
const derivedChannel = deriveChannel({
key,
kind,
@@ -176,9 +171,9 @@ export function createSessionsListTool(opts?: {
lastChannel,
});
const sessionId = typeof entry.sessionId === "string" ? entry.sessionId : undefined;
const sessionId = readStringValue(entry.sessionId);
const sessionFileRaw = (entry as { sessionFile?: unknown }).sessionFile;
const sessionFile = typeof sessionFileRaw === "string" ? sessionFileRaw : undefined;
const sessionFile = readStringValue(sessionFileRaw);
let transcriptPath: string | undefined;
if (sessionId) {
try {
@@ -215,8 +210,7 @@ export function createSessionsListTool(opts?: {
(typeof entryOrigin?.accountId === "string" ? entryOrigin.accountId : undefined)
? {
provider: originChannel,
accountId:
typeof entryOrigin?.accountId === "string" ? entryOrigin.accountId : undefined,
accountId: readStringValue(entryOrigin?.accountId),
}
: undefined,
spawnedBy:
@@ -227,8 +221,8 @@ export function createSessionsListTool(opts?: {
mainKey,
})
: undefined,
label: typeof entry.label === "string" ? entry.label : undefined,
displayName: typeof entry.displayName === "string" ? entry.displayName : undefined,
label: readStringValue(entry.label),
displayName: readStringValue(entry.displayName),
parentSessionKey:
typeof entry.parentSessionKey === "string"
? resolveDisplaySessionKey({
@@ -248,12 +242,12 @@ export function createSessionsListTool(opts?: {
: undefined,
updatedAt: typeof entry.updatedAt === "number" ? entry.updatedAt : undefined,
sessionId,
model: typeof entry.model === "string" ? entry.model : undefined,
model: readStringValue(entry.model),
contextTokens: typeof entry.contextTokens === "number" ? entry.contextTokens : undefined,
totalTokens: typeof entry.totalTokens === "number" ? entry.totalTokens : undefined,
estimatedCostUsd:
typeof entry.estimatedCostUsd === "number" ? entry.estimatedCostUsd : undefined,
status: typeof entry.status === "string" ? entry.status : undefined,
status: readStringValue(entry.status),
startedAt: typeof entry.startedAt === "number" ? entry.startedAt : undefined,
endedAt: typeof entry.endedAt === "number" ? entry.endedAt : undefined,
runtimeMs: typeof entry.runtimeMs === "number" ? entry.runtimeMs : undefined,
@@ -268,19 +262,18 @@ export function createSessionsListTool(opts?: {
}),
)
: undefined,
thinkingLevel: typeof entry.thinkingLevel === "string" ? entry.thinkingLevel : undefined,
thinkingLevel: readStringValue(entry.thinkingLevel),
fastMode: typeof entry.fastMode === "boolean" ? entry.fastMode : undefined,
verboseLevel: typeof entry.verboseLevel === "string" ? entry.verboseLevel : undefined,
reasoningLevel:
typeof entry.reasoningLevel === "string" ? entry.reasoningLevel : undefined,
elevatedLevel: typeof entry.elevatedLevel === "string" ? entry.elevatedLevel : undefined,
responseUsage: typeof entry.responseUsage === "string" ? entry.responseUsage : undefined,
verboseLevel: readStringValue(entry.verboseLevel),
reasoningLevel: readStringValue(entry.reasoningLevel),
elevatedLevel: readStringValue(entry.elevatedLevel),
responseUsage: readStringValue(entry.responseUsage),
systemSent: typeof entry.systemSent === "boolean" ? entry.systemSent : undefined,
abortedLastRun:
typeof entry.abortedLastRun === "boolean" ? entry.abortedLastRun : undefined,
sendPolicy: typeof entry.sendPolicy === "string" ? entry.sendPolicy : undefined,
sendPolicy: readStringValue(entry.sendPolicy),
lastChannel,
lastTo: deliveryTo ?? (typeof entry.lastTo === "string" ? entry.lastTo : undefined),
lastTo: deliveryTo ?? readStringValue(entry.lastTo),
lastAccountId,
transcriptPath,
};

View File

@@ -6,6 +6,7 @@ import { openBoundaryFile } from "../infra/boundary-file-read.js";
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { isCronSessionKey, isSubagentSessionKey } from "../routing/session-key.js";
import { readStringValue } from "../shared/string-coerce.js";
import { resolveUserPath } from "../utils.js";
import { resolveWorkspaceTemplateDir } from "./workspace-templates.js";
@@ -217,14 +218,11 @@ function parseWorkspaceSetupState(raw: string): WorkspaceSetupState | null {
if (!parsed || typeof parsed !== "object") {
return null;
}
const legacyCompletedAt =
typeof parsed.onboardingCompletedAt === "string" ? parsed.onboardingCompletedAt : undefined;
const legacyCompletedAt = readStringValue(parsed.onboardingCompletedAt);
return {
version: WORKSPACE_STATE_VERSION,
bootstrapSeededAt:
typeof parsed.bootstrapSeededAt === "string" ? parsed.bootstrapSeededAt : undefined,
setupCompletedAt:
typeof parsed.setupCompletedAt === "string" ? parsed.setupCompletedAt : legacyCompletedAt,
bootstrapSeededAt: readStringValue(parsed.bootstrapSeededAt),
setupCompletedAt: readStringValue(parsed.setupCompletedAt) ?? legacyCompletedAt,
};
} catch {
return null;

View File

@@ -1,6 +1,7 @@
import path from "node:path";
import * as tar from "tar";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { readStringValue } from "../shared/string-coerce.js";
import { isRecord, resolveUserPath } from "../utils.js";
const WINDOWS_ABSOLUTE_ARCHIVE_PATH_RE = /^[A-Za-z]:[\\/]/;
@@ -150,10 +151,9 @@ function parseManifest(raw: string): BackupManifest {
: undefined,
paths: isRecord(parsed.paths)
? {
stateDir: typeof parsed.paths.stateDir === "string" ? parsed.paths.stateDir : undefined,
configPath:
typeof parsed.paths.configPath === "string" ? parsed.paths.configPath : undefined,
oauthDir: typeof parsed.paths.oauthDir === "string" ? parsed.paths.oauthDir : undefined,
stateDir: readStringValue(parsed.paths.stateDir),
configPath: readStringValue(parsed.paths.configPath),
oauthDir: readStringValue(parsed.paths.oauthDir),
workspaceDirs: Array.isArray(parsed.paths.workspaceDirs)
? parsed.paths.workspaceDirs.filter(
(entry): entry is string => typeof entry === "string",

View File

@@ -11,6 +11,7 @@ import { findTailscaleBinary } from "../infra/tailscale.js";
import type { RuntimeEnv } from "../runtime.js";
import { resolveDefaultSecretProviderAlias } from "../secrets/ref-contract.js";
import { validateIPv4AddressInput } from "../shared/net/ipv4.js";
import { readStringValue } from "../shared/string-coerce.js";
import { note } from "../terminal/note.js";
import { buildGatewayAuthConfig } from "./configure.gateway-auth.js";
import { confirm, select, text } from "./configure.shared.js";
@@ -86,7 +87,7 @@ export async function promptGatewayConfig(
}),
runtime,
);
customBindHost = typeof input === "string" ? input : undefined;
customBindHost = readStringValue(input);
}
let authMode = guardCancel(

View File

@@ -1,3 +1,5 @@
import { readStringValue } from "../shared/string-coerce.js";
export type GatewaySelfPresence = {
host?: string;
ip?: string;
@@ -19,9 +21,9 @@ export function pickGatewaySelfPresence(presence: unknown): GatewaySelfPresence
return null;
}
return {
host: typeof self.host === "string" ? self.host : undefined,
ip: typeof self.ip === "string" ? self.ip : undefined,
version: typeof self.version === "string" ? self.version : undefined,
platform: typeof self.platform === "string" ? self.platform : undefined,
host: readStringValue(self.host),
ip: readStringValue(self.ip),
version: readStringValue(self.version),
platform: readStringValue(self.platform),
};
}

View File

@@ -5,6 +5,7 @@ import {
type GatewayBonjourBeacon,
} from "../../infra/bonjour-discovery.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { readStringValue } from "../../shared/string-coerce.js";
import { pickAutoSshTargetFromDiscovery } from "./discovery.js";
import {
extractConfigSummary,
@@ -117,8 +118,8 @@ export async function runGatewayStatusProbePass(params: {
const probed = await Promise.all(
targets.map(async (target) => {
const authResolution = await resolveAuthForTarget(params.cfg, target, {
token: typeof params.opts.token === "string" ? params.opts.token : undefined,
password: typeof params.opts.password === "string" ? params.opts.password : undefined,
token: readStringValue(params.opts.token),
password: readStringValue(params.opts.password),
});
const probe = await probeGateway({
url: target.url,

View File

@@ -2,6 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import { CONFIG_PATH, type HookMappingConfig, type HooksConfig } from "../config/config.js";
import { importFileModule, resolveFunctionModuleExport } from "../hooks/module-loader.js";
import { readStringValue } from "../shared/string-coerce.js";
import type { HookMessageChannel } from "./hooks.js";
export type HookMappingResolved = {
@@ -228,7 +229,7 @@ function mappingMatches(mapping: HookMappingResolved, ctx: HookMappingContext) {
}
}
if (mapping.matchSource) {
const source = typeof ctx.payload.source === "string" ? ctx.payload.source : undefined;
const source = readStringValue(ctx.payload.source);
if (!source || source !== mapping.matchSource) {
return false;
}

View File

@@ -33,7 +33,7 @@ import {
resolveAgentIdFromSessionKey,
toAgentStoreSessionKey,
} from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { normalizeOptionalString, readStringValue } from "../../shared/string-coerce.js";
import { GATEWAY_CLIENT_IDS } from "../protocol/client-info.js";
import {
ErrorCodes,
@@ -1206,14 +1206,14 @@ export const sessionsHandlers: GatewayRequestHandlers = {
context,
requestedKey: key,
canonicalKey,
runId: typeof p.runId === "string" ? p.runId : undefined,
runId: readStringValue(p.runId),
});
let abortedRunId: string | null = null;
await chatHandlers["chat.abort"]({
req,
params: {
sessionKey: abortSessionKey,
runId: typeof p.runId === "string" ? p.runId : undefined,
runId: readStringValue(p.runId),
},
respond: (ok, payload, error, meta) => {
if (!ok) {

View File

@@ -5,6 +5,7 @@ import { shouldLogSubsystemToConsole } from "../logging/console.js";
import { getDefaultRedactPatterns, redactSensitiveText } from "../logging/redact.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { parseAgentSessionKey } from "../routing/session-key.js";
import { readStringValue } from "../shared/string-coerce.js";
import { DEFAULT_WS_SLOW_MS, getGatewayWsLogStyle } from "./ws-logging.js";
const LOG_VALUE_LIMIT = 240;
@@ -169,10 +170,10 @@ export function summarizeAgentEventForWsLog(payload: unknown): Record<string, un
return {};
}
const rec = payload as Record<string, unknown>;
const runId = typeof rec.runId === "string" ? rec.runId : undefined;
const stream = typeof rec.stream === "string" ? rec.stream : undefined;
const runId = readStringValue(rec.runId);
const stream = readStringValue(rec.stream);
const seq = typeof rec.seq === "number" ? rec.seq : undefined;
const sessionKey = typeof rec.sessionKey === "string" ? rec.sessionKey : undefined;
const sessionKey = readStringValue(rec.sessionKey);
const data =
rec.data && typeof rec.data === "object" ? (rec.data as Record<string, unknown>) : undefined;
@@ -201,7 +202,7 @@ export function summarizeAgentEventForWsLog(payload: unknown): Record<string, un
}
if (stream === "assistant") {
const text = typeof data.text === "string" ? data.text : undefined;
const text = readStringValue(data.text);
if (text?.trim()) {
extra.text = compactPreview(text);
}
@@ -215,16 +216,16 @@ export function summarizeAgentEventForWsLog(payload: unknown): Record<string, un
}
if (stream === "tool") {
const phase = typeof data.phase === "string" ? data.phase : undefined;
const name = typeof data.name === "string" ? data.name : undefined;
const phase = readStringValue(data.phase);
const name = readStringValue(data.name);
if (phase || name) {
extra.tool = `${phase ?? "?"}:${name ?? "?"}`;
}
const toolCallId = typeof data.toolCallId === "string" ? data.toolCallId : undefined;
const toolCallId = readStringValue(data.toolCallId);
if (toolCallId) {
extra.call = shortId(toolCallId);
}
const meta = typeof data.meta === "string" ? data.meta : undefined;
const meta = readStringValue(data.meta);
if (meta?.trim()) {
extra.meta = meta;
}