typescript
import { z } from "zod";
type JsonValue = Record<string, unknown> | Array<unknown> | string | number | boolean | null;
export const subAgentSchema = z.object({
appId: z.string().min(1),
deploymentId: z.string().min(1),
toolName: z.string().min(1),
displayName: z.string().optional(),
method: z.enum(["GET", "POST"]).optional(),
body: z.unknown().optional(),
});
export const configSchema = z.object({
subAgents: z.array(subAgentSchema).optional(),
channels: z
.object({
email: z.boolean().optional(),
telegram: z.boolean().optional(),
})
.optional(),
schedule: z
.object({
cron: z.string().min(1).optional(),
enabled: z.boolean().optional(),
notifyEmail: z.boolean().optional(),
})
.optional(),
});
export type DailySummaryConfig = z.infer<typeof configSchema>;
function parseJson(raw: string | null): JsonValue | null {
if (!raw) return null;
try {
return JSON.parse(raw) as JsonValue;
} catch {
return null;
}
}
function mergeConfig(base: DailySummaryConfig, override: DailySummaryConfig): DailySummaryConfig {
return {
...base,
...override,
channels: {
...base.channels,
...override.channels,
},
schedule: {
...base.schedule,
...override.schedule,
},
subAgents: override.subAgents ?? base.subAgents,
};
}
export async function readConfig(): Promise<DailySummaryConfig> {
let config: DailySummaryConfig = {};
const envConfig = parseJson(process.env.OPENPOND_DAILY_SNAPSHOT_CONFIG ?? null);
if (envConfig && configSchema.safeParse(envConfig).success) {
config = mergeConfig(config, envConfig as DailySummaryConfig);
}
return config;
}
function resolveBaseUrl() {
const baseUrl = process.env.BASE_URL;
if (!baseUrl) {
throw new Error("BASE_URL is required for Daily Snapshot (API host).");
}
return baseUrl.replace(/\/$/, "");
}
async function fetchJson(
url: string,
options: RequestInit
): Promise<{ ok: boolean; status: number; data: JsonValue | null }> {
const response = await fetch(url, options);
const text = await response.text();
const data = parseJson(text);
return { ok: response.ok, status: response.status, data };
}
export async function openpondRequest(path: string, options: RequestInit) {
const apiKey = process.env.OPENPOND_API_KEY;
if (!apiKey) {
throw new Error("OPENPOND_API_KEY is required for daily summary.");
}
const url = `${resolveBaseUrl()}${path}`;
const headers = new Headers(options.headers ?? {});
headers.set("openpond-api-key", apiKey);
if (!headers.has("Authorization")) {
headers.set("Authorization", `ApiKey ${apiKey}`);
}
return fetchJson(url, { ...options, headers });
}
export function formatDigest(params: {
runAt: string;
performance: JsonValue | null;
subAgentResults: Array<{
name: string;
ok: boolean;
data?: JsonValue | null;
missing?: boolean;
}>;
}) {
const lines: string[] = [];
lines.push(`Daily Snapshot · ${params.runAt}`);
lines.push("");
if (params.performance) {
lines.push("Performance:");
lines.push(JSON.stringify(params.performance, null, 2));
lines.push("");
}
if (params.subAgentResults.length > 0) {
lines.push("Add-ons:");
for (const result of params.subAgentResults) {
const status = result.missing ? "missing" : result.ok ? "ok" : "failed";
lines.push(`- ${result.name}: ${status}`);
if (result.data && !result.missing) {
const snippet = JSON.stringify(result.data);
lines.push(` ${snippet.slice(0, 400)}${snippet.length > 400 ? "…" : ""}`);
}
}
lines.push("");
}
return lines.join("\n").trim();
}