oxify_model/
typescript.rs1pub fn generate_typescript_definitions() -> String {
31 let mut output = String::new();
32
33 output.push_str(HEADER);
34 output.push_str(WORKFLOW_TYPES);
35 output.push_str(NODE_TYPES);
36 output.push_str(EDGE_TYPES);
37 output.push_str(EXECUTION_TYPES);
38 output.push_str(CONFIG_TYPES);
39 output.push_str(UTILITY_TYPES);
40 output.push_str(WASM_BINDINGS);
41
42 output
43}
44
45const HEADER: &str = r#"/**
46 * OxiFY Model - TypeScript Type Definitions
47 *
48 * Auto-generated TypeScript definitions for OxiFY workflow models.
49 * These types are compatible with the WASM bindings provided by oxify-model.
50 *
51 * @version 0.1.0
52 * @generated
53 */
54
55"#;
56
57const WORKFLOW_TYPES: &str = r#"// ============================================================================
58// Workflow Types
59// ============================================================================
60
61/** UUID string type for unique identifiers */
62export type UUID = string;
63
64/** ISO 8601 date-time string */
65export type DateTime = string;
66
67/** Unique identifier for a workflow */
68export type WorkflowId = UUID;
69
70/** Unique identifier for a node */
71export type NodeId = UUID;
72
73/** Unique identifier for an edge */
74export type EdgeId = UUID;
75
76/** Metadata about a workflow */
77export interface WorkflowMetadata {
78 /** Unique workflow identifier */
79 id: WorkflowId;
80 /** Display name */
81 name: string;
82 /** Description of what this workflow does */
83 description?: string;
84 /** Version string (semantic versioning) */
85 version: string;
86 /** When the workflow was created */
87 created_at: DateTime;
88 /** When the workflow was last modified */
89 updated_at: DateTime;
90 /** Tags for categorization */
91 tags: string[];
92 /** Parent workflow ID (for versioning) */
93 parent_id?: WorkflowId;
94 /** Change description for this version */
95 change_description?: string;
96 /** Scheduling configuration */
97 schedule?: WorkflowSchedule;
98}
99
100/** Workflow scheduling configuration */
101export interface WorkflowSchedule {
102 /** Cron expression for scheduling */
103 cron: string;
104 /** Timezone (e.g., "UTC", "America/New_York") */
105 timezone?: string;
106 /** Whether the schedule is enabled */
107 enabled: boolean;
108}
109
110/** Version bump type */
111export type VersionBump = "major" | "minor" | "patch";
112
113/** Complete workflow definition */
114export interface Workflow {
115 /** Workflow metadata */
116 metadata: WorkflowMetadata;
117 /** Nodes in the workflow DAG */
118 nodes: Node[];
119 /** Edges connecting nodes */
120 edges: Edge[];
121}
122
123"#;
124
125const NODE_TYPES: &str = r#"// ============================================================================
126// Node Types
127// ============================================================================
128
129/** Node in the workflow DAG */
130export interface Node {
131 /** Unique node identifier */
132 id: NodeId;
133 /** Display name of the node */
134 name: string;
135 /** Type and configuration of the node */
136 kind: NodeKind;
137 /** Position in the visual editor */
138 position?: [number, number];
139 /** Retry configuration */
140 retry_config?: RetryConfig;
141 /** Timeout configuration */
142 timeout_config?: TimeoutConfig;
143}
144
145/** Retry configuration for nodes */
146export interface RetryConfig {
147 /** Maximum number of retry attempts */
148 max_retries: number;
149 /** Initial delay before first retry in milliseconds */
150 initial_delay_ms: number;
151 /** Backoff multiplier for exponential backoff */
152 backoff_multiplier: number;
153 /** Maximum delay between retries in milliseconds */
154 max_delay_ms: number;
155}
156
157/** Timeout configuration for nodes */
158export interface TimeoutConfig {
159 /** Maximum execution time in milliseconds */
160 execution_timeout_ms: number;
161 /** Idle timeout in milliseconds */
162 idle_timeout_ms?: number;
163 /** Action to take on timeout */
164 timeout_action: TimeoutAction;
165}
166
167/** Action to take when a timeout occurs */
168export type TimeoutAction = "Fail" | "Skip" | "UseDefault";
169
170/** Node kind discriminated union */
171export type NodeKind =
172 | { Start: {} }
173 | { End: {} }
174 | { LlmCall: LlmConfig }
175 | { Retriever: VectorConfig }
176 | { CodeExecution: ScriptConfig }
177 | { IfElse: Condition }
178 | { Switch: SwitchConfig }
179 | { Tool: McpConfig }
180 | { Loop: LoopConfig }
181 | { TryCatch: TryCatchConfig }
182 | { SubWorkflow: SubWorkflowConfig }
183 | { Parallel: ParallelConfig }
184 | { Approval: ApprovalConfig }
185 | { Form: FormConfig };
186
187/** LLM call configuration */
188export interface LlmConfig {
189 /** LLM provider (e.g., "openai", "anthropic", "ollama") */
190 provider: string;
191 /** Model name (e.g., "gpt-4", "claude-3-opus") */
192 model: string;
193 /** System prompt template */
194 system_prompt?: string;
195 /** User prompt template with {{variable}} placeholders */
196 prompt_template: string;
197 /** Temperature for sampling (0.0 - 2.0) */
198 temperature?: number;
199 /** Maximum tokens to generate */
200 max_tokens?: number;
201 /** Stop sequences */
202 stop_sequences?: string[];
203 /** Response format (json, text) */
204 response_format?: string;
205}
206
207/** Vector database configuration */
208export interface VectorConfig {
209 /** Database type (e.g., "qdrant", "pgvector") */
210 db_type: string;
211 /** Collection name */
212 collection: string;
213 /** Query template */
214 query: string;
215 /** Number of results to return */
216 top_k: number;
217 /** Minimum similarity score threshold */
218 score_threshold?: number;
219 /** Embedding model to use */
220 embedding_model?: string;
221}
222
223/** Script execution configuration */
224export interface ScriptConfig {
225 /** Runtime environment */
226 runtime: "rhai" | "wasm";
227 /** Script code */
228 code: string;
229 /** Input variable mappings */
230 input_mapping?: Record<string, string>;
231 /** Output variable name */
232 output_variable?: string;
233}
234
235/** Conditional node configuration */
236export interface Condition {
237 /** Boolean expression to evaluate */
238 expression: string;
239 /** Node ID for true branch */
240 true_branch: NodeId;
241 /** Node ID for false branch */
242 false_branch: NodeId;
243}
244
245/** Switch/case configuration */
246export interface SwitchConfig {
247 /** Expression to switch on */
248 switch_on: string;
249 /** Case definitions */
250 cases: SwitchCase[];
251 /** Default case action */
252 default_case?: string;
253}
254
255/** Single switch case */
256export interface SwitchCase {
257 /** Value to match */
258 match_value: string;
259 /** Action expression or node to execute */
260 action: string;
261}
262
263/** MCP tool configuration */
264export interface McpConfig {
265 /** MCP server ID */
266 server_id: string;
267 /** Tool name */
268 tool_name: string;
269 /** Tool arguments template */
270 arguments_template?: string;
271}
272
273/** Loop configuration */
274export interface LoopConfig {
275 /** Type of loop */
276 loop_type: LoopType;
277 /** Maximum iterations (safety limit) */
278 max_iterations: number;
279 /** Body expression to execute */
280 body: string;
281}
282
283/** Loop type variants */
284export type LoopType =
285 | { ForEach: ForEachLoop }
286 | { While: WhileLoop }
287 | { Repeat: RepeatLoop };
288
289/** ForEach loop configuration */
290export interface ForEachLoop {
291 /** Path to collection to iterate over */
292 collection_path: string;
293 /** Variable name for current item */
294 item_variable: string;
295 /** Variable name for current index */
296 index_variable?: string;
297 /** Body expression */
298 body_expression: string;
299 /** Enable parallel execution of loop iterations */
300 parallel: boolean;
301 /** Maximum number of concurrent iterations (only used when parallel=true) */
302 max_concurrency?: number;
303}
304
305/** While loop configuration */
306export interface WhileLoop {
307 /** Condition expression */
308 condition: string;
309 /** Body expression */
310 body_expression: string;
311}
312
313/** Repeat loop configuration */
314export interface RepeatLoop {
315 /** Number of times to repeat */
316 count: number;
317 /** Body expression */
318 body_expression: string;
319}
320
321/** Try-catch configuration */
322export interface TryCatchConfig {
323 /** Node ID to try */
324 try_node: NodeId;
325 /** Node ID for catch handler */
326 catch_node?: NodeId;
327 /** Node ID for finally handler */
328 finally_node?: NodeId;
329 /** Variable name for error */
330 error_variable?: string;
331 /** Whether to rethrow after catch */
332 rethrow?: boolean;
333}
334
335/** Sub-workflow configuration */
336export interface SubWorkflowConfig {
337 /** Path to sub-workflow file */
338 workflow_path: string;
339 /** Input variable mappings */
340 input_mappings?: Record<string, string>;
341 /** Output variable mappings */
342 output_mappings?: Record<string, string>;
343 /** Whether to inherit parent context */
344 inherit_context?: boolean;
345}
346
347/** Parallel execution configuration */
348export interface ParallelConfig {
349 /** Tasks to execute in parallel */
350 tasks: ParallelTask[];
351 /** Execution strategy */
352 strategy: ParallelStrategy;
353 /** Timeout in milliseconds */
354 timeout_ms?: number;
355 /** Maximum concurrent tasks */
356 max_concurrency?: number;
357}
358
359/** Single parallel task */
360export interface ParallelTask {
361 /** Task identifier */
362 id: string;
363 /** Expression to execute */
364 expression: string;
365}
366
367/** Parallel execution strategy */
368export type ParallelStrategy = "WaitAll" | "Race" | "AllSettled";
369
370/** Approval node configuration */
371export interface ApprovalConfig {
372 /** Message to display for approval */
373 message: string;
374 /** Detailed description */
375 description?: string;
376 /** Required approvers (user IDs or roles) */
377 required_approvers?: string[];
378 /** Timeout in milliseconds */
379 timeout_ms?: number;
380 /** Context data for approval UI */
381 context_data?: Record<string, unknown>;
382}
383
384/** Form node configuration */
385export interface FormConfig {
386 /** Form title */
387 title: string;
388 /** Form description */
389 description?: string;
390 /** Form fields */
391 fields: FormField[];
392 /** Submit button label */
393 submit_label?: string;
394 /** Allowed submitters */
395 allowed_submitters?: string[];
396 /** Timeout in milliseconds */
397 timeout_ms?: number;
398}
399
400/** Form field definition */
401export interface FormField {
402 /** Field identifier */
403 id: string;
404 /** Field label */
405 label: string;
406 /** Field type */
407 field_type: FormFieldType;
408 /** Whether field is required */
409 required: boolean;
410 /** Default value */
411 default_value?: unknown;
412 /** Placeholder text */
413 placeholder?: string;
414 /** Help text */
415 help_text?: string;
416 /** Validation pattern (regex) */
417 validation_pattern?: string;
418 /** Options for select/radio fields */
419 options?: string[];
420}
421
422/** Form field types */
423export type FormFieldType =
424 | "Text"
425 | "Number"
426 | "Email"
427 | "Password"
428 | "TextArea"
429 | "Select"
430 | "MultiSelect"
431 | "Radio"
432 | "Checkbox"
433 | "Date"
434 | "DateTime";
435
436"#;
437
438const EDGE_TYPES: &str = r#"// ============================================================================
439// Edge Types
440// ============================================================================
441
442/** Edge connecting two nodes */
443export interface Edge {
444 /** Unique edge identifier */
445 id: EdgeId;
446 /** Source node ID */
447 from: NodeId;
448 /** Target node ID */
449 to: NodeId;
450 /** Condition for conditional edges */
451 condition?: string;
452 /** Edge label */
453 label?: string;
454}
455
456"#;
457
458const EXECUTION_TYPES: &str = r#"// ============================================================================
459// Execution Types
460// ============================================================================
461
462/** Execution state */
463export type ExecutionState =
464 | "Pending"
465 | "Running"
466 | "Completed"
467 | "Failed"
468 | "Cancelled"
469 | "Paused";
470
471/** Unique identifier for an execution */
472export type ExecutionId = UUID;
473
474/** Execution context variables */
475export type ExecutionContext = Record<string, unknown>;
476
477/** Node execution result */
478export interface NodeExecutionResult {
479 /** Node ID */
480 node_id: NodeId;
481 /** Execution state */
482 state: ExecutionState;
483 /** Output value */
484 output?: unknown;
485 /** Error message if failed */
486 error?: string;
487 /** Execution duration in milliseconds */
488 duration_ms?: number;
489 /** Token usage for LLM nodes */
490 token_usage?: TokenUsage;
491 /** Number of retry attempts */
492 retry_count?: number;
493}
494
495/** Token usage for LLM calls */
496export interface TokenUsage {
497 /** Input tokens */
498 input_tokens: number;
499 /** Output tokens */
500 output_tokens: number;
501 /** Total tokens */
502 total_tokens: number;
503}
504
505/** Complete execution result */
506export interface ExecutionResult {
507 /** Execution ID */
508 id: ExecutionId;
509 /** Workflow ID */
510 workflow_id: WorkflowId;
511 /** Overall state */
512 state: ExecutionState;
513 /** Started at timestamp */
514 started_at: DateTime;
515 /** Completed at timestamp */
516 completed_at?: DateTime;
517 /** Node results */
518 node_results: Record<string, NodeExecutionResult>;
519 /** Final context */
520 context: ExecutionContext;
521 /** Total duration in milliseconds */
522 duration_ms?: number;
523 /** Total cost in USD */
524 cost_usd?: number;
525}
526
527"#;
528
529const CONFIG_TYPES: &str = r#"// ============================================================================
530// Configuration Types
531// ============================================================================
532
533/** Cost estimate for a workflow */
534export interface CostEstimate {
535 /** Total estimated cost in USD */
536 total_cost_usd: number;
537 /** Cost breakdown by node */
538 node_costs: NodeCost[];
539 /** Cost breakdown by category */
540 category_costs: CategoryCosts;
541 /** Token estimates */
542 token_estimates: TokenEstimates;
543}
544
545/** Cost for a single node */
546export interface NodeCost {
547 /** Node ID */
548 node_id: NodeId;
549 /** Node name */
550 node_name: string;
551 /** Estimated cost in USD */
552 cost_usd: number;
553 /** Cost components */
554 components: CostComponent[];
555}
556
557/** Cost component */
558export interface CostComponent {
559 /** Component name */
560 name: string;
561 /** Cost in USD */
562 cost_usd: number;
563 /** Quantity */
564 quantity?: number;
565 /** Unit */
566 unit?: string;
567}
568
569/** Costs by category */
570export interface CategoryCosts {
571 /** LLM costs */
572 llm: number;
573 /** Vector search costs */
574 vector: number;
575 /** Tool/API costs */
576 tool: number;
577 /** Other costs */
578 other: number;
579}
580
581/** Token estimates */
582export interface TokenEstimates {
583 /** Estimated input tokens */
584 input_tokens: number;
585 /** Estimated output tokens */
586 output_tokens: number;
587 /** Total estimated tokens */
588 total_tokens: number;
589}
590
591/** Time estimate for a workflow */
592export interface TimeEstimate {
593 /** Total estimated time in milliseconds */
594 total_ms: number;
595 /** Time per node */
596 node_times: NodeTime[];
597 /** Critical path */
598 critical_path: NodeId[];
599 /** Estimated parallel speedup factor */
600 parallel_speedup: number;
601}
602
603/** Time estimate for a single node */
604export interface NodeTime {
605 /** Node ID */
606 node_id: NodeId;
607 /** Node name */
608 node_name: string;
609 /** Estimated time in milliseconds */
610 estimated_ms: number;
611 /** Minimum time in milliseconds */
612 min_ms?: number;
613 /** Maximum time in milliseconds */
614 max_ms?: number;
615}
616
617"#;
618
619const UTILITY_TYPES: &str = r#"// ============================================================================
620// Utility Types
621// ============================================================================
622
623/** Validation error */
624export interface ValidationError {
625 /** Error code */
626 code: string;
627 /** Error message */
628 message: string;
629 /** Related node ID */
630 node_id?: NodeId;
631 /** Related field */
632 field?: string;
633}
634
635/** Validation report */
636export interface ValidationReport {
637 /** Whether validation passed */
638 is_valid: boolean;
639 /** Validation errors */
640 errors: ValidationError[];
641 /** Validation warnings */
642 warnings: ValidationError[];
643 /** Validation statistics */
644 stats: ValidationStats;
645}
646
647/** Validation statistics */
648export interface ValidationStats {
649 /** Number of nodes */
650 node_count: number;
651 /** Number of edges */
652 edge_count: number;
653 /** Workflow depth */
654 max_depth: number;
655 /** Has cycles */
656 has_cycles: boolean;
657}
658
659"#;
660
661const WASM_BINDINGS: &str = r#"// ============================================================================
662// WASM Bindings
663// ============================================================================
664
665/**
666 * WASM-based workflow manipulation.
667 * Use with oxify-model compiled with `wasm-pack build --features wasm`
668 */
669export interface WasmWorkflow {
670 /** Get workflow as JSON string */
671 to_json(): string;
672 /** Get workflow as YAML string */
673 to_yaml(): string;
674 /** Get workflow ID */
675 id(): string;
676 /** Get workflow name */
677 name(): string;
678 /** Get workflow version */
679 version(): string;
680 /** Get node count */
681 node_count(): number;
682 /** Get edge count */
683 edge_count(): number;
684 /** Validate workflow */
685 validate(): string;
686}
687
688/**
689 * Fluent builder for creating workflows.
690 */
691export interface WasmWorkflowBuilder {
692 /** Set workflow description */
693 description(desc: string): WasmWorkflowBuilder;
694 /** Set workflow version */
695 version(version: string): WasmWorkflowBuilder;
696 /** Add a tag */
697 tag(tag: string): WasmWorkflowBuilder;
698 /** Add start node */
699 start_node(name: string): WasmWorkflowBuilder;
700 /** Add end node */
701 end_node(name: string): WasmWorkflowBuilder;
702 /** Add LLM node */
703 llm_node(name: string, provider: string, model: string, prompt: string): WasmWorkflowBuilder;
704 /** Add code node */
705 code_node(name: string, code: string): WasmWorkflowBuilder;
706 /** Add retriever node */
707 retriever_node(name: string, db_type: string, collection: string, query: string, top_k: number): WasmWorkflowBuilder;
708 /** Add if-else node */
709 if_else_node(name: string, expression: string, true_branch: string, false_branch: string): WasmWorkflowBuilder;
710 /** Add switch node */
711 switch_node(name: string, expression: string): WasmWorkflowBuilder;
712 /** Add tool node */
713 tool_node(name: string, server_id: string, tool_name: string): WasmWorkflowBuilder;
714 /** Add foreach loop node */
715 foreach_node(name: string, collection_path: string, item_var: string, body: string): WasmWorkflowBuilder;
716 /** Add while loop node */
717 while_node(name: string, condition: string, body: string, max_iterations: number): WasmWorkflowBuilder;
718 /** Add repeat loop node */
719 repeat_node(name: string, count: number, body: string): WasmWorkflowBuilder;
720 /** Connect two nodes */
721 connect(from_name: string, to_name: string): WasmWorkflowBuilder;
722 /** Build the workflow */
723 build(): WasmWorkflow;
724}
725
726/**
727 * Utility functions for working with workflows.
728 */
729export interface WasmWorkflowUtils {
730 /** Generate a new UUID */
731 generate_uuid(): string;
732 /** Convert JSON to YAML */
733 json_to_yaml(json: string): string;
734 /** Convert YAML to JSON */
735 yaml_to_json(yaml: string): string;
736}
737
738/** Create a new workflow from JSON */
739export function workflow_from_json(json: string): WasmWorkflow;
740
741/** Create a new workflow from YAML */
742export function workflow_from_yaml(yaml: string): WasmWorkflow;
743
744/** Create a new workflow builder */
745export function new_workflow_builder(name: string): WasmWorkflowBuilder;
746
747/** Get workflow utilities */
748export function workflow_utils(): WasmWorkflowUtils;
749"#;
750
751#[cfg(test)]
752mod tests {
753 use super::*;
754
755 #[test]
756 fn test_generate_typescript_definitions() {
757 let definitions = generate_typescript_definitions();
758 assert!(!definitions.is_empty());
759 assert!(definitions.contains("export interface Workflow"));
760 assert!(definitions.contains("export interface Node"));
761 assert!(definitions.contains("export interface Edge"));
762 assert!(definitions.contains("export type NodeKind"));
763 assert!(definitions.contains("export interface LlmConfig"));
764 assert!(definitions.contains("export interface VectorConfig"));
765 }
766
767 #[test]
768 fn test_definitions_contain_all_node_types() {
769 let definitions = generate_typescript_definitions();
770 assert!(definitions.contains("LlmCall"));
771 assert!(definitions.contains("Retriever"));
772 assert!(definitions.contains("CodeExecution"));
773 assert!(definitions.contains("IfElse"));
774 assert!(definitions.contains("Switch"));
775 assert!(definitions.contains("Loop"));
776 assert!(definitions.contains("TryCatch"));
777 assert!(definitions.contains("SubWorkflow"));
778 assert!(definitions.contains("Parallel"));
779 assert!(definitions.contains("Approval"));
780 assert!(definitions.contains("Form"));
781 }
782
783 #[test]
784 fn test_definitions_contain_execution_types() {
785 let definitions = generate_typescript_definitions();
786 assert!(definitions.contains("ExecutionState"));
787 assert!(definitions.contains("ExecutionResult"));
788 assert!(definitions.contains("NodeExecutionResult"));
789 assert!(definitions.contains("TokenUsage"));
790 }
791
792 #[test]
793 fn test_definitions_contain_wasm_bindings() {
794 let definitions = generate_typescript_definitions();
795 assert!(definitions.contains("WasmWorkflow"));
796 assert!(definitions.contains("WasmWorkflowBuilder"));
797 assert!(definitions.contains("WasmWorkflowUtils"));
798 assert!(definitions.contains("workflow_from_json"));
799 assert!(definitions.contains("new_workflow_builder"));
800 }
801
802 #[test]
803 fn test_definitions_contain_config_types() {
804 let definitions = generate_typescript_definitions();
805 assert!(definitions.contains("CostEstimate"));
806 assert!(definitions.contains("TimeEstimate"));
807 assert!(definitions.contains("ValidationReport"));
808 }
809
810 #[test]
811 fn test_definitions_valid_typescript_syntax() {
812 let definitions = generate_typescript_definitions();
813 assert!(definitions.contains("export interface"));
815 assert!(definitions.contains("export type"));
816 assert!(definitions.contains(": string"));
817 assert!(definitions.contains(": number"));
818 assert!(definitions.contains("?: ")); assert!(definitions.contains("Record<")); }
821}