This document describes the architecture and code organization of the AgentScript Migration Tool.
The codebase is organized into logical modules following the Single Responsibility Principle. Each module has a clear, focused purpose.
src/
├── index.ts # Main exports (public API)
├── generator.ts # Main orchestrator class (~120 lines)
├── types.ts # TypeScript type definitions
├── validation.ts # Input validation utilities
├── validation.test.ts # Validation tests
├── generator.test.ts # Generator tests
├── js-yaml.d.ts # Type declarations
│
├── builders/ # Builder modules (single responsibility)
│ ├── index.ts # Builder exports
│ ├── configBuilder.ts # Config block builder
│ ├── systemBuilder.ts # System block builder
│ ├── languageBuilder.ts # Language block builder
│ ├── variablesBuilder.ts # Variables block builder
│ ├── topicBuilder.ts # Topic block builder
│ ├── actionBuilder.ts # Action block builder
│ └── startAgentBuilder.ts # Start agent builder
│
├── formatters/ # YAML formatting modules
│ ├── index.ts # Formatter exports
│ └── yamlFormatter.ts # YAML conversion and formatting
│
└── utils/ # Utility functions
├── index.ts # Utility exports
└── nameSanitizer.ts # Name sanitization utilities
- Purpose: Main orchestrator class
- Responsibilities:
- Validates input
- Coordinates builders
- Calls formatter
- Error handling
- Dependencies: builders, formatters, validation, utils
- Purpose: TypeScript type definitions
- Responsibilities:
- Define all interfaces
- Export types for consumers
- Dependencies: None
- Purpose: Input validation
- Responsibilities:
- Validate planner structure
- Validate topics and actions
- Sanitize strings
- Validate options
- Dependencies: types
Each builder module is responsible for constructing a specific part of the Agent Script structure.
- Builds the
configblock - Handles agent metadata
- Builds the
systemblock - Handles global instructions and messages
- Builds the
languageblock - Handles locale configuration
- Builds the
variablesblock - Converts planner variables to Agent Script variables
- Handles type inference
- Builds individual topic blocks
- Generates topic instructions
- Handles topic actions
- Builds action definitions
- Formats action targets
- Handles inputs/outputs
- Supports all action types (Flow, Apex, etc.)
- Builds the
start_agent topic_selectorblock - Creates transition actions
- Purpose: Convert Agent Script structure to YAML
- Responsibilities:
- YAML serialization
- Format transformations (compact format, Python booleans, etc.)
- Instruction formatting (
->syntax) - Variable formatting
- Action formatting
- Dependencies: types, js-yaml
- Purpose: Sanitize names for Agent Script compatibility
- Responsibilities:
- Clean developer names (remove IDs)
- Sanitize topic names
- Sanitize action names
- Dependencies: None
Each module has one clear responsibility:
- Builders build specific blocks
- Formatters format YAML
- Utils provide reusable functions
- Validators validate input
- Building (builders/) - Construct data structures
- Formatting (formatters/) - Convert to YAML
- Validation (validation.ts) - Validate input
- Utilities (utils/) - Reusable functions
generator.ts
├── builders/ (depends on types, utils)
├── formatters/ (depends on types)
├── validation.ts (depends on types)
└── utils/ (no dependencies)
Each module can be tested independently:
- Builders can be tested with mock data
- Formatters can be tested with known structures
- Validators can be tested with various inputs
- Utils can be tested with unit tests
generator.ts: ~888 lines (monolithic)
generator.ts: ~120 lines (orchestrator)builders/: ~360 lines (8 modules, ~45 lines each)formatters/: ~350 lines (1 module)utils/: ~100 lines (1 module)validation.ts: ~150 lines
Total: ~1080 lines (slightly more due to module overhead, but much more maintainable)
- Easy to find code (clear module names)
- Changes are isolated to specific modules
- Reduced cognitive load
- Each module can be tested independently
- Mock dependencies easily
- Clear test boundaries
- Builders can be reused in other contexts
- Utils are framework-agnostic
- Formatters can be extended
- Easy to add new builders
- Easy to add new formatters
- Easy to extend functionality
- Small, focused files
- Clear naming conventions
- Self-documenting structure
- Create
builders/newBuilder.ts - Export from
builders/index.ts - Use in
generator.ts - Add tests
- Create
formatters/newFormatter.ts - Export from
formatters/index.ts - Use in
yamlFormatter.ts - Add tests
- Create
utils/newUtility.ts - Export from
utils/index.ts - Use where needed
- Add tests
generator.ts
│
├─── validation.ts ──┐
│ │
├─── builders/ ──────┼─── types.ts
│ ├── configBuilder.ts
│ ├── systemBuilder.ts
│ ├── languageBuilder.ts
│ ├── variablesBuilder.ts
│ ├── topicBuilder.ts
│ ├── actionBuilder.ts
│ └── startAgentBuilder.ts
│
├─── formatters/ ────┘
│ └── yamlFormatter.ts
│
└─── utils/
└── nameSanitizer.ts
- Keep modules focused: Each module should do one thing well
- Minimize dependencies: Prefer composition over deep nesting
- Export explicitly: Use named exports for clarity
- Document interfaces: JSDoc comments for public APIs
- Test independently: Each module should have its own tests
Potential areas for further modularization:
- Parser Module: If we add YAML parsing
- Validator Module: More complex validation rules
- Transformer Module: Data transformations
- Plugin System: Extensible builders/formatters