import { makeApi, Zodios, type ZodiosOptions } from "@zodios/core"; import { z } from "zod"; export type AnalysisModuleConfig = { analysis_prompt: string; context_selector: ContextSelectorConfig; dependencies: Array; id?: (string | null) | undefined; llm_config?: (null | LlmConfig) | undefined; name: string; output_type: string; }; export type ContextSelectorConfig = SelectionMode; export type SelectionMode = | { Manual: { rules: Array; }; } | { Auto: Partial<{ llm_config: null | LlmConfig; }>; } | { Hybrid: { llm_config?: (null | LlmConfig) | undefined; selection_prompt: string; }; }; export type LlmConfig = Partial<{ max_tokens: number | null; model_id: string | null; temperature: number | null; }>; export type AnalysisTemplateSet = { modules: {}; name: string; }; export type AnalysisTemplateSets = {}; export type ConfigFieldSchema = { default_value?: (string | null) | undefined; description?: (string | null) | undefined; field_type: FieldType; key: ConfigKey; label: string; options?: (Array | null) | undefined; placeholder?: (string | null) | undefined; required: boolean; }; export type FieldType = "Text" | "Password" | "Url" | "Boolean" | "Select"; export type ConfigKey = | "ApiKey" | "ApiToken" | "ApiUrl" | "BaseUrl" | "SecretKey" | "Username" | "Password" | "SandboxMode" | "Region"; export type DataSourceConfig = { api_key?: (string | null) | undefined; api_url?: (string | null) | undefined; enabled: boolean; provider: DataSourceProvider; }; export type DataSourceProvider = "Tushare" | "Finnhub" | "Alphavantage" | "Yfinance"; export type DataSourcesConfig = {}; export type HealthStatus = { details: {}; module_id: string; status: ServiceStatus; version: string; }; export type ServiceStatus = "Ok" | "Degraded" | "Unhealthy"; export type LlmProvider = { api_base_url: string; api_key: string; models: Array; name: string; }; export type LlmModel = { is_active: boolean; model_id: string; name?: (string | null) | undefined; }; export type LlmProvidersConfig = {}; export type ProviderMetadata = { config_schema: Array; description: string; icon_url?: (string | null) | undefined; id: string; name_cn: string; name_en: string; supports_test_connection: boolean; }; export type StartWorkflowCommand = { market: string; request_id: string; symbol: CanonicalSymbol; template_id: string; }; export type CanonicalSymbol = string; export type TaskNode = { display_name?: (string | null) | undefined; id: string; initial_status: TaskStatus; name: string; type: TaskType; }; export type TaskStatus = | "Pending" | "Scheduled" | "Running" | "Completed" | "Failed" | "Skipped"; export type TaskType = "DataFetch" | "DataProcessing" | "Analysis"; export type TaskProgress = { details: string; progress_percent: number; request_id: string; started_at: string; status: ObservabilityTaskStatus; task_name: string; }; export type ObservabilityTaskStatus = "Queued" | "InProgress" | "Completed" | "Failed"; export type WorkflowDag = { edges: Array; nodes: Array; }; export type TaskDependency = { from: string; to: string; }; export type WorkflowEvent = | { payload: { task_graph: WorkflowDag; timestamp: number; }; type: "WorkflowStarted"; } | { payload: { input_commit?: (string | null) | undefined; message?: (string | null) | undefined; output_commit?: (string | null) | undefined; progress?: (number | null) | undefined; status: TaskStatus; task_id: string; task_type: TaskType; timestamp: number; }; type: "TaskStateChanged"; } | { payload: { content_delta: string; index: number; task_id: string; }; type: "TaskStreamUpdate"; } | { payload: { level: string; message: string; task_id: string; timestamp: number; }; type: "TaskLog"; } | { payload: { end_timestamp: number; result_summary?: unknown | undefined; }; type: "WorkflowCompleted"; } | { payload: { end_timestamp: number; is_fatal: boolean; reason: string; }; type: "WorkflowFailed"; } | { payload: { task_graph: WorkflowDag; tasks_metadata: {}; tasks_output: {}; tasks_status: {}; timestamp: number; }; type: "WorkflowStateSnapshot"; }; export type TaskMetadata = Partial<{ execution_log_path: string | null; output_path: string | null; }>; export type WorkflowHistoryDto = { created_at: string; end_time?: (string | null) | undefined; market: string; request_id: string; snapshot_data: Value; start_time: string; status: string; symbol: string; template_id?: (string | null) | undefined; }; export type Value = unknown; export const LlmConfig = z .object({ max_tokens: z.union([z.number(), z.null()]), model_id: z.union([z.string(), z.null()]), temperature: z.union([z.number(), z.null()]), }) .partial(); export const SelectionMode = z.union([ z .object({ Manual: z.object({ rules: z.array(z.string()) }).passthrough() }) .passthrough(), z .object({ Auto: z .object({ llm_config: z.union([z.null(), LlmConfig]) }) .partial() .passthrough(), }) .passthrough(), z .object({ Hybrid: z .object({ llm_config: z.union([z.null(), LlmConfig]).optional(), selection_prompt: z.string(), }) .passthrough(), }) .passthrough(), ]); export const ContextSelectorConfig = SelectionMode; export const AnalysisModuleConfig = z.object({ analysis_prompt: z.string(), context_selector: ContextSelectorConfig, dependencies: z.array(z.string()), id: z.union([z.string(), z.null()]).optional(), llm_config: z.union([z.null(), LlmConfig]).optional(), name: z.string(), output_type: z.string(), }); export const AnalysisTemplateSet = z.object({ modules: z.record(AnalysisModuleConfig), name: z.string(), }); export const AnalysisTemplateSets = z.record(AnalysisTemplateSet); export const DataSourceProvider = z.enum([ "Tushare", "Finnhub", "Alphavantage", "Yfinance", ]); export const DataSourceConfig = z.object({ api_key: z.union([z.string(), z.null()]).optional(), api_url: z.union([z.string(), z.null()]).optional(), enabled: z.boolean(), provider: DataSourceProvider, }); export const DataSourcesConfig = z.record(DataSourceConfig); export const TestLlmConfigRequest = z.object({ api_base_url: z.string(), api_key: z.string(), model_id: z.string(), }); export const LlmModel = z.object({ is_active: z.boolean(), model_id: z.string(), name: z.union([z.string(), z.null()]).optional(), }); export const LlmProvider = z.object({ api_base_url: z.string(), api_key: z.string(), models: z.array(LlmModel), name: z.string(), }); export const LlmProvidersConfig = z.record(LlmProvider); export const TestConfigRequest = z.object({ data: z.unknown(), type: z.string() }); export const TestConnectionResponse = z.object({ message: z.string(), success: z.boolean(), }); export const DiscoverPreviewRequest = z.object({ api_base_url: z.string(), api_key: z.string(), }); export const WorkflowHistorySummaryDto = z.object({ end_time: z.union([z.string(), z.null()]).optional(), market: z.string(), request_id: z.string().uuid(), start_time: z.string().datetime({ offset: true }), status: z.string(), symbol: z.string(), template_id: z.union([z.string(), z.null()]).optional(), }); export const Value = z.unknown(); export const WorkflowHistoryDto = z.object({ created_at: z.string().datetime({ offset: true }), end_time: z.union([z.string(), z.null()]).optional(), market: z.string(), request_id: z.string().uuid(), snapshot_data: Value, start_time: z.string().datetime({ offset: true }), status: z.string(), symbol: z.string(), template_id: z.union([z.string(), z.null()]).optional(), }); export const FieldType = z.enum(["Text", "Password", "Url", "Boolean", "Select"]); export const ConfigKey = z.enum([ "ApiKey", "ApiToken", "ApiUrl", "BaseUrl", "SecretKey", "Username", "Password", "SandboxMode", "Region", ]); export const ConfigFieldSchema = z.object({ default_value: z.union([z.string(), z.null()]).optional(), description: z.union([z.string(), z.null()]).optional(), field_type: FieldType, key: ConfigKey, label: z.string(), options: z.union([z.array(z.string()), z.null()]).optional(), placeholder: z.union([z.string(), z.null()]).optional(), required: z.boolean(), }); export const ProviderMetadata = z.object({ config_schema: z.array(ConfigFieldSchema), description: z.string(), icon_url: z.union([z.string(), z.null()]).optional(), id: z.string(), name_cn: z.string(), name_en: z.string(), supports_test_connection: z.boolean(), }); export const SymbolResolveRequest = z.object({ market: z.union([z.string(), z.null()]).optional(), symbol: z.string(), }); export const SymbolResolveResponse = z.object({ market: z.string(), symbol: z.string(), }); export const DataRequest = z.object({ market: z.union([z.string(), z.null()]).optional(), symbol: z.string(), template_id: z.string(), }); export const RequestAcceptedResponse = z.object({ market: z.string(), request_id: z.string().uuid(), symbol: z.string(), }); export const ObservabilityTaskStatus = z.enum([ "Queued", "InProgress", "Completed", "Failed", ]); export const TaskProgress = z.object({ details: z.string(), progress_percent: z.number().int().gte(0), request_id: z.string().uuid(), started_at: z.string().datetime({ offset: true }), status: ObservabilityTaskStatus, task_name: z.string(), }); export const CanonicalSymbol = z.string(); export const ServiceStatus = z.enum(["Ok", "Degraded", "Unhealthy"]); export const HealthStatus = z.object({ details: z.record(z.string()), module_id: z.string(), status: ServiceStatus, version: z.string(), }); export const StartWorkflowCommand = z.object({ market: z.string(), request_id: z.string().uuid(), symbol: CanonicalSymbol, template_id: z.string(), }); export const TaskDependency = z.object({ from: z.string(), to: z.string(), }); export const TaskMetadata = z .object({ execution_log_path: z.union([z.string(), z.null()]), output_path: z.union([z.string(), z.null()]), }) .partial(); export const TaskStatus = z.enum([ "Pending", "Scheduled", "Running", "Completed", "Failed", "Skipped", ]); export const TaskType = z.enum(["DataFetch", "DataProcessing", "Analysis"]); export const TaskNode = z.object({ display_name: z.union([z.string(), z.null()]).optional(), id: z.string(), initial_status: TaskStatus, name: z.string(), type: TaskType, }); export const WorkflowDag = z.object({ edges: z.array(TaskDependency), nodes: z.array(TaskNode), }); export const WorkflowEvent = z.union([ z .object({ payload: z .object({ task_graph: WorkflowDag, timestamp: z.number().int() }) .passthrough(), type: z.literal("WorkflowStarted"), }) .passthrough(), z .object({ payload: z .object({ input_commit: z.union([z.string(), z.null()]).optional(), message: z.union([z.string(), z.null()]).optional(), output_commit: z.union([z.string(), z.null()]).optional(), progress: z.union([z.number(), z.null()]).optional(), status: TaskStatus, task_id: z.string(), task_type: TaskType, timestamp: z.number().int(), }) .passthrough(), type: z.literal("TaskStateChanged"), }) .passthrough(), z .object({ payload: z .object({ content_delta: z.string(), index: z.number().int().gte(0), task_id: z.string(), }) .passthrough(), type: z.literal("TaskStreamUpdate"), }) .passthrough(), z .object({ payload: z .object({ level: z.string(), message: z.string(), task_id: z.string(), timestamp: z.number().int(), }) .passthrough(), type: z.literal("TaskLog"), }) .passthrough(), z .object({ payload: z .object({ end_timestamp: z.number().int(), result_summary: z.unknown().optional(), }) .passthrough(), type: z.literal("WorkflowCompleted"), }) .passthrough(), z .object({ payload: z .object({ end_timestamp: z.number().int(), is_fatal: z.boolean(), reason: z.string(), }) .passthrough(), type: z.literal("WorkflowFailed"), }) .passthrough(), z .object({ payload: z .object({ task_graph: WorkflowDag, tasks_metadata: z.record(TaskMetadata), tasks_output: z.record(z.union([z.string(), z.null()])), tasks_status: z.record(TaskStatus), timestamp: z.number().int(), }) .passthrough(), type: z.literal("WorkflowStateSnapshot"), }) .passthrough(), ]); export const schemas = { LlmConfig, SelectionMode, ContextSelectorConfig, AnalysisModuleConfig, AnalysisTemplateSet, AnalysisTemplateSets, DataSourceProvider, DataSourceConfig, DataSourcesConfig, TestLlmConfigRequest, LlmModel, LlmProvider, LlmProvidersConfig, TestConfigRequest, TestConnectionResponse, DiscoverPreviewRequest, WorkflowHistorySummaryDto, Value, WorkflowHistoryDto, FieldType, ConfigKey, ConfigFieldSchema, ProviderMetadata, SymbolResolveRequest, SymbolResolveResponse, DataRequest, RequestAcceptedResponse, ObservabilityTaskStatus, TaskProgress, CanonicalSymbol, ServiceStatus, HealthStatus, StartWorkflowCommand, TaskDependency, TaskMetadata, TaskStatus, TaskType, TaskNode, WorkflowDag, WorkflowEvent, }; export const endpoints = makeApi([ { method: "get", path: "/api/v1/configs/analysis_template_sets", alias: "get_analysis_template_sets", requestFormat: "json", response: z.record(AnalysisTemplateSet), }, { method: "put", path: "/api/v1/configs/analysis_template_sets", alias: "update_analysis_template_sets", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: z.record(AnalysisTemplateSet), }, ], response: z.record(AnalysisTemplateSet), }, { method: "get", path: "/api/v1/configs/data_sources", alias: "get_data_sources_config", requestFormat: "json", response: z.record(DataSourceConfig), }, { method: "put", path: "/api/v1/configs/data_sources", alias: "update_data_sources_config", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: z.record(DataSourceConfig), }, ], response: z.record(DataSourceConfig), }, { method: "get", path: "/api/v1/configs/llm_providers", alias: "get_llm_providers_config", requestFormat: "json", response: z.record(LlmProvider), }, { method: "put", path: "/api/v1/configs/llm_providers", alias: "update_llm_providers_config", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: z.record(LlmProvider), }, ], response: z.record(LlmProvider), }, { method: "post", path: "/api/v1/configs/llm/test", alias: "test_llm_config", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: TestLlmConfigRequest, }, ], response: z.void(), }, { method: "post", path: "/api/v1/configs/test", alias: "test_data_source_config", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: z.object({ data: z.unknown(), type: z.string() }), }, ], response: TestConnectionResponse, }, { method: "post", path: "/api/v1/discover-models", alias: "discover_models_preview", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: DiscoverPreviewRequest, }, ], response: z.void(), errors: [ { status: 502, description: `Provider error`, schema: z.void(), }, ], }, { method: "get", path: "/api/v1/discover-models/:provider_id", alias: "discover_models", requestFormat: "json", parameters: [ { name: "provider_id", type: "Path", schema: z.string(), }, ], response: z.void(), errors: [ { status: 404, description: `Provider not found`, schema: z.void(), }, { status: 502, description: `Provider error`, schema: z.void(), }, ], }, { method: "get", path: "/api/v1/history", alias: "get_workflow_histories", requestFormat: "json", parameters: [ { name: "symbol", type: "Query", schema: z.string().optional(), }, { name: "limit", type: "Query", schema: z.number().int().optional(), }, ], response: z.array(WorkflowHistorySummaryDto), }, { method: "get", path: "/api/v1/history/:request_id", alias: "get_workflow_history_by_id", requestFormat: "json", parameters: [ { name: "request_id", type: "Path", schema: z.string().uuid(), }, ], response: WorkflowHistoryDto, errors: [ { status: 404, description: `History not found`, schema: z.void(), }, ], }, { method: "get", path: "/api/v1/registry/providers", alias: "get_registered_providers", requestFormat: "json", response: z.array(ProviderMetadata), }, { method: "post", path: "/api/v1/tools/resolve-symbol", alias: "resolve_symbol", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: SymbolResolveRequest, }, ], response: SymbolResolveResponse, }, { method: "post", path: "/api/v1/workflow/start", alias: "start_workflow", requestFormat: "json", parameters: [ { name: "body", type: "Body", schema: DataRequest, }, ], response: RequestAcceptedResponse, }, { method: "get", path: "/health", alias: "health_check", requestFormat: "json", response: z.void(), }, { method: "get", path: "/tasks/:request_id", alias: "get_task_progress", requestFormat: "json", parameters: [ { name: "request_id", type: "Path", schema: z.string().uuid(), }, ], response: z.array(TaskProgress), errors: [ { status: 404, description: `Tasks not found`, schema: z.void(), }, ], }, ]); export const api = new Zodios(endpoints); export function createApiClient(baseUrl: string, options?: ZodiosOptions) { return new Zodios(baseUrl, endpoints, options); }