2Branches0Tags
GL
glucryptoFix trade candle loading via gateway
4620100a month ago52Commits
typescript
import type { ToolProfile } from "opentool"; import { store } from "opentool/store"; import { buildDigestBriefing, extractImportantDatesSection, extractNewsSection, extractStrategies, fetchDigestHistory, formatDigest, type JsonValue, type DailySummarySubAgentResult, } from "../src/daily-summary"; import { type DailySummaryConfig, MY_OPENPOND_TEMPLATE_CONFIG, readConfig, resolveConnectedApps, resolveScheduleConfig, } from "../src/config"; import { openpondRequest, unwrapOpenpondExecuteResponse, } from "../src/openpond"; const scheduleConfig = resolveScheduleConfig(); export const profile: ToolProfile = { description: "Daily OpenPond summary (performance + add-on tools).", category: "orchestrator", schedule: { cron: scheduleConfig.cron, enabled: scheduleConfig.enabled, notifyEmail: scheduleConfig.notifyEmail, }, connectedApps: resolveConnectedApps(), templateConfig: MY_OPENPOND_TEMPLATE_CONFIG, }; type DailySummaryResponse = JsonValue; type ConfiguredSubAgent = NonNullable<DailySummaryConfig["subAgents"]>[number]; const DAILY_SUMMARY_ENABLED_SUBAGENT_TOOL_NAMES = new Set<string>([ "news-intelligence-roundup", "important-dates-roundup", ]); const SUBAGENT_EXECUTION_TIMEOUT_MS = 30_000; function buildDailySummaryImportantDatesBody() { return { title: "Important Upcoming Dates", daysAhead: 14, limit: 3, category: "macro", series: ["CPI", "Core PCE", "PCE", "Jobs Report", "FOMC", "GDP", "Retail Sales"], summaryMaxEvents: 3, }; } function isMissing(response: Awaited<ReturnType<typeof openpondRequest>>) { const data = response.data; if (response.status === 404) return true; if (!data || typeof data !== "object") return false; return (data as Record<string, unknown>).error === "Not Found"; } function buildPersistedMetadata(params: { runAt: string; briefing: Awaited<ReturnType<typeof buildDigestBriefing>>["briefing"]; strategies: ReturnType<typeof extractStrategies>; strategyChanges: Awaited<ReturnType<typeof buildDigestBriefing>>["strategyChanges"]; news: ReturnType<typeof extractNewsSection>; importantDates: ReturnType<typeof extractImportantDatesSection>; }) { return { runAt: params.runAt, briefing: params.briefing, strategies: params.strategies, strategyChanges: params.strategyChanges, news: params.news, importantDates: params.importantDates, }; } function normalizeToolKey(value: string) { return value.trim().toLowerCase(); } function resolveSubAgentMethod(agent: ConfiguredSubAgent) { return agent.method ?? "POST"; } function resolveSubAgentBody(agent: ConfiguredSubAgent, method: "GET" | "POST") { if (method !== "POST") { return undefined; } const toolKey = normalizeToolKey(agent.toolName); if (toolKey === "important-dates-roundup") { return buildDailySummaryImportantDatesBody(); } return agent.body; } function normalizeConfiguredSubAgents(config: DailySummaryConfig) { const subAgents = Array.isArray(config.subAgents) ? config.subAgents : []; const seenToolNames = new Set<string>(); return subAgents.filter((agent) => { const toolKey = normalizeToolKey(agent.toolName); if ( !toolKey || seenToolNames.has(toolKey) || !DAILY_SUMMARY_ENABLED_SUBAGENT_TOOL_NAMES.has(toolKey) ) { return false; } seenToolNames.add(toolKey); return true; }); } export async function GET(_req: Request) { const runAt = new Date().toISOString(); const config = await readConfig(); const configuredSubAgents = normalizeConfiguredSubAgents(config); const performanceResponse = await openpondRequest("/apps/performance", { method: "GET", }); const performance = isMissing(performanceResponse) ? null : (performanceResponse.data as JsonValue | null); const subAgentResults = configuredSubAgents.length ? await Promise.all( configuredSubAgents.map(async (agent) => { const method = resolveSubAgentMethod(agent); const body = resolveSubAgentBody(agent, method); const executeForTarget = async (params: { appId: string; deploymentId: string; }) => { const controller = new AbortController(); const timeout = setTimeout( () => controller.abort("daily-summary-subagent-timeout"), SUBAGENT_EXECUTION_TIMEOUT_MS, ); const requestBody = method === "POST" || body !== undefined ? { appId: params.appId, deploymentId: params.deploymentId, toolName: agent.toolName, method, ...(body !== undefined ? { body } : {}), } : { appId: params.appId, deploymentId: params.deploymentId, toolName: agent.toolName, method, }; try { return await openpondRequest("/apps/tools/execute", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody), signal: controller.signal, }); } finally { clearTimeout(timeout); } }; const configuredTarget = agent.appId.trim() && agent.deploymentId.trim() ? { appId: agent.appId, deploymentId: agent.deploymentId, } : null; let executedResponse: | ReturnType<typeof unwrapOpenpondExecuteResponse> | null = null; let response = null as Awaited<ReturnType<typeof openpondRequest>> | null; if (configuredTarget) { try { response = await executeForTarget(configuredTarget); executedResponse = unwrapOpenpondExecuteResponse(response); } catch { response = null; executedResponse = null; } } if (!configuredTarget) { return { name: agent.displayName ?? agent.toolName, ok: false, data: { error: "configured_target_missing" }, missing: true, } satisfies DailySummarySubAgentResult; } return { name: agent.displayName ?? agent.toolName, ok: executedResponse?.ok ?? false, data: (executedResponse?.data as DailySummaryResponse | null) ?? null, missing: response ? isMissing(response) : false, } satisfies DailySummarySubAgentResult; }), ) : []; const historyItems = await fetchDigestHistory(config.historyLimit ?? 3); const strategies = extractStrategies(performance); const news = extractNewsSection(subAgentResults); const importantDates = extractImportantDatesSection(subAgentResults); const { briefing, strategyChanges } = await buildDigestBriefing({ runAt, config, performance, currentStrategies: strategies, subAgentResults, news, importantDates, historyItems, }); const content = formatDigest({ runAt, briefing, performance, strategies, strategyChanges, subAgentResults, news, importantDates, }); const persistedMetadata = buildPersistedMetadata({ runAt, briefing, strategies, strategyChanges, news, importantDates, }); const conversationPersistResponse = await openpondRequest( "/apps/agent/conversation-message", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content, runAt, metadata: persistedMetadata, }), } ); if (!conversationPersistResponse.ok) { throw new Error( `Daily summary conversation persist failed (${conversationPersistResponse.status})` ); } await store({ source: "daily-summary", ref: `daily-summary-${runAt}`, status: "info", action: "digest", metadata: { content, ...persistedMetadata, }, }); return Response.json({ ok: true, runAt, briefing, content, performance, strategies, strategyChanges, news, importantDates, subAgents: subAgentResults, }); }