openpondai/agents/news-intelligence-roundup
OpenTool app
1Branch0Tags
OP
OpenPond Syncsync: merge local template master into production
typescript
import { z } from "zod";
const CONFIG_ENV = "OPENTOOL_PUBLIC_NEWS_INTELLIGENCE_ROUNDUP_CONFIG";
const TEMPLATE_CONFIG_ENV_VAR = CONFIG_ENV;
const TEMPLATE_CONFIG_VERSION = 3;
const MAX_WINDOW_HOURS = 24 * 90;
const MAX_WINDOWS = 8;
const roundupModeSchema = z.enum([
"query_search",
"recent_feed",
"top_events",
]);
const sourceFamilySchema = z.enum([
"rss",
"official",
"macro",
"prediction_market",
"social",
]);
const includePredictionMarketsSchema = z.union([
z.boolean(),
z.literal("auto"),
]);
const baseConfigSchema = z
.object({
configVersion: z.number().int().optional(),
title: z.string().min(1).max(120).optional(),
mode: roundupModeSchema.optional(),
query: z.string().min(1).optional(),
windows: z
.array(z.number().int().min(1).max(MAX_WINDOW_HOURS))
.min(1)
.max(MAX_WINDOWS)
.optional(),
limitPerWindow: z.number().int().min(1).max(50).optional(),
sourceIds: z.array(z.string().min(1)).max(50).optional(),
sourceFamilies: z.array(sourceFamilySchema).max(10).optional(),
includePredictionMarkets: includePredictionMarketsSchema.optional(),
ingestOnRequest: z.boolean().optional(),
summaryModel: z.string().min(1).optional(),
summaryMaxArticles: z.number().int().min(1).max(10).optional(),
asOf: z.string().datetime().optional(),
})
.strict();
export const requestOverrideSchema = baseConfigSchema.partial();
export type SourceFamily = z.infer<typeof sourceFamilySchema>;
export type RoundupMode = z.infer<typeof roundupModeSchema>;
export type IncludePredictionMarkets = z.infer<
typeof includePredictionMarketsSchema
>;
export type NewsIntelligenceRoundupConfig = {
configVersion: number;
title: string;
mode: RoundupMode;
query: string | null;
windows: number[];
limitPerWindow: number;
sourceIds?: string[];
sourceFamilies?: SourceFamily[];
includePredictionMarkets: IncludePredictionMarkets;
ingestOnRequest: boolean;
summaryModel?: string;
summaryMaxArticles: number;
asOf?: string;
};
const TEMPLATE_CONFIG_DEFAULTS: NewsIntelligenceRoundupConfig = {
configVersion: TEMPLATE_CONFIG_VERSION,
title: "Market News Roundup",
mode: "top_events",
query:
"global markets, macro, geopolitics, oil, rates, inflation, crypto policy",
windows: [24],
limitPerWindow: 8,
includePredictionMarkets: false,
ingestOnRequest: false,
summaryModel: "gpt-4.1-mini",
summaryMaxArticles: 5,
};
const TEMPLATE_CONFIG_SCHEMA = {
type: "object",
properties: {
configVersion: {
type: "number",
title: "Config version",
description: "Internal version for roundup defaults.",
readOnly: true,
"x-hidden": true,
},
title: {
type: "string",
title: "Title",
description: "Display title used in the roundup payload.",
},
mode: {
type: "string",
title: "Mode",
description: "Use query search, recent feed, or top events.",
enum: ["query_search", "recent_feed", "top_events"],
},
query: {
type: "string",
title: "Query",
description:
"Optional search query for query_search mode, or editorial focus used by the AI summary for recent_feed and top_events.",
},
windows: {
type: "array",
title: "Windows",
description: "Lookback windows in hours, for example [1,4,24].",
items: { type: "number" },
},
limitPerWindow: {
type: "number",
title: "Limit per window",
description: "Max articles requested from gateway per lookback window.",
},
sourceIds: {
type: "array",
title: "Source IDs",
description: "Optional explicit source IDs to include.",
items: { type: "string" },
},
sourceFamilies: {
type: "array",
title: "Source families",
description: "Optional source family filters.",
items: {
type: "string",
enum: ["rss", "official", "macro", "prediction_market", "social"],
},
},
includePredictionMarkets: {
type: ["boolean", "string"],
title: "Include prediction markets",
description: "Whether to attach bounded prediction-market context when available.",
},
ingestOnRequest: {
type: "boolean",
title: "Ingest on request",
description: "Ask gateway to ingest matching sources before resolving the roundup.",
},
summaryModel: {
type: "string",
title: "Summary model",
description: "Model used for the short AI-written roundup summary.",
},
summaryMaxArticles: {
type: "number",
title: "Summary max articles",
description: "Max number of top articles returned in the final roundup.",
},
asOf: {
type: "string",
title: "As of",
description: "Optional ISO timestamp for replaying the roundup at a prior point in time.",
},
},
};
function parseJson(raw: string | null): unknown | null {
if (!raw) return null;
try {
return JSON.parse(raw) as unknown;
} catch {
return null;
}
}
function pickDefined<T extends Record<string, unknown>>(value: T): Partial<T> {
return Object.fromEntries(
Object.entries(value).filter(([, entry]) => entry !== undefined),
) as Partial<T>;
}
function uniqueSortedWindows(windows?: number[]) {
const resolved = windows && windows.length > 0
? windows
: TEMPLATE_CONFIG_DEFAULTS.windows;
return Array.from(new Set(resolved)).sort((left, right) => left - right);
}
function normalizeStringArray(value?: string[]) {
if (!value || value.length === 0) return undefined;
const normalized = Array.from(
new Set(value.map((entry) => entry.trim()).filter(Boolean)),
);
return normalized.length > 0 ? normalized : undefined;
}
export function resolveRuntimeConfig(
overrides?: z.infer<typeof requestOverrideSchema>,
): NewsIntelligenceRoundupConfig {
const envConfig = parseJson(process.env[CONFIG_ENV] ?? null);
const parsed = baseConfigSchema.safeParse(
envConfig ?? TEMPLATE_CONFIG_DEFAULTS,
);
const base = parsed.success ? parsed.data : TEMPLATE_CONFIG_DEFAULTS;
const merged = {
...base,
...pickDefined((overrides ?? {}) as Record<string, unknown>),
};
const finalMode =
merged.mode ??
(typeof merged.query === "string" && merged.query.trim().length > 0
? "query_search"
: TEMPLATE_CONFIG_DEFAULTS.mode);
const finalQuery =
typeof merged.query === "string" && merged.query.trim().length > 0
? merged.query.trim()
: null;
if (finalMode === "query_search" && !finalQuery) {
throw new Error("query is required for query_search mode");
}
return {
configVersion: TEMPLATE_CONFIG_VERSION,
title: merged.title ?? TEMPLATE_CONFIG_DEFAULTS.title,
mode: finalMode,
query: finalQuery,
windows: uniqueSortedWindows(merged.windows),
limitPerWindow:
merged.limitPerWindow ?? TEMPLATE_CONFIG_DEFAULTS.limitPerWindow,
sourceIds: normalizeStringArray(merged.sourceIds),
sourceFamilies: merged.sourceFamilies?.length
? Array.from(new Set(merged.sourceFamilies))
: undefined,
includePredictionMarkets:
merged.includePredictionMarkets ??
TEMPLATE_CONFIG_DEFAULTS.includePredictionMarkets,
ingestOnRequest:
merged.ingestOnRequest ?? TEMPLATE_CONFIG_DEFAULTS.ingestOnRequest,
summaryModel:
merged.summaryModel ?? TEMPLATE_CONFIG_DEFAULTS.summaryModel,
summaryMaxArticles:
merged.summaryMaxArticles ?? TEMPLATE_CONFIG_DEFAULTS.summaryMaxArticles,
asOf: merged.asOf,
};
}
export const NEWS_INTELLIGENCE_ROUNDUP_TEMPLATE_CONFIG = {
version: TEMPLATE_CONFIG_VERSION,
schema: TEMPLATE_CONFIG_SCHEMA,
defaults: TEMPLATE_CONFIG_DEFAULTS,
envVar: TEMPLATE_CONFIG_ENV_VAR,
};