openpondai/agents/my-openpond
OpenTool app
typescript
import { z } from "zod";
const CONFIG_ENV = "OPENPOND_DAILY_SNAPSHOT_CONFIG";
const TEMPLATE_CONFIG_ENV_VAR = CONFIG_ENV;
const TEMPLATE_CONFIG_VERSION = 2;
export type ConnectedApp = {
appId: string;
deploymentId: string;
toolName: string;
displayName?: string;
method?: "GET" | "POST";
body?: unknown;
};
export type ScheduleConfig = {
cron: string;
enabled: boolean;
notifyEmail: boolean;
};
const tradeReviewSchema = z.object({
useRecentTrades: z.boolean().optional(),
riskProfile: z.enum(["conservative", "balanced", "aggressive"]).optional(),
allowHighLeverage: z.boolean().optional(),
});
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({
configVersion: z.number().int().optional(),
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(),
summaryModel: z.string().min(1).optional(),
historyLimit: z.number().int().min(1).max(10).optional(),
tradeReview: tradeReviewSchema.optional(),
});
export type DailySummaryConfig = z.infer<typeof configSchema>;
export type TradeReviewConfig = NonNullable<DailySummaryConfig["tradeReview"]>;
const TEMPLATE_CONFIG_DEFAULTS: DailySummaryConfig = {
configVersion: TEMPLATE_CONFIG_VERSION,
channels: {
email: false,
},
schedule: {
cron: "0 8 * * *",
enabled: false,
notifyEmail: true,
},
summaryModel: "gpt-5-mini",
historyLimit: 3,
tradeReview: {
useRecentTrades: true,
riskProfile: "balanced",
allowHighLeverage: false,
},
};
const TEMPLATE_CONFIG_SCHEMA = {
type: "object",
additionalProperties: false,
properties: {
tradeReview: {
type: "object",
title: "Trade review preferences",
additionalProperties: false,
properties: {
useRecentTrades: {
type: "boolean",
title: "Use recent trades",
description: "Whether trade review should factor in your recent manual trading history.",
},
riskProfile: {
type: "string",
title: "Risk profile",
enum: ["conservative", "balanced", "aggressive"],
description: "Controls how strict the review should be about aggressive setups.",
},
allowHighLeverage: {
type: "boolean",
title: "Allow high leverage",
description: "Treat elevated leverage as acceptable unless the liquidation and TP/SL structure are weak.",
},
},
},
summaryModel: {
type: "string",
title: "Summary model",
description: "Model used for daily summaries and trade review narration.",
},
historyLimit: {
type: "number",
title: "History items",
minimum: 1,
maximum: 10,
description: "How many prior digest runs to use for change summaries.",
},
},
};
function normalizeToolName(value: string | undefined) {
return (value ?? "").trim().toLowerCase();
}
function parseJson(raw: string | null): unknown | null {
if (!raw) return null;
try {
return JSON.parse(raw) as unknown;
} catch {
return null;
}
}
function mergeConfig(
base: DailySummaryConfig,
override: DailySummaryConfig,
): DailySummaryConfig {
return {
...base,
...override,
channels: {
...base.channels,
...override.channels,
},
schedule: {
...base.schedule,
...override.schedule,
},
tradeReview: {
...base.tradeReview,
...override.tradeReview,
},
subAgents: override.subAgents ?? base.subAgents,
};
}
export async function readConfig(): Promise<DailySummaryConfig> {
let config: DailySummaryConfig = TEMPLATE_CONFIG_DEFAULTS;
const envConfig = parseJson(process.env[CONFIG_ENV] ?? null);
if (envConfig && configSchema.safeParse(envConfig).success) {
config = mergeConfig(config, envConfig as DailySummaryConfig);
}
return config;
}
export function resolveConnectedApps(): ConnectedApp[] {
const raw = process.env[CONFIG_ENV];
if (!raw) return [];
try {
const parsed = JSON.parse(raw) as { subAgents?: unknown };
const subAgents = Array.isArray(parsed?.subAgents) ? parsed.subAgents : [];
const seenToolNames = new Set<string>();
return subAgents
.map((agent) => {
if (!agent || typeof agent !== "object") return null;
const record = agent as Record<string, unknown>;
const appId = typeof record.appId === "string" ? record.appId : "";
const deploymentId =
typeof record.deploymentId === "string" ? record.deploymentId : "";
const toolName =
typeof record.toolName === "string" ? record.toolName : "";
if (!appId || !deploymentId || !toolName) return null;
const connectedApp: ConnectedApp = {
appId,
deploymentId,
toolName,
};
if (
typeof record.displayName === "string" &&
record.displayName.trim().length > 0
) {
connectedApp.displayName = record.displayName;
}
if (record.method === "GET" || record.method === "POST") {
connectedApp.method = record.method;
}
if ("body" in record) {
connectedApp.body = record.body;
}
return connectedApp;
})
.filter((item): item is ConnectedApp => {
if (item === null) return false;
const toolKey = normalizeToolName(item.toolName);
if (!toolKey || seenToolNames.has(toolKey)) {
return false;
}
seenToolNames.add(toolKey);
return true;
});
} catch {
return [];
}
}
export function resolveScheduleConfig(): ScheduleConfig {
const fallback: ScheduleConfig = {
cron: "0 8 * * *",
enabled: false,
notifyEmail: true,
};
const raw = process.env[CONFIG_ENV];
if (!raw) return fallback;
try {
const parsed = JSON.parse(raw) as {
schedule?: { cron?: unknown; enabled?: unknown; notifyEmail?: unknown };
channels?: { email?: unknown };
};
const cronRaw = parsed?.schedule?.cron;
const cron =
typeof cronRaw === "string" && cronRaw.trim().length > 0
? cronRaw.trim()
: fallback.cron;
const enabled = parsed?.schedule?.enabled === true;
const notifyEmail =
typeof parsed?.schedule?.notifyEmail === "boolean"
? parsed.schedule.notifyEmail
: typeof parsed?.channels?.email === "boolean"
? parsed.channels.email
: fallback.notifyEmail;
return { cron, enabled, notifyEmail };
} catch {
return fallback;
}
}
export function resolveTradeReviewConfig(config: DailySummaryConfig): Required<TradeReviewConfig> {
return {
useRecentTrades: config.tradeReview?.useRecentTrades ?? true,
riskProfile: config.tradeReview?.riskProfile ?? "balanced",
allowHighLeverage: config.tradeReview?.allowHighLeverage ?? false,
};
}
export const MY_OPENPOND_TEMPLATE_CONFIG = {
version: TEMPLATE_CONFIG_VERSION,
schema: TEMPLATE_CONFIG_SCHEMA,
defaults: TEMPLATE_CONFIG_DEFAULTS,
envVar: TEMPLATE_CONFIG_ENV_VAR,
};