This is the abridged developer documentation for RCL Documentation # RCL Documentation > Rich Communication Language - A domain-specific language for creating RCS agents Welcome to the RCL (Rich Communication Language) documentation. ## Core Documentation [Section titled “Core Documentation”](#core-documentation) * [RCL Formal Specification](/rcl-formal-specification) - Complete EBNF grammar specification * [RCL Output Specification](/rcl-output-specification) - JSON/JS output format documentation * [Getting Started](/getting-started) - Quick start guide * [API Reference](/api) - API documentation * [Examples](/examples) - Example RCL files * [Release Guide](/release-guide) - Release process documentation * [Local CI](/local-ci) - Local CI setup * [Conversational Agent FSM Requirements](/conversational-agent-fsm-requirements) - FSM requirements ## Package Documentation [Section titled “Package Documentation”](#package-documentation) ### Core Packages [Section titled “Core Packages”](#core-packages) * **AST Package** - [Documentation](/packages/ast) * **Parser Package** - [Documentation](/packages/parser) * **Compiler Package** - [Documentation](/packages/compiler) * **Language Service Package** - [Documentation](/packages/language-service) * **CSM (Conversational State Machine) Package** - [Documentation](/packages/csm) ## Applications [Section titled “Applications”](#applications) * **CLI** - Command-line compiler for RCL files * **VSCode Extension** - Full language support for VSCode ## Creators [Section titled “Creators”](#creators) RCL was created with ❤️ by these amazing developers: ![Felipe Hlibco avatar](https://avatars.githubusercontent.com/u/755307?v=4) ### Felipe Hlibco Core Architecture & Tooling Ecosystem 📍 San Francisco Developer Relations Engineer @ Google, passionate about creating tools that make developers' lives easier [ ](https://github.com/hlibco)[ ](https://www.hlibco.com)[](https://twitter.com/hlibco) ![Saulo Vallory avatar](https://avatars.githubusercontent.com/u/117560?v=4) ### Saulo Vallory Language Design & Parser Implementation 📍 Rio de Janeiro Social Alchemist, curious, creative, 2e (twice-exceptional), poet, songwriter, dancer, guitarist, amateur cook, oh... and a polyglot Senior Software Engineer 😁 [ ](https://github.com/svallory)[ ](https://saulo.engineer)[](https://twitter.com/svallory_en) # API Reference > Comprehensive API documentation for all RCL packages # RCL Language API Documentation [Section titled “RCL Language API Documentation”](#rcl-language-api-documentation) ## Overview [Section titled “Overview”](#overview) This document provides comprehensive API documentation for all RCL language packages. The RCL (Rich Communication Language) toolchain consists of several interconnected packages that work together to provide a complete language implementation. ## Package Architecture [Section titled “Package Architecture”](#package-architecture) ```plaintext ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ @rcs-lang/ │ │ @rcs-lang/ │ │ @rcs-lang/ │ │ ast │───▶│ parser │───▶│ compiler │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ @rcs-lang/ │ │ @rcs-lang/ │ │ @rcs-lang/ │ │ language-service│ │ cli │ │ csm │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ## Core Packages [Section titled “Core Packages”](#core-packages) ### 1. @rcs-lang/ast [Section titled “1. @rcs-lang/ast”](#1-rcs-langast) **Purpose**: Parser-independent AST definitions and utilities\ **Location**: `packages/ast/`\ **Documentation**: [AST Package Documentation](./packages/ast)\ **API Reference**: [AST API Reference](./api/ast/) Provides TypeScript type definitions for the RCL Abstract Syntax Tree, including all node types, position information, and tree manipulation utilities. **Key Exports**: * `ASTNode` - Base interface for all AST nodes * `RCLDocument` - Root document node * `Agent`, `Flow`, `Message` - Core language constructs * `Position`, `Range` - Source location types * Type guards and utilities ### 2. @rcs-lang/types [Section titled “2. @rcs-lang/types”](#2-rcs-langtypes) **Purpose**: RCS Business Messaging type definitions\ **Location**: `packages/types/`\ **Documentation**: [Types Package Documentation](./packages/types)\ **API Reference**: [Types API Reference](./api/types/) Comprehensive TypeScript types for working with RCS Business Messaging APIs, based on Google's official RBM API reference. **Key Exports**: * `AgentMessage` - Complete agent message structure * `RcsBusinessMessagingAgent` - Agent configuration * `RichCard` - Rich card messages (standalone or carousel) * `Suggestion` - Reply suggestions and actions * Branded types for type safety (PhoneNumber, EmailAddress, etc.) ### 3. @rcs-lang/compiler [Section titled “3. @rcs-lang/compiler”](#3-rcs-langcompiler) **Purpose**: Modular compilation pipeline\ **Location**: `packages/compiler/`\ **Documentation**: [Compiler Package Documentation](./packages/compiler) Multi-stage compilation pipeline that transforms RCL source code into various output formats (JavaScript, D2 diagrams, Mermaid, etc.). **Key Features**: * Parse → Validate → Transform → Generate pipeline * Multiple output generators * Extensible architecture * Error handling and diagnostics ### 4. @rcs-lang/csm [Section titled “4. @rcs-lang/csm”](#4-rcs-langcsm) **Purpose**: Conversation State Machine runtime\ **Location**: `packages/csm/`\ **Documentation**: [CSM Package Documentation](./packages/csm) Runtime library for executing compiled RCL agents as conversation state machines. Handles message routing, context management, and flow execution. **Key Features**: * State machine execution * Message pattern matching * Context variable management * Event handling system ### 5. @rcs-lang/language-service [Section titled “5. @rcs-lang/language-service”](#5-rcs-langlanguage-service) **Purpose**: IDE language features\ **Location**: `packages/language-service/`\ **Documentation**: [Language Service Package Documentation](./packages/language-service) Advanced language service providers for IDE integration, including completion, hover, diagnostics, and more. **Key Features**: * Completion provider * Hover information * Go-to-definition * Reference finding * Semantic validation ## Application Packages [Section titled “Application Packages”](#application-packages) ### 6. @rcs-lang/cli [Section titled “6. @rcs-lang/cli”](#6-rcs-langcli) **Purpose**: Command-line compiler\ **Location**: `packages/cli/`\ **Documentation**: [CLI Package README](../../../packages/cli/README.md) Command-line interface for compiling RCL files and managing RCL projects. **Usage**: ```bash npx @rcs-lang/cli compile input.rcl npx @rcs-lang/cli validate input.rcl npx @rcs-lang/cli generate --format js input.rcl ``` ### 7. VSCode Extension [Section titled “7. VSCode Extension”](#7-vscode-extension) **Purpose**: Full language support for VSCode\ **Location**: `apps/extension/`\ **Documentation**: [Extension README](../../../apps/extension/README.md) VSCode extension providing syntax highlighting, completion, diagnostics, and interactive diagram features for RCL files. ## Common Usage Patterns [Section titled “Common Usage Patterns”](#common-usage-patterns) ### Basic Compilation [Section titled “Basic Compilation”](#basic-compilation) ```typescript import { Compiler } from '@rcs-lang/compiler'; import { AntlrRclParser } from '@rcs-lang/parser'; const compiler = new Compiler({ parser: new AntlrRclParser(), outputFormat: 'javascript' }); const result = await compiler.compile(sourceCode); if (result.success) { console.log(result.output); } else { console.error(result.errors); } ``` ### AST Manipulation [Section titled “AST Manipulation”](#ast-manipulation) ```typescript import { RCLDocument, Agent } from '@rcs-lang/ast'; import { isAgent, isFlow } from '@rcs-lang/ast/guards'; function findAgents(document: RCLDocument): Agent[] { return document.children?.filter(isAgent) || []; } ``` ### State Machine Execution [Section titled “State Machine Execution”](#state-machine-execution) ```typescript import { ConversationalAgent } from '@rcs-lang/csm'; const agent = new ConversationalAgent(compiledOutput); const response = await agent.processMessage({ type: 'text', content: 'Hello' }); ``` ### Language Service Integration [Section titled “Language Service Integration”](#language-service-integration) ```typescript import { CompletionProvider } from '@rcs-lang/language-service'; const provider = new CompletionProvider({ parser: new AntlrRclParser() }); const completions = await provider.provideCompletions( document, position ); ``` ## Type Definitions [Section titled “Type Definitions”](#type-definitions) ### Core AST Types [Section titled “Core AST Types”](#core-ast-types) ```typescript // Base node interface interface ASTNode { type: string; range: Range; parent?: ASTNode; children?: ASTNode[]; } // Document root interface RCLDocument extends ASTNode { type: 'document'; imports: ImportStatement[]; agent: Agent; } // Agent definition interface Agent extends ASTNode { type: 'agent'; name: Identifier; sections: AgentSection[]; } ``` ### Compilation Pipeline [Section titled “Compilation Pipeline”](#compilation-pipeline) ```typescript interface CompilerOptions { parser: Parser; outputFormat: 'javascript' | 'd2' | 'mermaid' | 'json'; validate?: boolean; includeSourceMap?: boolean; } interface CompilationResult { success: boolean; output?: string; errors?: CompilerError[]; warnings?: CompilerWarning[]; sourceMap?: SourceMap; } ``` ### State Machine Types [Section titled “State Machine Types”](#state-machine-types) ```typescript interface MachineDefinition { id: string; initial: string; states: Record; context?: Record; } interface StateDefinition { on?: Record; entry?: Action[]; exit?: Action[]; } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) All packages follow consistent error handling patterns: ```typescript // Compilation errors interface CompilerError { code: string; message: string; severity: 'error' | 'warning' | 'info'; range: Range; source: string; } // Runtime errors class CSMError extends Error { code: string; context?: Record; } ``` ## Versioning and Compatibility [Section titled “Versioning and Compatibility”](#versioning-and-compatibility) * All packages follow [Semantic Versioning](https://semver.org/) * Major version alignment across core packages * Backwards compatibility maintained within major versions * Migration guides provided for breaking changes ## Contributing [Section titled “Contributing”](#contributing) See the project repository for guidelines on contributing to the RCL language toolchain. ## License [Section titled “License”](#license) All packages are licensed under MIT License. See individual package directories for specific license files. # Conversational Agent FSM Requirements > Requirements analysis for FSM implementation # Conversational Agent FSM Requirements Analysis [Section titled “Conversational Agent FSM Requirements Analysis”](#conversational-agent-fsm-requirements-analysis) ## Overview [Section titled “Overview”](#overview) This document analyzes the requirements for a Finite State Machine (FSM) implementation to power the backend of RCS conversational agents, and evaluates whether XState is the appropriate solution or if a simpler alternative would be more suitable. ## Core Requirements [Section titled “Core Requirements”](#core-requirements) ### 1. State Persistence and Restoration [Section titled “1. State Persistence and Restoration”](#1-state-persistence-and-restoration) * **Requirement**: Ability to save and restore machine state between requests * **Use Case**: HTTP-based conversations where each request is stateless * **Details**: * Serialize current state, context variables, and history * Deserialize and resume from any point in the conversation ### 2. URL-Safe State Representation [Section titled “2. URL-Safe State Representation”](#2-url-safe-state-representation) * **Requirement**: Generate a hash representation of state that can be appended to URLs * **Use Case**: Server-side state restoration from URL parameters * **Details**: * Compact, URL-safe encoding of state + context * Deterministic hash generation * Ability to decode and reconstruct full state ### 3. User Response Processing [Section titled “3. User Response Processing”](#3-user-response-processing) * **Requirement**: Process user responses to determine next state * **Use Case**: Handle text messages, button clicks, and other user inputs * **Details**: * Pattern matching on user input * Default/fallback handling * Context-aware transitions ### 4. State Entry Actions [Section titled “4. State Entry Actions”](#4-state-entry-actions) * **Requirement**: Execute actions upon entering a state * **Use Case**: Send messages, log events, call APIs * **Details**: * Side effects on state entry * Access to context variables * Async action support ### 5. Transient States [Section titled “5. Transient States”](#5-transient-states) * **Requirement**: States that automatically transition when their action completes * **Use Case**: Processing states, validation states, intermediate logic * **Details**: * Parameterized target states (e.g., InvalidOption → @next) * No user interaction required * Immediate transition after action ## Additional Requirements (Discovered) [Section titled “Additional Requirements (Discovered)”](#additional-requirements-discovered) ### 6. Context Management [Section titled “6. Context Management”](#6-context-management) * **Requirement**: Accumulate and access conversation context * **Use Case**: Collect user choices throughout conversation * **Details**: * Hierarchical context (state-specific + global) * Variable interpolation in messages * Context persistence across state transitions ### 7. Message Templating [Section titled “7. Message Templating”](#7-message-templating) * **Requirement**: Dynamic message generation with context variables * **Use Case**: Personalized responses using collected data * **Details**: * String interpolation: `#{context.size}`, `#{@price}` * JavaScript expressions: `${(context.price + extraCharge).toFixed(2)}` * Conditional content based on context ### 8. Multi-Machine Architecture [Section titled “8. Multi-Machine Architecture”](#8-multi-machine-architecture) * **Requirement**: Each flow generates a separate FSM, multiple machines per agent * **Use Case**: Modular conversation flows, separation of concerns * **Details**: * One machine per flow definition * Agent coordinates multiple machines * Clean flow boundaries ### 9. Flow Composition and Reusability [Section titled “9. Flow Composition and Reusability”](#9-flow-composition-and-reusability) * **Requirement**: Connect machines and compose agents from reusable flows * **Use Case**: "Contact Support" flow reused across different agents/verticals * **Details**: * Import and compose existing flows * Machine-to-machine transitions * Share context between machines * Library of reusable flows ### 10. Agent-Level State Management [Section titled “10. Agent-Level State Management”](#10-agent-level-state-management) * **Requirement**: Hash representation must encode agent state (current machine + state) * **Use Case**: Restore conversation spanning multiple flows * **Details**: * Track which machine is active * Preserve context across machine transitions * URL hash format: `agentId:machineId:stateId:contextHash` ### 11. Event Logging and Analytics [Section titled “11. Event Logging and Analytics”](#11-event-logging-and-analytics) * **Requirement**: Track state transitions and user interactions * **Use Case**: Analytics, debugging, conversation optimization * **Details**: * Transition history * Timing information * User input logging ### 12. Error Recovery [Section titled “12. Error Recovery”](#12-error-recovery) * **Requirement**: Graceful handling of invalid states or errors * **Use Case**: Network failures, corrupted state, invalid input * **Details**: * Fallback to known good state * Error state handling * Recovery mechanisms ## Solution Evaluation [Section titled “Solution Evaluation”](#solution-evaluation) ### Option 1: XState (Current Approach) [Section titled “Option 1: XState (Current Approach)”](#option-1-xstate-current-approach) **Pros:** * Industry-standard state machine implementation * Built-in state persistence (state.toJSON()) * Hierarchical states support * Robust action/service system * TypeScript support * Visualization tools * Active community and ecosystem **Cons:** * Large bundle size (\~50KB min+gzip per machine) * Complex API for simple use cases * Overhead for features we don't use (actors, parallel states, history states) * Difficult to implement simple machine-to-machine transitions * XState's composition model (invoke, spawn) is complex for our needs * Learning curve for team members * Overkill when each flow is a simple linear FSM **Verdict**: Even more overkill with multi-machine architecture ### Option 2: Custom Lightweight FSM [Section titled “Option 2: Custom Lightweight FSM”](#option-2-custom-lightweight-fsm) **Pros:** * Tailored exactly to our needs * Minimal bundle size (<5KB) * Simple, clear API * Easy to understand and maintain * Direct control over serialization format * Optimized for conversational flows **Cons:** * Need to implement core features ourselves * Less battle-tested * No ecosystem/tooling * Potential for bugs in edge cases **Example Implementation:** ```typescript // Individual Flow Machine interface FlowMachine { id: string; states: Map; currentState: string; context: Record; transition(input: string): TransitionResult; serialize(): MachineState; } // Agent orchestrating multiple machines interface Agent { machines: Map; activeMachine: string; globalContext: Record; processInput(input: string): Promise; switchMachine(machineId: string, initialState?: string): void; toURLHash(): string; static fromURLHash(hash: string): Agent; } // Simple machine-to-machine transition // In flow A: -> ContactSupport // Switches to ContactSupport machine with shared context ``` ### Option 3: Lighter State Machine Libraries [Section titled “Option 3: Lighter State Machine Libraries”](#option-3-lighter-state-machine-libraries) **robot3** (\~2KB) * Pros: Tiny, functional API, TypeScript support * Cons: Less features, smaller community **nanostate** (\~3KB) * Pros: Simple API, event emitter based * Cons: No TypeScript, less maintained **javascript-state-machine** (\~7KB) * Pros: Simple, well-documented * Cons: Class-based API, less modern ## Recommendation [Section titled “Recommendation”](#recommendation) **Implement a custom lightweight FSM tailored for conversational agents.** ### Rationale: [Section titled “Rationale:”](#rationale) 1. **Specific Use Case**: Conversational flows have specific patterns (linear progression, context accumulation, message-driven) that don't require XState's advanced features 2. **Performance**: A custom solution will be 10x smaller and faster, important for server-side execution 3. **Simplicity**: Our requirements are well-defined and limited - a 200-300 line implementation can cover everything 4. **Control**: Direct control over serialization format, URL encoding, and state structure 5. **Learning Curve**: Team can understand and modify a simple FSM vs learning XState's complex mental model ### Proposed Architecture: [Section titled “Proposed Architecture:”](#proposed-architecture) ```typescript // Individual Flow Machine (lightweight, ~50 lines) export class FlowMachine { constructor( public id: string, private definition: FlowDefinition ) {} transition(input: string, context: Context): TransitionResult { // Simple pattern matching, return next state or machine } } // Agent coordinating multiple machines export class ConversationalAgent { private machines = new Map(); private activeMachineId: string; private activeStateId: string; private context: Context; // Add a flow (can be imported from a library) addFlow(flow: FlowDefinition): void { this.machines.set(flow.id, new FlowMachine(flow.id, flow)); } // Process user input async processInput(input: string): Promise { const machine = this.machines.get(this.activeMachineId); const result = machine.transition(input, this.context); if (result.type === 'state') { this.activeStateId = result.stateId; return this.executeState(result.stateId); } else if (result.type === 'machine') { // Transition to different flow this.activeMachineId = result.machineId; this.activeStateId = result.stateId || 'start'; return this.executeState(this.activeStateId); } } // URL-safe serialization toURLHash(): string { // Format: base64url(agent:machine:state:context) const state = { a: this.id, m: this.activeMachineId, s: this.activeStateId, c: this.context }; return base64url.encode(JSON.stringify(state)); } } // Usage - Composing an agent from reusable flows import { ContactSupportFlow } from '@rcs-lang/common-flows'; import { FAQFlow } from '@rcs-lang/common-flows'; const agent = new ConversationalAgent('RetailBot'); agent.addFlow(WelcomeFlow); // Custom flow agent.addFlow(ContactSupportFlow); // Reusable agent.addFlow(FAQFlow); // Reusable // In WelcomeFlow definition: // on ShowMenu // match @reply.text // "Contact Support" -> machine ContactSupport // "FAQ" -> machine FAQ ``` ### Migration Path: [Section titled “Migration Path:”](#migration-path) 1. Build the lightweight FSM alongside XState output 2. Add a compiler flag to choose output format 3. Gradually migrate services to use lightweight FSM 4. Remove XState dependency once stable ## Conclusion [Section titled “Conclusion”](#conclusion) The multi-machine architecture fundamentally changes our requirements. Instead of one complex state machine per agent, we need: 1. **Multiple simple FSMs** - One per flow, each focused on a specific conversation path 2. **Agent-level orchestration** - Coordinate between machines, manage shared context 3. **Flow composition** - Import and reuse flows across agents and verticals This architecture strongly favors a custom lightweight solution because: * **XState's complexity is wasted** on simple, linear conversation flows * **Machine composition** is simpler with explicit machine switching vs XState's actor model * **Flow reusability** is cleaner with standalone machines vs hierarchical states * **Bundle size matters more** when potentially loading many flow definitions A custom solution of \~300 lines can handle the agent orchestration, while each flow machine can be just \~50 lines of simple pattern matching. This is far more maintainable than wrestling XState into this specific use case. ### Example RCL for machine composition: [Section titled “Example RCL for machine composition:”](#example-rcl-for-machine-composition) ```rcl agent CustomerService start: MainMenu # Import reusable flows import ContactSupportFlow from "@rcs-lang/common-flows/contact-support" import FAQFlow from "@rcs-lang/common-flows/faq" import StoreLocatorFlow from "./store-locator" flow MainMenu on Welcome match @reply.text "Contact Support" -> machine ContactSupportFlow "FAQ" -> machine FAQFlow "Find Store" -> machine StoreLocatorFlow ``` This approach enables a marketplace of reusable conversation flows while keeping each flow simple and testable. # Examples > Comprehensive examples demonstrating RCL features # RCL Language Examples [Section titled “RCL Language Examples”](#rcl-language-examples) This document provides comprehensive examples demonstrating various features of the RCL (Rich Communication Language) and how to use the language toolchain. ## Table of Contents [Section titled “Table of Contents”](#table-of-contents) 1. [Basic Agent Structure](#basic-agent-structure) 2. [Message Types](#message-types) 3. [Flow Control](#flow-control) 4. [Context Variables](#context-variables) 5. [Advanced Features](#advanced-features) 6. [API Usage Examples](#api-usage-examples) 7. [Integration Examples](#integration-examples) ## Basic Agent Structure [Section titled “Basic Agent Structure”](#basic-agent-structure) ### Minimal Agent [Section titled “Minimal Agent”](#minimal-agent) ```rcl agent GreetingBot displayName "Simple Greeting Bot" flow greeting start -> welcome welcome: "Hello! How can I help you today?" * -> end messages Messages # Messages will be auto-generated ``` ### Complete Agent Structure [Section titled “Complete Agent Structure”](#complete-agent-structure) ```rcl agent CoffeeShopBot displayName "Coffee Shop Assistant" description "Helps customers order coffee and learn about our menu" version "1.0.0" flow ordering start -> welcome welcome: "Welcome to our coffee shop! What can I get you today?" "menu" -> show_menu "order *" -> take_order * -> help show_menu: text "Here's our menu:" richCard "Coffee Menu" medium title "Our Coffee Selection" description "Fresh roasted daily" media Coffee menu suggestions ["Espresso", "Latte", "Cappuccino"] * -> take_order take_order: "Great choice! What size would you like?" context.drink = match[1] "small" -> confirm_order(size="small") "medium" -> confirm_order(size="medium") "large" -> confirm_order(size="large") * -> ask_size_again confirm_order: text "Perfect! One {context.size} {context.drink}." text "That'll be ${prices[context.size]}. Please proceed to payment." * -> end ask_size_again: "I didn't catch that. What size: small, medium, or large?" "small" -> confirm_order(size="small") "medium" -> confirm_order(size="medium") "large" -> confirm_order(size="large") * -> ask_size_again help: "I can help you with our menu or take your order. Just say 'menu' or 'order [drink name]'." * -> welcome messages Messages welcome: "Welcome to our coffee shop! What can I get you today?" show_menu: "Here's our menu:" take_order: "Great choice! What size would you like?" confirm_order: "Perfect! One {context.size} {context.drink}." ``` ## Message Types [Section titled “Message Types”](#message-types) ### Text Messages [Section titled “Text Messages”](#text-messages) ```rcl agent TextExamples displayName "Text Message Examples" flow examples start -> simple_text simple_text: "This is a simple text message" * -> formatted_text formatted_text: text "This is a text block with formatting" text "You can have multiple text elements" * -> end ``` ### Rich Cards [Section titled “Rich Cards”](#rich-cards) ```rcl agent RichCardExamples displayName "Rich Card Examples" flow examples start -> basic_card basic_card: richCard "Product Card" medium title "Coffee Beans" description "Premium Arabica beans" media Coffee beans suggestions ["Buy Now", "Learn More"] * -> advanced_card advanced_card: richCard "Complex Card" large title "Special Offer" description "Limited time discount on all drinks" media Special offer actions action "claim_discount" "Claim 20% Off" action "view_menu" "View Menu" * -> end ``` ### Carousel Messages [Section titled “Carousel Messages”](#carousel-messages) ```rcl agent CarouselExamples displayName "Carousel Examples" flow examples start -> product_carousel product_carousel: carousel "Our Products" richCard "Espresso" small title "Espresso" description "Strong and bold" media richCard "Latte" small title "Latte" description "Smooth and creamy" media richCard "Cappuccino" small title "Cappuccino" description "Frothy perfection" media * -> end ``` ### Suggestions and Quick Replies [Section titled “Suggestions and Quick Replies”](#suggestions-and-quick-replies) ```rcl agent SuggestionExamples displayName "Suggestion Examples" flow examples start -> with_suggestions with_suggestions: "What would you like to know about?" suggestions ["Menu", "Hours", "Location", "Contact"] "menu" -> show_menu "hours" -> show_hours "location" -> show_location "contact" -> show_contact * -> help ``` ## Flow Control [Section titled “Flow Control”](#flow-control) ### Linear Flow [Section titled “Linear Flow”](#linear-flow) ```rcl agent LinearFlow displayName "Linear Flow Example" flow onboarding start -> step1 step1: "Welcome! Let's get you set up. What's your name?" * -> step2 step2: "Nice to meet you, {match}! What's your email?" context.name = match * -> step3 step3: "Thanks! We'll send updates to {match}. You're all set!" context.email = match * -> end ``` ### Branching Flow [Section titled “Branching Flow”](#branching-flow) ```rcl agent BranchingFlow displayName "Branching Flow Example" flow support start -> identify_issue identify_issue: "How can I help you today?" "technical*" -> technical_support "billing*" -> billing_support "general*" -> general_support * -> clarify_issue technical_support: "I'll connect you with our technical team." * -> end billing_support: "Let me help with your billing question." * -> end general_support: "I'm here to help with general questions." * -> end clarify_issue: "Could you be more specific about your issue?" * -> identify_issue ``` ### Loops and Repetition [Section titled “Loops and Repetition”](#loops-and-repetition) ```rcl agent LoopingFlow displayName "Looping Flow Example" flow quiz start -> ask_question ask_question: "What's 2 + 2?" "4" -> correct "four" -> correct * -> incorrect correct: "Correct! Want another question?" "yes" -> ask_question "no" -> end * -> ask_question incorrect: "Not quite right. The answer is 4. Try another?" "yes" -> ask_question "no" -> end * -> ask_question ``` ## Context Variables [Section titled “Context Variables”](#context-variables) ### Setting and Using Context [Section titled “Setting and Using Context”](#setting-and-using-context) ```rcl agent ContextExample displayName "Context Variables Example" flow ordering start -> get_name get_name: "What's your name?" * -> get_drink get_drink: "Hi {match}! What drink would you like?" context.customer_name = match * -> get_size get_size: "What size {match}?" context.drink = match "small" -> confirm(size="small") "medium" -> confirm(size="medium") "large" -> confirm(size="large") * -> get_size confirm: "Perfect! One {context.size} {context.drink} for {context.customer_name}." * -> end ``` ### Complex Context Operations [Section titled “Complex Context Operations”](#complex-context-operations) ```rcl agent ComplexContext displayName "Complex Context Example" flow shopping start -> browse browse: "What would you like to browse?" context.cart = [] context.total = 0 "coffee" -> show_coffee "pastries" -> show_pastries "checkout" -> checkout * -> browse show_coffee: "Here's our coffee selection:" richCard "Add to Cart" medium title "Espresso - $3.50" actions action "add_espresso" "Add to Cart" "add espresso" -> add_item(item="espresso", price=3.50) "back" -> browse * -> show_coffee add_item: context.cart = context.cart + [context.item] context.total = context.total + context.price text "Added {context.item} to cart. Total: ${context.total}" * -> browse checkout: "Your total is ${context.total}. Proceed to payment?" "yes" -> payment "no" -> browse * -> checkout ``` ## Advanced Features [Section titled “Advanced Features”](#advanced-features) ### External Data Integration [Section titled “External Data Integration”](#external-data-integration) ```rcl agent WeatherBot displayName "Weather Bot" flow weather start -> get_location get_location: "What city would you like weather for?" * -> show_weather show_weather: context.city = match richCard "Weather Info" large title "Weather in {context.city}" description media * -> end ``` ### Multi-language Support [Section titled “Multi-language Support”](#multi-language-support) ```rcl agent MultiLangBot displayName "Multi-language Bot" flow greeting start -> detect_language detect_language: "Hello / Hola / Bonjour" "english" -> english_flow "español" -> spanish_flow "français" -> french_flow * -> detect_language english_flow: "Welcome! How can I help you?" * -> end spanish_flow: "¡Bienvenido! ¿Cómo puedo ayudarte?" * -> end french_flow: "Bienvenue! Comment puis-je vous aider?" * -> end ``` ## API Usage Examples [Section titled “API Usage Examples”](#api-usage-examples) ### Compilation Pipeline [Section titled “Compilation Pipeline”](#compilation-pipeline) ```typescript import { Compiler } from '@rcs-lang/compiler'; import { AntlrRclParser } from '@rcs-lang/parser'; // Basic compilation const compiler = new Compiler({ parser: new AntlrRclParser() }); const rclSource = ` agent SimpleBot displayName "Simple Bot" flow greeting start -> hello hello: "Hello!" * -> end messages Messages `; const result = await compiler.compile(rclSource); if (result.success) { console.log('JavaScript output:', result.javascript); console.log('D2 diagram:', result.d2); } else { console.error('Compilation errors:', result.errors); } ``` ### State Machine Execution [Section titled “State Machine Execution”](#state-machine-execution) ```typescript import { ConversationalAgent } from '@rcs-lang/csm'; // Load compiled agent const agentDefinition = require('./compiled-agent.js'); const agent = new ConversationalAgent(agentDefinition); // Process messages async function chatWithAgent() { let response = await agent.processMessage({ type: 'text', content: 'hello' }); console.log('Bot:', response.message); response = await agent.processMessage({ type: 'text', content: 'menu' }); console.log('Bot:', response.message); } chatWithAgent(); ``` ### Language Service Integration [Section titled “Language Service Integration”](#language-service-integration) ```typescript import { CompletionProvider, HoverProvider, DiagnosticsProvider } from '@rcs-lang/language-service'; // Setup language service const completionProvider = new CompletionProvider(); const hoverProvider = new HoverProvider(); const diagnosticsProvider = new DiagnosticsProvider(); // Get completions at cursor position const completions = await completionProvider.provideCompletions( document, { line: 5, character: 10 } ); // Get hover information const hover = await hoverProvider.provideHover( document, { line: 8, character: 15 } ); // Get diagnostics const diagnostics = await diagnosticsProvider.provideDiagnostics(document); ``` ## Integration Examples [Section titled “Integration Examples”](#integration-examples) ### Express.js Web Server [Section titled “Express.js Web Server”](#expressjs-web-server) ```javascript const express = require('express'); const { ConversationalAgent } = require('@rcs-lang/csm'); const app = express(); app.use(express.json()); // Load compiled agent const agentDefinition = require('./coffee-shop-bot.js'); const bot = new ConversationalAgent(agentDefinition); // Chat endpoint app.post('/chat', async (req, res) => { try { const { message, sessionId } = req.body; const response = await bot.processMessage({ type: 'text', content: message, sessionId }); res.json({ success: true, message: response.message, suggestions: response.suggestions }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); app.listen(3000, () => { console.log('Chat server running on port 3000'); }); ``` ### React Component [Section titled “React Component”](#react-component) ```jsx import React, { useState } from 'react'; import { ConversationalAgent } from '@rcs-lang/csm'; const ChatComponent = ({ agentDefinition }) => { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [agent] = useState(() => new ConversationalAgent(agentDefinition)); const sendMessage = async () => { if (!input.trim()) return; // Add user message const userMessage = { sender: 'user', content: input }; setMessages(prev => [...prev, userMessage]); try { // Get bot response const response = await agent.processMessage({ type: 'text', content: input }); // Add bot message const botMessage = { sender: 'bot', content: response.message, suggestions: response.suggestions }; setMessages(prev => [...prev, botMessage]); } catch (error) { console.error('Chat error:', error); } setInput(''); }; return (
{messages.map((msg, index) => (
{msg.content} {msg.suggestions && (
{msg.suggestions.map((suggestion, i) => ( ))}
)}
))}
setInput(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && sendMessage()} placeholder="Type a message..." />
); }; export default ChatComponent; ``` These examples demonstrate the flexibility and power of the RCL language and its toolchain for building sophisticated conversational agents and integrating them into various applications. # Getting Started > Quick start guide for RCL # Getting Started with RCL [Section titled “Getting Started with RCL”](#getting-started-with-rcl) Welcome to RCL (Rich Communication Language)! This guide will help you get started with creating conversational agents using RCL and its toolchain. ## What is RCL? [Section titled “What is RCL?”](#what-is-rcl) RCL is a domain-specific language designed for creating Rich Communication Services (RCS) agents. It provides a declarative syntax for defining conversational flows, message types, and agent behaviors. ## Quick Start [Section titled “Quick Start”](#quick-start) ### 1. Installation [Section titled “1. Installation”](#1-installation) #### Using npm [Section titled “Using npm”](#using-npm) ```bash # Install the CLI globally npm install -g @rcs-lang/cli # Or use npx (recommended) npx @rcs-lang/cli --version ``` #### Using the Web IDE [Section titled “Using the Web IDE”](#using-the-web-ide) Visit [RCS Agent Studio](https://rcs-lang.github.io/ide) for a browser-based development experience with no installation required. ### 2. Your First Agent [Section titled “2. Your First Agent”](#2-your-first-agent) Create a file called `hello-bot.rcl`: ```rcl agent HelloBot displayName "Hello Bot" description "A simple greeting bot" flow greeting start -> welcome welcome: "Hello! I'm your friendly bot. How can I help you today?" "help" -> show_help "bye" -> goodbye * -> confused show_help: "I can greet you and say goodbye. Try saying 'bye' when you're ready to leave." * -> welcome goodbye: "Goodbye! Have a great day!" * -> end confused: "I didn't quite understand that. Try saying 'help' for assistance." * -> welcome messages Messages # Messages will be automatically generated from the flow ``` ### 3. Compile Your Agent [Section titled “3. Compile Your Agent”](#3-compile-your-agent) ```bash # Compile to JavaScript (for runtime execution) npx @rcs-lang/cli compile hello-bot.rcl # Compile to specific format npx @rcs-lang/cli compile hello-bot.rcl --format javascript npx @rcs-lang/cli compile hello-bot.rcl --format json # Generate a flow diagram npx @rcs-lang/cli compile hello-bot.rcl --format d2 ``` ### 4. Test Your Agent [Section titled “4. Test Your Agent”](#4-test-your-agent) ```bash # Validate syntax and semantics npx @rcs-lang/cli validate hello-bot.rcl # Interactive testing (if available) npx @rcs-lang/cli test hello-bot.rcl ``` ## Core Concepts [Section titled “Core Concepts”](#core-concepts) ### Agents [Section titled “Agents”](#agents) An agent is the top-level container for your conversational bot: ```rcl agent MyBot displayName "My Conversational Bot" description "Description of what the bot does" version "1.0.0" # Agent configuration goes here ``` ### Flows [Section titled “Flows”](#flows) Flows define the conversation logic using states and transitions: ```rcl flow conversation start -> greeting greeting: "Hello!" "hi" -> friendly_response "help" -> show_help * -> default_response ``` ### Messages [Section titled “Messages”](#messages) Messages define what the bot says and how it's presented: ```rcl # Simple text message state: "Hello there!" # Rich message with suggestions state: "What would you like to do?" suggestions ["Option A", "Option B", "Help"] # Rich card message state: richCard "Welcome" medium title "Welcome to our service" description "How can we help you today?" media Welcome ``` ### Context Variables [Section titled “Context Variables”](#context-variables) Store and use information throughout the conversation: ```rcl flow ordering start -> get_name get_name: "What's your name?" * -> get_order get_order: "Hi {match}! What would you like to order?" context.customer_name = match * -> confirm_order confirm_order: "Got it, {context.customer_name}! Your order is confirmed." * -> end ``` ### Pattern Matching [Section titled “Pattern Matching”](#pattern-matching) RCL supports flexible pattern matching for user input: ```rcl state: "How can I help you?" "order *" -> take_order # Matches "order coffee", "order pizza", etc. "help" -> show_help # Exact match "cancel*" -> cancel_flow # Matches anything starting with "cancel" /\d+/ -> handle_number # Regular expression for numbers * -> default_handler # Catch-all pattern ``` ## Development Workflow [Section titled “Development Workflow”](#development-workflow) ### 1. Write RCL Code [Section titled “1. Write RCL Code”](#1-write-rcl-code) Start with a simple agent structure and gradually add complexity: ```rcl agent SimpleBot displayName "Simple Bot" flow main start -> hello hello: "Hello!" * -> end messages Messages ``` ### 2. Validate and Compile [Section titled “2. Validate and Compile”](#2-validate-and-compile) Always validate your code before deployment: ```bash # Check for syntax and semantic errors npx @rcs-lang/cli validate my-bot.rcl # Compile to your target format npx @rcs-lang/cli compile my-bot.rcl --format javascript ``` ### 3. Test Locally [Section titled “3. Test Locally”](#3-test-locally) Test your agent logic before deployment: test-agent.js ```javascript const { ConversationalAgent } = require('@rcs-lang/csm'); const agentDefinition = require('./my-bot.js'); const agent = new ConversationalAgent(agentDefinition); async function test() { const response = await agent.processMessage({ type: 'text', content: 'hello' }); console.log('Bot response:', response.message); } test(); ``` ### 4. Deploy [Section titled “4. Deploy”](#4-deploy) Deploy your compiled agent to your preferred platform: * Web applications (Express.js, React, etc.) * Cloud functions (AWS Lambda, Google Cloud Functions) * Mobile applications (React Native, Flutter) * Chat platforms (Slack, Discord, Teams) ## Best Practices [Section titled “Best Practices”](#best-practices) ### 1. Start Simple [Section titled “1. Start Simple”](#1-start-simple) Begin with basic flows and add complexity gradually: ```rcl # Good: Simple, focused flow flow greeting start -> welcome welcome: "Hello! How can I help?" "help" -> show_help * -> end # Avoid: Complex nested flows initially ``` ### 2. Use Clear State Names [Section titled “2. Use Clear State Names”](#2-use-clear-state-names) Choose descriptive names for your states: ```rcl # Good: Descriptive names flow ordering start -> welcome_customer welcome_customer -> take_drink_order take_drink_order -> confirm_order # Avoid: Generic names flow ordering start -> state1 state1 -> state2 state2 -> state3 ``` ### 3. Handle Edge Cases [Section titled “3. Handle Edge Cases”](#3-handle-edge-cases) Always provide fallback responses: ```rcl state: "What size drink?" "small" -> confirm_small "medium" -> confirm_medium "large" -> confirm_large * -> ask_size_again # Handle unexpected input ask_size_again: "I didn't catch that. Please choose small, medium, or large." * -> state # Try again ``` ### 4. Use Context Wisely [Section titled “4. Use Context Wisely”](#4-use-context-wisely) Store important information but don't over-complicate: ```rcl # Good: Store essential information get_name: "What's your name?" * -> get_email context.customer_name = match # Good: Use stored context confirm: "Thanks {context.customer_name}! Your order is confirmed." # Avoid: Storing too much unnecessary data ``` ### 5. Organize Complex Agents [Section titled “5. Organize Complex Agents”](#5-organize-complex-agents) For larger agents, consider breaking flows into logical sections: ```rcl agent CustomerService displayName "Customer Service Bot" # Main entry flow flow main start -> identify_need identify_need: "How can I help you today?" "technical*" -> technical_support.start "billing*" -> billing_support.start "general*" -> general_support.start # Specialized flows flow technical_support # Technical support logic flow billing_support # Billing support logic flow general_support # General support logic ``` ## Common Patterns [Section titled “Common Patterns”](#common-patterns) ### FAQ Bot [Section titled “FAQ Bot”](#faq-bot) ```rcl agent FAQBot displayName "FAQ Bot" flow faq start -> main_menu main_menu: "What would you like to know about?" suggestions ["Hours", "Location", "Contact", "Services"] "hours" -> show_hours "location" -> show_location "contact" -> show_contact "services" -> show_services * -> main_menu show_hours: "We're open Monday-Friday 9AM-5PM, Saturday 10AM-3PM." * -> main_menu show_location: "We're located at 123 Main Street, Downtown." * -> main_menu ``` ### Order Taking Bot [Section titled “Order Taking Bot”](#order-taking-bot) ```rcl agent OrderBot displayName "Order Taking Bot" flow ordering start -> welcome welcome: "Welcome! What would you like to order?" * -> process_order process_order: "Great choice! What size?" context.item = match "small" -> confirm_order(size="small") "medium" -> confirm_order(size="medium") "large" -> confirm_order(size="large") * -> ask_size_again confirm_order: "Perfect! One {context.size} {context.item}. Anything else?" "no" -> finalize_order "yes" -> welcome * -> finalize_order ``` ## Next Steps [Section titled “Next Steps”](#next-steps) 1. **Explore Examples**: Check out [examples/](../../../examples/) for more complex agent implementations 2. **Read the API Documentation**: Learn about the full [API](./api) 3. **Join the Community**: Get help and share your agents 4. **Contribute**: Help improve RCL by contributing to the project ## Getting Help [Section titled “Getting Help”](#getting-help) * **Documentation**: Browse the [main documentation](./index) * **Examples**: See [examples/](../../../examples/) for real-world use cases * **Issues**: Report bugs or request features on GitHub * **Community**: Join our Discord server for discussions Happy bot building! 🤖 # Local CI > Running GitHub Actions locally for RCL development # Running GitHub Actions Locally [Section titled “Running GitHub Actions Locally”](#running-github-actions-locally) This project includes scripts to run GitHub Actions workflows locally using [act](https://github.com/nektos/act). ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Install act: ```bash # macOS brew install act # Linux curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash # Windows (via Chocolatey) choco install act-cli ``` ## Available Scripts [Section titled “Available Scripts”](#available-scripts) Run these from the root directory: ```bash # List all available workflows npm run act:list # Run the main CI workflow npm run act:ci # Simulate a push event (runs workflows triggered by push) npm run act:push # Simulate a pull request event npm run act:pr # Run with custom options npm run act -- [options] ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) ### Test CI Before Pushing [Section titled “Test CI Before Pushing”](#test-ci-before-pushing) ```bash npm run act:ci ``` ### Debug a Specific Job [Section titled “Debug a Specific Job”](#debug-a-specific-job) ```bash npm run act -- -j test -W .github/workflows/ci.yml ``` ### Use a Different Runner Image [Section titled “Use a Different Runner Image”](#use-a-different-runner-image) ```bash npm run act -- --platform ubuntu-latest=nektos/act-environments-ubuntu:22.04 ``` ## Notes [Section titled “Notes”](#notes) * Act uses Docker to simulate GitHub Actions runners * Some GitHub-specific features may not work locally (like secrets) * For secrets, create a `.secrets` file in the root (gitignored) * Moon is installed as part of the workflow steps # RCL Packages > Overview of all RCL ecosystem packages # RCL Packages [Section titled “RCL Packages”](#rcl-packages) The RCL ecosystem consists of several modular packages that work together to provide a complete language toolchain. Each package has a specific responsibility and can be used independently or as part of the full suite. ## 🚀 Quick Start Guide [Section titled “🚀 Quick Start Guide”](#-quick-start-guide) **For Users:** Install the CLI globally to start compiling RCL files: ```bash bun add -g @rcs-lang/cli rcl compile my-agent.rcl ``` **For Developers:** Install packages for building RCL tools: ```bash bun add @rcs-lang/parser @rcs-lang/compiler @rcs-lang/core ``` **For IDE Integration:** Use the language service for editor features: ```bash bun add @rcs-lang/language-service ``` *** ## 📦 Package Overview [Section titled “📦 Package Overview”](#-package-overview) ### 🏗️ **Foundation Packages** [Section titled “🏗️ Foundation Packages”](#️-foundation-packages) *Core infrastructure that everything else builds on* | Package | Purpose | When to Use | | -------------------------------------------------- | ------------------------------------------ | ------------------------------------------- | | **[@rcs-lang/core](/packages/core)** | Shared types, interfaces, and abstractions | Building any RCL tool - required foundation | | **[@rcs-lang/ast](/packages/ast)** | Type-safe AST definitions and utilities | Working with parsed RCL syntax trees | | **[@rcs-lang/types](/packages/types)** | RCS Business Messaging type definitions | Working with RBM APIs and message formats | | **[@rcs-lang/file-system](/packages/file-system)** | Cross-platform file operations | Building tools that read/write files | ### ⚙️ **Language Processing** [Section titled “⚙️ Language Processing”](#️-language-processing) *Parsing and compilation pipeline* | Package | Purpose | When to Use | | ------------------------------------------------ | ------------------------------- | -------------------------------------- | | **[@rcs-lang/parser](/packages/parser)** | ANTLR4-based RCL parser | Converting RCL source code to AST | | **[@rcs-lang/compiler](/packages/compiler)** | Modern compilation pipeline | Transforming AST to executable formats | | **[@rcs-lang/validation](/packages/validation)** | Comprehensive validation system | Checking RCL code for errors/warnings | ### 🛠️ **Developer Tools** [Section titled “🛠️ Developer Tools”](#️-developer-tools) *CLI and IDE integration* | Package | Purpose | When to Use | | ------------------------------------------------------------ | -------------------------------------- | --------------------------------- | | **[@rcs-lang/cli](/packages/cli)** | Command-line compiler | Building RCS agents from terminal | | **[@rcs-lang/language-service](/packages/language-service)** | IDE features (completion, hover, etc.) | Building editor extensions | ### 🤖 **Runtime** [Section titled “🤖 Runtime”](#-runtime) *Conversation execution engine* | Package | Purpose | When to Use | | ---------------------------------- | -------------------------------------- | -------------------------------- | | **[@rcs-lang/csm](/packages/csm)** | Lightweight conversation state machine | Running RCS agents in production | *** ## 🎯 **Choose the Right Package** [Section titled “🎯 Choose the Right Package”](#-choose-the-right-package) ### I want to... [Section titled “I want to...”](#i-want-to) **📝 Parse RCL code** ```typescript import { AntlrRclParser } from '@rcs-lang/parser'; // ✅ Use @rcs-lang/parser ``` **🔨 Compile RCL to JSON/JavaScript** ```typescript import { RCLCompiler } from '@rcs-lang/compiler'; // ✅ Use @rcs-lang/compiler ``` **💻 Add RCL support to my editor** ```typescript import { LanguageService } from '@rcs-lang/language-service'; // ✅ Use @rcs-lang/language-service ``` **🚀 Run RCS agents in production** ```typescript import { ConversationalAgent } from '@rcs-lang/csm'; // ✅ Use @rcs-lang/csm ``` **🧪 Build custom tooling** ```typescript import { Result, IFileSystem } from '@rcs-lang/core'; // ✅ Start with @rcs-lang/core ``` *** ## 🏛️ **Architecture Overview** [Section titled “🏛️ Architecture Overview”](#️-architecture-overview) The RCL ecosystem follows a layered architecture: ```mermaid graph TB subgraph "🛠️ Developer Tools" CLI[CLI Tool] LS[Language Service] end subgraph "⚙️ Language Processing" Parser[Parser] Compiler[Compiler] Validation[Validation] end subgraph "🏗️ Foundation" AST[AST Types] Core[Core Interfaces] Types[RBM Types] FileSystem[File System] end subgraph "🤖 Runtime" CSM[Conversation State Machine] end CLI --> Compiler CLI --> Parser CLI --> FileSystem LS --> Parser LS --> Compiler LS --> Validation Compiler --> AST Compiler --> Core Compiler --> Parser Compiler --> Validation Parser --> AST Parser --> Core Validation --> Core Validation --> Parser CSM --> Core FileSystem --> Core ``` ### 🔄 **Typical Data Flow** [Section titled “🔄 Typical Data Flow”](#-typical-data-flow) 1. **Source Code** → **Parser** → **AST** 2. **AST** → **Validation** → **Diagnostics** 3. **AST** → **Compiler** → **JSON/JavaScript** 4. **JSON** → **CSM** → **Running Agent** *** ## 📚 **Learning Path** [Section titled “📚 Learning Path”](#-learning-path) ### 🟢 **Beginner** - Just want to use RCL [Section titled “🟢 Beginner - Just want to use RCL”](#-beginner---just-want-to-use-rcl) 1. Start with **[@rcs-lang/cli](/packages/cli)** - compile your first agent 2. Learn **[@rcs-lang/csm](/packages/csm)** - run your agent ### 🟡 **Intermediate** - Building RCL tools [Section titled “🟡 Intermediate - Building RCL tools”](#-intermediate---building-rcl-tools) 1. Understand **[@rcs-lang/core](/packages/core)** - core concepts 2. Use **[@rcs-lang/parser](/packages/parser)** - parse RCL code 3. Explore **[@rcs-lang/ast](/packages/ast)** - work with syntax trees ### 🔴 **Advanced** - Contributing to RCL [Section titled “🔴 Advanced - Contributing to RCL”](#-advanced---contributing-to-rcl) 1. Master **[@rcs-lang/compiler](/packages/compiler)** - compilation pipeline 2. Study **[@rcs-lang/validation](/packages/validation)** - validation system 3. Dive into **[@rcs-lang/language-service](/packages/language-service)** - IDE features *** ## 🚀 **Installation & Usage** [Section titled “🚀 Installation \& Usage”](#-installation--usage) ### Global CLI Installation [Section titled “Global CLI Installation”](#global-cli-installation) ```bash # Install CLI globally for terminal usage bun add -g @rcs-lang/cli # Verify installation rcl --version ``` ### Library Usage [Section titled “Library Usage”](#library-usage) ```bash # Core packages for building tools bun add @rcs-lang/core @rcs-lang/ast @rcs-lang/parser # Full compilation stack bun add @rcs-lang/compiler @rcs-lang/validation @rcs-lang/file-system # Runtime for production agents bun add @rcs-lang/csm # IDE integration bun add @rcs-lang/language-service ``` ### Package Versioning [Section titled “Package Versioning”](#package-versioning) All RCL packages follow **synchronized versioning** - when any package is updated, all packages are bumped to the same version number. This ensures compatibility across the ecosystem. **Current version: 0.2.1** *** ## 🧑‍💻 **Development** [Section titled “🧑‍💻 Development”](#-development) ### Monorepo Structure [Section titled “Monorepo Structure”](#monorepo-structure) All packages are part of a monorepo managed with **Moon** and use **Bun** for package management: ```bash # Clone the repository git clone https://github.com/rcs-lang/rcl.git cd rcl # Install dependencies bun install # Build all packages moon run :build # Run tests moon run :test # Watch mode for development moon run :dev ``` ### Package Management [Section titled “Package Management”](#package-management) * **Build System:** Moon (task orchestration) * **Package Manager:** Bun (fast, modern) * **Runtime:** Node.js AND Web browser support * **Grammar:** ANTLR4 (replaced Tree-sitter) *** ## 🤝 **Contributing** [Section titled “🤝 Contributing”](#-contributing) We welcome contributions! Each package accepts: * **Bug reports** - Help us improve stability * **Feature requests** - Guide our roadmap * **Documentation** - Make RCL more accessible * **Code contributions** - Implement features and fixes See the main repository for detailed contribution guidelines. *** ## 📖 **Additional Resources** [Section titled “📖 Additional Resources”](#-additional-resources) * **[Getting Started Guide](/docs/getting-started)** - Build your first RCS agent * **[RCL Language Specification](/docs/rcl-formal-specification)** - Complete language reference * **[Examples](/docs/examples)** - Real-world RCL implementations * **[API Documentation](/docs/api)** - Complete API reference # @rcs-lang/ast > TypeScript type definitions and utilities for working with RCL Abstract Syntax Trees # @rcs-lang/ast [Section titled “@rcs-lang/ast”](#rcs-langast) The `@rcs-lang/ast` package provides TypeScript type definitions for working with RCL Abstract Syntax Trees. This guide will help you understand how to use these types effectively in your projects. ## Installation [Section titled “Installation”](#installation) * npm ```bash npm install @rcs-lang/ast ``` * pnpm ```bash pnpm add @rcs-lang/ast ``` * Yarn ```bash yarn add @rcs-lang/ast ``` * Bun ```bash bun add @rcs-lang/ast ``` ## Basic Usage [Section titled “Basic Usage”](#basic-usage) ### Importing Types [Section titled “Importing Types”](#importing-types) ```typescript // Import specific types import { RclFile, AgentDefinition, FlowDefinition } from '@rcs-lang/ast'; // Import all types under namespace import * as AST from '@rcs-lang/ast'; // Import utilities import { walkAST, isMessageDefinition } from '@rcs-lang/ast'; ``` ### Working with AST Nodes [Section titled “Working with AST Nodes”](#working-with-ast-nodes) Every AST node has a `type` property that identifies its kind and a `range` property that indicates its location in the source code. ```typescript import { ASTNode, Range } from '@rcs-lang/ast'; function printNodeInfo(node: ASTNode) { console.log(`Node type: ${node.type}`); console.log(`Location: Line ${node.range.start.line}, Column ${node.range.start.character}`); } ``` ## Understanding the AST Structure [Section titled “Understanding the AST Structure”](#understanding-the-ast-structure) ### Document Hierarchy [Section titled “Document Hierarchy”](#document-hierarchy) RCL documents follow this structure: ```plaintext RclFile ├── AgentDefinition │ ├── ConfigSection (optional) │ ├── DefaultsSection (optional) │ └── FlowDefinition[] (one or more) └── MessagesSection (optional) └── MessageDefinition[] (zero or more) ``` ### Example AST [Section titled “Example AST”](#example-ast) For this RCL code: ```rcl agent CoffeeBot displayName: "Coffee Shop Assistant" flow OrderFlow start: Welcome on Welcome match @reply.text "coffee" -> OrderCoffee :default -> Welcome messages Messages text Welcome "What can I get you?" ``` The AST structure would be: ```typescript const ast: AST.RclFile = { type: 'RclFile', agent: { type: 'AgentDefinition', name: 'CoffeeBot', displayName: 'Coffee Shop Assistant', flows: [ { type: 'FlowDefinition', name: 'OrderFlow', start: 'Welcome', states: [ { type: 'StateDefinition', name: 'Welcome', transitions: [/* ... */] } ] } ] }, messages: { type: 'MessagesSection', messages: [ { type: 'TextMessage', name: 'Welcome', messageType: 'text', text: 'What can I get you?' } ] } } ``` ## Working with Different Node Types [Section titled “Working with Different Node Types”](#working-with-different-node-types) ### Agent Definitions [Section titled “Agent Definitions”](#agent-definitions) ```typescript import { AgentDefinition, isAgentDefinition } from '@rcs-lang/ast'; function analyzeAgent(node: ASTNode) { if (isAgentDefinition(node)) { console.log(`Agent: ${node.name}`); console.log(`Display Name: ${node.displayName || 'Not set'}`); console.log(`Flows: ${node.flows.length}`); // Check for configuration if (node.config) { console.log('Has configuration section'); } // Check for defaults if (node.defaults) { console.log('Has defaults section'); } } } ``` ### Flow Definitions [Section titled “Flow Definitions”](#flow-definitions) ```typescript import { FlowDefinition, isFlowDefinition } from '@rcs-lang/ast'; function analyzeFlow(node: ASTNode) { if (isFlowDefinition(node)) { console.log(`Flow: ${node.name}`); console.log(`Start State: ${node.start}`); console.log(`States: ${node.states.map(s => s.name).join(', ')}`); } } ``` ### Message Definitions [Section titled “Message Definitions”](#message-definitions) ```typescript import { MessageDefinition, isTextMessage, isRichCardMessage, isCarouselMessage } from '@rcs-lang/ast'; function analyzeMessage(message: MessageDefinition) { console.log(`Message: ${message.name}`); if (isTextMessage(message)) { console.log(`Type: Text`); console.log(`Content: ${message.text}`); if (message.suggestions) { console.log(`Suggestions: ${message.suggestions.length}`); } } else if (isRichCardMessage(message)) { console.log(`Type: Rich Card`); console.log(`Title: ${message.title}`); console.log(`Size: ${message.size || 'default'}`); if (message.description) { console.log(`Description: ${message.description}`); } } else if (isCarouselMessage(message)) { console.log(`Type: Carousel`); console.log(`Title: ${message.title}`); console.log(`Cards: ${message.cards.length}`); } } ``` ## AST Traversal Patterns [Section titled “AST Traversal Patterns”](#ast-traversal-patterns) ### Walking the Entire Tree [Section titled “Walking the Entire Tree”](#walking-the-entire-tree) ```typescript import { walkAST } from '@rcs-lang/ast'; function findAllIdentifiers(ast: AST.RclFile): string[] { const identifiers: string[] = []; walkAST(ast, (node) => { if (node.type === 'Identifier') { identifiers.push((node as AST.Identifier).name); } }); return identifiers; } ``` ### Finding Specific Nodes [Section titled “Finding Specific Nodes”](#finding-specific-nodes) ```typescript import { findNode, findAllNodes } from '@rcs-lang/ast'; // Find the first flow function getFirstFlow(ast: AST.RclFile): AST.FlowDefinition | null { const flowNode = findNode(ast, (node) => node.type === 'FlowDefinition'); return flowNode as AST.FlowDefinition | null; } // Find all text messages function getAllTextMessages(ast: AST.RclFile): AST.TextMessage[] { const textNodes = findAllNodes(ast, (node) => node.type === 'TextMessage'); return textNodes as AST.TextMessage[]; } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) ### Extracting Metadata [Section titled “Extracting Metadata”](#extracting-metadata) ```typescript import { RclFile, isMessageDefinition } from '@rcs-lang/ast'; interface AgentMetadata { name: string; displayName?: string; flowCount: number; messageCount: number; messageTypes: string[]; } function extractMetadata(ast: RclFile): AgentMetadata { const messageTypes = new Set(); let messageCount = 0; walkAST(ast, (node) => { if (isMessageDefinition(node)) { messageCount++; messageTypes.add(node.messageType); } }); return { name: ast.agent.name, displayName: ast.agent.displayName, flowCount: ast.agent.flows.length, messageCount, messageTypes: Array.from(messageTypes) }; } ``` ### Integration with Other Packages [Section titled “Integration with Other Packages”](#integration-with-other-packages) ```typescript import { RCLParser } from '@rcs-lang/parser'; import { RclFile } from '@rcs-lang/ast'; async function parseAndAnalyze(source: string) { const parser = new RCLParser(); const result = await parser.parse(source); if (result.success) { const ast: RclFile = result.data; const metadata = extractMetadata(ast); console.log('Agent metadata:', metadata); } } ``` ## Type Safety Best Practices [Section titled “Type Safety Best Practices”](#type-safety-best-practices) ### Using Type Guards [Section titled “Using Type Guards”](#using-type-guards) Always use type guards instead of casting: ```typescript // ✅ Good: Type-safe with runtime checking function processNode(node: ASTNode) { if (isFlowDefinition(node)) { // TypeScript knows node is FlowDefinition console.log(node.start); } } // ❌ Bad: Unsafe casting function processNodeUnsafe(node: ASTNode) { const flow = node as FlowDefinition; // Could be wrong! console.log(flow.start); // Runtime error if not a flow } ``` ### Exhaustive Type Checking [Section titled “Exhaustive Type Checking”](#exhaustive-type-checking) Use discriminated unions for complete type coverage: ```typescript function processMessage(message: MessageDefinition) { switch (message.messageType) { case 'text': // Handle text message break; case 'richCard': // Handle rich card break; case 'carousel': // Handle carousel break; default: // TypeScript will error if we miss a case const exhaustive: never = message.messageType; throw new Error(`Unhandled message type: ${exhaustive}`); } } ``` ## API Reference [Section titled “API Reference”](#api-reference) For detailed API documentation of all interfaces, types, and functions, see the [API Reference](/api/ast/readme/). # AST API Reference > Type definitions for RCL Abstract Syntax Tree # AST API Reference [Section titled “AST API Reference”](#ast-api-reference) ## Overview [Section titled “Overview”](#overview) The `@rcs-lang/ast` package provides TypeScript type definitions for the RCL Abstract Syntax Tree. This reference documents all available types, interfaces, and utilities. ## Core Types [Section titled “Core Types”](#core-types) ### Base Types [Section titled “Base Types”](#base-types) #### ASTNode [Section titled “ASTNode”](#astnode) Base interface for all AST nodes. ```typescript interface ASTNode { type: string; range: Range; parent?: ASTNode; children?: ASTNode[]; } ``` #### Range [Section titled “Range”](#range) Represents a location in source code. ```typescript interface Range { start: Position; end: Position; } interface Position { line: number; character: number; } ``` ## Document Structure [Section titled “Document Structure”](#document-structure) ### RclFile [Section titled “RclFile”](#rclfile) The root node of an RCL document. ```typescript interface RclFile extends ASTNode { type: 'RclFile'; agent: AgentDefinition; messages?: MessagesSection; } ``` **Properties:** * `agent` - The agent definition (required) * `messages` - Optional messages section ## Agent Definition [Section titled “Agent Definition”](#agent-definition) ### AgentDefinition [Section titled “AgentDefinition”](#agentdefinition) Defines an RCS agent with its configuration and flows. ```typescript interface AgentDefinition extends ASTNode { type: 'AgentDefinition'; name: string; displayName?: string; config?: ConfigSection; defaults?: DefaultsSection; flows: FlowDefinition[]; } ``` **Properties:** * `name` - Agent identifier (must be valid identifier) * `displayName` - Human-readable name * `config` - Agent configuration section * `defaults` - Default values section * `flows` - Array of conversation flows ### ConfigSection [Section titled “ConfigSection”](#configsection) Agent configuration settings. ```typescript interface ConfigSection extends ASTNode { type: 'ConfigSection'; properties: ConfigProperty[]; } interface ConfigProperty extends ASTNode { type: 'ConfigProperty'; key: string; value: PropertyValue; } ``` **Standard Config Properties:** * `description` - Agent description * `logoUri` - Agent logo URL * `color` - Brand color * `phoneNumber` - Contact phone number * `phoneLabel` - Phone number label ### DefaultsSection [Section titled “DefaultsSection”](#defaultssection) Default configuration values. ```typescript interface DefaultsSection extends ASTNode { type: 'DefaultsSection'; properties: DefaultProperty[]; } interface DefaultProperty extends ASTNode { type: 'DefaultProperty'; key: string; value: PropertyValue; } ``` **Standard Default Properties:** * `fallbackMessage` - Default fallback message * `messageTrafficType` - Message traffic type ## Flow Definitions [Section titled “Flow Definitions”](#flow-definitions) ### FlowDefinition [Section titled “FlowDefinition”](#flowdefinition) Defines a conversation flow with states and transitions. ```typescript interface FlowDefinition extends ASTNode { type: 'FlowDefinition'; name: string; start: string; states: StateDefinition[]; } ``` **Properties:** * `name` - Flow identifier * `start` - Starting state name * `states` - Array of state definitions ### StateDefinition [Section titled “StateDefinition”](#statedefinition) Defines a state within a flow. ```typescript interface StateDefinition extends ASTNode { type: 'StateDefinition'; name: string; transitions?: TransitionDefinition[]; actions?: ActionDefinition[]; } ``` **Properties:** * `name` - State identifier * `transitions` - Outgoing transitions * `actions` - Actions to perform in this state ### TransitionDefinition [Section titled “TransitionDefinition”](#transitiondefinition) Defines a transition between states. ```typescript interface TransitionDefinition extends ASTNode { type: 'TransitionDefinition'; condition?: ConditionExpression; target: string; actions?: ActionDefinition[]; } ``` **Properties:** * `condition` - Condition for transition * `target` - Target state name * `actions` - Actions to perform during transition ## Match Blocks [Section titled “Match Blocks”](#match-blocks) ### MatchBlock [Section titled “MatchBlock”](#matchblock) Pattern matching for user input. ```typescript interface MatchBlock extends ASTNode { type: 'MatchBlock'; discriminant: Expression; cases: MatchCase[]; defaultCase?: MatchCase; } ``` ### MatchCase [Section titled “MatchCase”](#matchcase) A single case in a match block. ```typescript interface MatchCase extends ASTNode { type: 'MatchCase'; pattern: MatchPattern; target: string; actions?: ActionDefinition[]; } ``` ### MatchPattern [Section titled “MatchPattern”](#matchpattern) Patterns for matching user input. ```typescript type MatchPattern = | StringPattern | RegexPattern | DefaultPattern; interface StringPattern extends ASTNode { type: 'StringPattern'; value: string; } interface RegexPattern extends ASTNode { type: 'RegexPattern'; pattern: string; flags?: string; } interface DefaultPattern extends ASTNode { type: 'DefaultPattern'; } ``` ## Message Definitions [Section titled “Message Definitions”](#message-definitions) ### MessagesSection [Section titled “MessagesSection”](#messagessection) Container for message definitions. ```typescript interface MessagesSection extends ASTNode { type: 'MessagesSection'; messages: MessageDefinition[]; } ``` ### MessageDefinition [Section titled “MessageDefinition”](#messagedefinition) Base interface for all message types. ```typescript interface MessageDefinition extends ASTNode { name: string; messageType: MessageType; } type MessageType = 'text' | 'richCard' | 'carousel'; ``` ### TextMessage [Section titled “TextMessage”](#textmessage) Simple text message. ```typescript interface TextMessage extends MessageDefinition { type: 'TextMessage'; messageType: 'text'; text: string; suggestions?: Suggestion[]; } ``` ### RichCardMessage [Section titled “RichCardMessage”](#richcardmessage) Rich card with media and buttons. ```typescript interface RichCardMessage extends MessageDefinition { type: 'RichCardMessage'; messageType: 'richCard'; title: string; size?: CardSize; description?: string; media?: MediaElement; suggestions?: Suggestion[]; } type CardSize = 'compact' | 'medium' | 'large'; ``` ### CarouselMessage [Section titled “CarouselMessage”](#carouselmessage) Carousel of multiple cards. ```typescript interface CarouselMessage extends MessageDefinition { type: 'CarouselMessage'; messageType: 'carousel'; title: string; size?: CardSize; cards: RichCardMessage[]; } ``` ## Suggestions [Section titled “Suggestions”](#suggestions) ### Suggestion [Section titled “Suggestion”](#suggestion) Base interface for suggestions. ```typescript interface Suggestion extends ASTNode { suggestionType: SuggestionType; text: string; } type SuggestionType = 'reply' | 'action'; ``` ### ReplySuggestion [Section titled “ReplySuggestion”](#replysuggestion) Quick reply suggestion. ```typescript interface ReplySuggestion extends Suggestion { type: 'ReplySuggestion'; suggestionType: 'reply'; } ``` ### ActionSuggestion [Section titled “ActionSuggestion”](#actionsuggestion) Action suggestion with URL. ```typescript interface ActionSuggestion extends Suggestion { type: 'ActionSuggestion'; suggestionType: 'action'; url: string; } ``` ## Expressions [Section titled “Expressions”](#expressions) ### Expression [Section titled “Expression”](#expression) Base interface for expressions. ```typescript interface Expression extends ASTNode { expressionType: ExpressionType; } type ExpressionType = | 'identifier' | 'literal' | 'memberAccess' | 'functionCall'; ``` ### Identifier [Section titled “Identifier”](#identifier) Variable or property reference. ```typescript interface Identifier extends Expression { type: 'Identifier'; expressionType: 'identifier'; name: string; } ``` ### Literal [Section titled “Literal”](#literal) Literal value. ```typescript interface Literal extends Expression { type: 'Literal'; expressionType: 'literal'; value: string | number | boolean; } ``` ### MemberAccess [Section titled “MemberAccess”](#memberaccess) Property access expression. ```typescript interface MemberAccess extends Expression { type: 'MemberAccess'; expressionType: 'memberAccess'; object: Expression; property: string; } ``` ## Type Guards [Section titled “Type Guards”](#type-guards) The package provides type guard functions for runtime type checking: ```typescript // Document structure function isRclFile(node: ASTNode): node is RclFile; function isAgentDefinition(node: ASTNode): node is AgentDefinition; function isMessagesSection(node: ASTNode): node is MessagesSection; // Flow elements function isFlowDefinition(node: ASTNode): node is FlowDefinition; function isStateDefinition(node: ASTNode): node is StateDefinition; function isTransitionDefinition(node: ASTNode): node is TransitionDefinition; // Messages function isMessageDefinition(node: ASTNode): node is MessageDefinition; function isTextMessage(node: ASTNode): node is TextMessage; function isRichCardMessage(node: ASTNode): node is RichCardMessage; function isCarouselMessage(node: ASTNode): node is CarouselMessage; // Suggestions function isSuggestion(node: ASTNode): node is Suggestion; function isReplySuggestion(node: ASTNode): node is ReplySuggestion; function isActionSuggestion(node: ASTNode): node is ActionSuggestion; // Expressions function isExpression(node: ASTNode): node is Expression; function isIdentifier(node: ASTNode): node is Identifier; function isLiteral(node: ASTNode): node is Literal; function isMemberAccess(node: ASTNode): node is MemberAccess; ``` ## Utility Functions [Section titled “Utility Functions”](#utility-functions) ### AST Traversal [Section titled “AST Traversal”](#ast-traversal) ```typescript function walkAST(node: ASTNode, visitor: (node: ASTNode) => void): void; function walkASTAsync(node: ASTNode, visitor: (node: ASTNode) => Promise): Promise; ``` ### AST Queries [Section titled “AST Queries”](#ast-queries) ```typescript function findNode(root: ASTNode, predicate: (node: ASTNode) => boolean): ASTNode | null; function findAllNodes(root: ASTNode, predicate: (node: ASTNode) => boolean): ASTNode[]; function getParent(node: ASTNode): ASTNode | null; function getChildren(node: ASTNode): ASTNode[]; ``` ### Location Utilities [Section titled “Location Utilities”](#location-utilities) ```typescript function getNodeRange(node: ASTNode): Range; function isPositionInRange(position: Position, range: Range): boolean; function comparePositions(a: Position, b: Position): number; function compareRanges(a: Range, b: Range): number; ``` ## Constants [Section titled “Constants”](#constants) ### Node Types [Section titled “Node Types”](#node-types) ```typescript export const NodeTypes = { // Document RCL_FILE: 'RclFile', // Agent AGENT_DEFINITION: 'AgentDefinition', CONFIG_SECTION: 'ConfigSection', DEFAULTS_SECTION: 'DefaultsSection', // Flows FLOW_DEFINITION: 'FlowDefinition', STATE_DEFINITION: 'StateDefinition', TRANSITION_DEFINITION: 'TransitionDefinition', // Messages MESSAGES_SECTION: 'MessagesSection', TEXT_MESSAGE: 'TextMessage', RICH_CARD_MESSAGE: 'RichCardMessage', CAROUSEL_MESSAGE: 'CarouselMessage', // Suggestions REPLY_SUGGESTION: 'ReplySuggestion', ACTION_SUGGESTION: 'ActionSuggestion', // Expressions IDENTIFIER: 'Identifier', LITERAL: 'Literal', MEMBER_ACCESS: 'MemberAccess' } as const; ``` ### Message Types [Section titled “Message Types”](#message-types) ```typescript export const MessageTypes = { TEXT: 'text', RICH_CARD: 'richCard', CAROUSEL: 'carousel' } as const; ``` ### Card Sizes [Section titled “Card Sizes”](#card-sizes) ```typescript export const CardSizes = { COMPACT: 'compact', MEDIUM: 'medium', LARGE: 'large' } as const; ``` ## Examples [Section titled “Examples”](#examples) ### Creating AST Nodes [Section titled “Creating AST Nodes”](#creating-ast-nodes) ```typescript import * as AST from '@rcs-lang/ast'; // Create a text message const textMessage: AST.TextMessage = { type: 'TextMessage', messageType: 'text', name: 'Welcome', text: 'Hello, world!', range: { start: { line: 1, character: 0 }, end: { line: 1, character: 30 } } }; // Create an agent definition const agent: AST.AgentDefinition = { type: 'AgentDefinition', name: 'MyAgent', displayName: 'My Agent', flows: [], range: { start: { line: 0, character: 0 }, end: { line: 10, character: 0 } } }; ``` ### AST Traversal [Section titled “AST Traversal”](#ast-traversal-1) ```typescript import { walkAST, isMessageDefinition } from '@rcs-lang/ast'; function collectMessages(ast: AST.RclFile): string[] { const messages: string[] = []; walkAST(ast, (node) => { if (isMessageDefinition(node)) { messages.push(node.name); } }); return messages; } ``` ### Type Guards [Section titled “Type Guards”](#type-guards-1) ```typescript import { isTextMessage, isRichCardMessage } from '@rcs-lang/ast'; function analyzeMessage(message: AST.MessageDefinition) { if (isTextMessage(message)) { console.log('Text message:', message.text); } else if (isRichCardMessage(message)) { console.log('Rich card:', message.title); } } ``` # AST User Guide > Guide for working with RCL Abstract Syntax Trees # AST User Guide [Section titled “AST User Guide”](#ast-user-guide) ## Getting Started [Section titled “Getting Started”](#getting-started) The `@rcs-lang/ast` package provides TypeScript type definitions for working with RCL Abstract Syntax Trees. This guide will help you understand how to use these types effectively in your projects. ## Installation [Section titled “Installation”](#installation) ```bash npm install @rcs-lang/ast ``` ## Basic Usage [Section titled “Basic Usage”](#basic-usage) ### Importing Types [Section titled “Importing Types”](#importing-types) ```typescript // Import specific types import { RclFile, AgentDefinition, FlowDefinition } from '@rcs-lang/ast'; // Import all types under namespace import * as AST from '@rcs-lang/ast'; // Import utilities import { walkAST, isMessageDefinition } from '@rcs-lang/ast'; ``` ### Working with AST Nodes [Section titled “Working with AST Nodes”](#working-with-ast-nodes) Every AST node has a `type` property that identifies its kind and a `range` property that indicates its location in the source code. ```typescript import { ASTNode, Range } from '@rcs-lang/ast'; function printNodeInfo(node: ASTNode) { console.log(`Node type: ${node.type}`); console.log(`Location: Line ${node.range.start.line}, Column ${node.range.start.character}`); } ``` ## Understanding the AST Structure [Section titled “Understanding the AST Structure”](#understanding-the-ast-structure) ### Document Hierarchy [Section titled “Document Hierarchy”](#document-hierarchy) RCL documents follow this structure: ```plaintext RclFile ├── AgentDefinition │ ├── ConfigSection (optional) │ ├── DefaultsSection (optional) │ └── FlowDefinition[] (one or more) └── MessagesSection (optional) └── MessageDefinition[] (zero or more) ``` ### Example AST [Section titled “Example AST”](#example-ast) For this RCL code: ```rcl agent CoffeeBot displayName: "Coffee Shop Assistant" flow OrderFlow start: Welcome on Welcome match @reply.text "coffee" -> OrderCoffee :default -> Welcome messages Messages text Welcome "What can I get you?" ``` The AST structure would be: ```typescript const ast: AST.RclFile = { type: 'RclFile', agent: { type: 'AgentDefinition', name: 'CoffeeBot', displayName: 'Coffee Shop Assistant', flows: [ { type: 'FlowDefinition', name: 'OrderFlow', start: 'Welcome', states: [ { type: 'StateDefinition', name: 'Welcome', transitions: [/* ... */] } ] } ] }, messages: { type: 'MessagesSection', messages: [ { type: 'TextMessage', name: 'Welcome', messageType: 'text', text: 'What can I get you?' } ] } } ``` ## Working with Different Node Types [Section titled “Working with Different Node Types”](#working-with-different-node-types) ### Agent Definitions [Section titled “Agent Definitions”](#agent-definitions) ```typescript import { AgentDefinition, isAgentDefinition } from '@rcs-lang/ast'; function analyzeAgent(node: ASTNode) { if (isAgentDefinition(node)) { console.log(`Agent: ${node.name}`); console.log(`Display Name: ${node.displayName || 'Not set'}`); console.log(`Flows: ${node.flows.length}`); // Check for configuration if (node.config) { console.log('Has configuration section'); } // Check for defaults if (node.defaults) { console.log('Has defaults section'); } } } ``` ### Flow Definitions [Section titled “Flow Definitions”](#flow-definitions) ```typescript import { FlowDefinition, isFlowDefinition } from '@rcs-lang/ast'; function analyzeFlow(node: ASTNode) { if (isFlowDefinition(node)) { console.log(`Flow: ${node.name}`); console.log(`Start State: ${node.start}`); console.log(`States: ${node.states.map(s => s.name).join(', ')}`); } } ``` ### Message Definitions [Section titled “Message Definitions”](#message-definitions) ```typescript import { MessageDefinition, isTextMessage, isRichCardMessage, isCarouselMessage } from '@rcs-lang/ast'; function analyzeMessage(message: MessageDefinition) { console.log(`Message: ${message.name}`); if (isTextMessage(message)) { console.log(`Type: Text`); console.log(`Content: ${message.text}`); if (message.suggestions) { console.log(`Suggestions: ${message.suggestions.length}`); } } else if (isRichCardMessage(message)) { console.log(`Type: Rich Card`); console.log(`Title: ${message.title}`); console.log(`Size: ${message.size || 'default'}`); if (message.description) { console.log(`Description: ${message.description}`); } } else if (isCarouselMessage(message)) { console.log(`Type: Carousel`); console.log(`Title: ${message.title}`); console.log(`Cards: ${message.cards.length}`); } } ``` ## AST Traversal Patterns [Section titled “AST Traversal Patterns”](#ast-traversal-patterns) ### Walking the Entire Tree [Section titled “Walking the Entire Tree”](#walking-the-entire-tree) ```typescript import { walkAST } from '@rcs-lang/ast'; function findAllIdentifiers(ast: AST.RclFile): string[] { const identifiers: string[] = []; walkAST(ast, (node) => { if (node.type === 'Identifier') { identifiers.push((node as AST.Identifier).name); } }); return identifiers; } ``` ### Finding Specific Nodes [Section titled “Finding Specific Nodes”](#finding-specific-nodes) ```typescript import { findNode, findAllNodes } from '@rcs-lang/ast'; // Find the first flow function getFirstFlow(ast: AST.RclFile): AST.FlowDefinition | null { const flowNode = findNode(ast, (node) => node.type === 'FlowDefinition'); return flowNode as AST.FlowDefinition | null; } // Find all text messages function getAllTextMessages(ast: AST.RclFile): AST.TextMessage[] { const textNodes = findAllNodes(ast, (node) => node.type === 'TextMessage'); return textNodes as AST.TextMessage[]; } ``` ### Conditional Processing [Section titled “Conditional Processing”](#conditional-processing) ```typescript import { isFlowDefinition, isStateDefinition } from '@rcs-lang/ast'; function analyzeFlowComplexity(ast: AST.RclFile) { walkAST(ast, (node) => { if (isFlowDefinition(node)) { const stateCount = node.states.length; const complexity = stateCount > 5 ? 'High' : stateCount > 2 ? 'Medium' : 'Low'; console.log(`Flow ${node.name}: ${complexity} complexity (${stateCount} states)`); } }); } ``` ## Common Use Cases [Section titled “Common Use Cases”](#common-use-cases) ### Extracting Metadata [Section titled “Extracting Metadata”](#extracting-metadata) ```typescript import { RclFile, isMessageDefinition } from '@rcs-lang/ast'; interface AgentMetadata { name: string; displayName?: string; flowCount: number; messageCount: number; messageTypes: string[]; } function extractMetadata(ast: RclFile): AgentMetadata { const messageTypes = new Set(); let messageCount = 0; walkAST(ast, (node) => { if (isMessageDefinition(node)) { messageCount++; messageTypes.add(node.messageType); } }); return { name: ast.agent.name, displayName: ast.agent.displayName, flowCount: ast.agent.flows.length, messageCount, messageTypes: Array.from(messageTypes) }; } ``` ### Validation and Analysis [Section titled “Validation and Analysis”](#validation-and-analysis) ```typescript import { RclFile, isStateDefinition, isTransitionDefinition } from '@rcs-lang/ast'; interface ValidationResult { isValid: boolean; errors: string[]; warnings: string[]; } function validateFlowStructure(ast: RclFile): ValidationResult { const errors: string[] = []; const warnings: string[] = []; // Check that all flows have start states ast.agent.flows.forEach(flow => { const hasStartState = flow.states.some(state => state.name === flow.start); if (!hasStartState) { errors.push(`Flow ${flow.name} references unknown start state: ${flow.start}`); } // Check for unreachable states const reachableStates = new Set([flow.start]); walkAST(flow, (node) => { if (isTransitionDefinition(node)) { reachableStates.add(node.target); } }); flow.states.forEach(state => { if (!reachableStates.has(state.name)) { warnings.push(`State ${state.name} in flow ${flow.name} may be unreachable`); } }); }); return { isValid: errors.length === 0, errors, warnings }; } ``` ### Code Generation [Section titled “Code Generation”](#code-generation) ```typescript import { RclFile, isTextMessage } from '@rcs-lang/ast'; function generateMessageConstants(ast: RclFile): string { const lines: string[] = []; lines.push('// Generated message constants'); lines.push('export const Messages = {'); if (ast.messages) { ast.messages.messages.forEach(message => { if (isTextMessage(message)) { const safeName = message.name.toUpperCase().replace(/[^A-Z0-9]/g, '_'); lines.push(` ${safeName}: '${message.text.replace(/'/g, "\'")}',`); } }); } lines.push('} as const;'); return lines.join(' '); } ``` ## Performance Considerations [Section titled “Performance Considerations”](#performance-considerations) ### Efficient Traversal [Section titled “Efficient Traversal”](#efficient-traversal) When working with large ASTs, consider these optimization strategies: ```typescript // Early termination function findFirstError(ast: RclFile): string | null { let error: string | null = null; try { walkAST(ast, (node) => { if (/* some error condition */) { error = 'Found error'; throw new Error('Stop traversal'); // Early exit } }); } catch (e) { // Expected early termination } return error; } // Targeted searches function getFlowNames(ast: RclFile): string[] { // Direct access is more efficient than full traversal return ast.agent.flows.map(flow => flow.name); } // Memoization for expensive operations const analysisCache = new Map(); function analyzeWithCaching(ast: RclFile, key: string) { if (analysisCache.has(key)) { return analysisCache.get(key); } const result = performExpensiveAnalysis(ast); analysisCache.set(key, result); return result; } ``` ### Memory Management [Section titled “Memory Management”](#memory-management) ```typescript // Clean up references when done function processAST(ast: RclFile) { try { // Process the AST return doSomethingWithAST(ast); } finally { // Clear parent references to help GC walkAST(ast, (node) => { if (node.parent) { delete node.parent; } }); } } ``` ## Type Safety Best Practices [Section titled “Type Safety Best Practices”](#type-safety-best-practices) ### Using Type Guards [Section titled “Using Type Guards”](#using-type-guards) Always use type guards instead of casting: ```typescript // ✅ Good: Type-safe with runtime checking function processNode(node: ASTNode) { if (isFlowDefinition(node)) { // TypeScript knows node is FlowDefinition console.log(node.start); } } // ❌ Bad: Unsafe casting function processNodeUnsafe(node: ASTNode) { const flow = node as FlowDefinition; // Could be wrong! console.log(flow.start); // Runtime error if not a flow } ``` ### Exhaustive Type Checking [Section titled “Exhaustive Type Checking”](#exhaustive-type-checking) Use discriminated unions for complete type coverage: ```typescript function processMessage(message: MessageDefinition) { switch (message.messageType) { case 'text': // Handle text message break; case 'richCard': // Handle rich card break; case 'carousel': // Handle carousel break; default: // TypeScript will error if we miss a case const exhaustive: never = message.messageType; throw new Error(`Unhandled message type: ${exhaustive}`); } } ``` ## Integration Examples [Section titled “Integration Examples”](#integration-examples) ### With Parser [Section titled “With Parser”](#with-parser) ```typescript import { RCLParser } from '@rcs-lang/parser'; import { RclFile } from '@rcs-lang/ast'; async function parseAndAnalyze(source: string) { const parser = new RCLParser(); const result = await parser.parse(source); if (result.success) { const ast: RclFile = result.data; const metadata = extractMetadata(ast); console.log('Agent metadata:', metadata); } } ``` ### With Compiler [Section titled “With Compiler”](#with-compiler) ```typescript import { RCLCompiler } from '@rcs-lang/compiler'; import { walkAST, isMessageDefinition } from '@rcs-lang/ast'; class CustomCompiler extends RCLCompiler { protected preprocessAST(ast: RclFile): RclFile { // Custom preprocessing using AST types walkAST(ast, (node) => { if (isMessageDefinition(node)) { // Transform message nodes } }); return ast; } } ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues [Section titled “Common Issues”](#common-issues) 1. **Missing Type Guards**: Always use type guards before accessing type-specific properties. 2. **Range Information**: Not all AST nodes may have complete range information during construction. 3. **Parent References**: Parent references are typically set by the parser, not manually constructed ASTs. 4. **Memory Leaks**: Clear parent references when no longer needed to help garbage collection. ### Debugging Tips [Section titled “Debugging Tips”](#debugging-tips) ```typescript // Add helper for debugging AST structure function debugAST(node: ASTNode, depth = 0) { const indent = ' '.repeat(depth); console.log(`${indent}${node.type}`); if (node.children) { node.children.forEach(child => debugAST(child, depth + 1)); } } // Validate AST structure function validateASTStructure(node: ASTNode): boolean { // Check required properties exist if (!node.type || !node.range) { console.error('Invalid node: missing type or range'); return false; } // Recursively validate children if (node.children) { return node.children.every(child => validateASTStructure(child)); } return true; } ``` # @rcs-lang/cli > Command-line interface for compiling RCL files # @rcs-lang/cli [Section titled “@rcs-lang/cli”](#rcs-langcli) Command-line interface for compiling RCL (Rich Communication Language) files into JavaScript modules and JSON configurations. Provides a simple way to compile `.rcl` files from the command line with multiple output formats and helpful development features. ## Installation [Section titled “Installation”](#installation) ### Global Installation [Section titled “Global Installation”](#global-installation) ```bash bun add -g @rcs-lang/cli # or npm install -g @rcs-lang/cli ``` ### Local Installation [Section titled “Local Installation”](#local-installation) ```bash bun add --dev @rcs-lang/cli # or npm install --save-dev @rcs-lang/cli ``` ## Quick Start [Section titled “Quick Start”](#quick-start) ```bash # Compile a single file rcl compile agent.rcl # Compile with specific output directory rcl compile agent.rcl --output dist/ # Compile multiple files rcl compile src/**/*.rcl # Watch for changes and recompile rcl compile agent.rcl --watch ``` ## Available Commands [Section titled “Available Commands”](#available-commands) ### `compile` - Compile RCL Files [Section titled “compile - Compile RCL Files”](#compile---compile-rcl-files) Compile RCL files to JavaScript and JSON. ```bash rcl compile [options] ``` **Options:** * `-o, --output ` - Output directory (default: same as input) * `-f, --format ` - Output format: `json`, `js`, or `both` (default: `both`) * `--no-pretty` - Disable pretty printing for JSON * `-w, --watch` - Watch files for changes and recompile * `-c, --config ` - Path to rcl.config.json **Examples:** ```bash # Basic compilation rcl compile coffee-shop.rcl # Specify output directory rcl compile agent.rcl --output dist/ # JSON output only rcl compile agent.rcl --format json # Watch mode for development rcl compile src/**/*.rcl --watch --output dist/ ``` ### `parse` - Parse and Output AST [Section titled “parse - Parse and Output AST”](#parse---parse-and-output-ast) Parse RCL files and output the Abstract Syntax Tree (useful for debugging). ```bash rcl parse [output] [options] ``` **Options:** * `--no-pretty` - Disable pretty printing for JSON * `--exclude ` - Comma-separated list of fields to exclude from AST * `--only ` - Comma-separated list of fields to keep in AST **Examples:** ```bash # Parse and output to stdout rcl parse agent.rcl # Parse and save to file rcl parse agent.rcl ast.json # Exclude location information rcl parse agent.rcl --exclude location,source # Only show structure rcl parse agent.rcl --only type,sections,body ``` ### `diagram` - Generate Flow Diagrams [Section titled “diagram - Generate Flow Diagrams”](#diagram---generate-flow-diagrams) Generate visual diagrams from RCL flow definitions. ```bash rcl diagram [options] ``` **Options:** * `-o, --output ` - Output file path * `-t, --type ` - Diagram type: `d2` or `mermaid` (default: `d2`) * `--no-error-paths` - Hide error/invalid option paths * `--no-separate-invalid` - Use shared InvalidOption state instead of local ones **Examples:** ```bash # Generate D2 diagram rcl diagram coffee-shop.rcl # Generate Mermaid diagram rcl diagram coffee-shop.rcl --type mermaid # Custom output location rcl diagram agent.rcl --output diagrams/agent-flow.d2 ``` ### `init` - Initialize Project [Section titled “init - Initialize Project”](#init---initialize-project) Initialize a new RCL project with configuration file. ```bash rcl init ``` Creates an `rcl.config.json` file in the current directory with default settings. ## Output Formats [Section titled “Output Formats”](#output-formats) The CLI generates multiple output formats: ### JSON Output [Section titled “JSON Output”](#json-output) Structured data representation suitable for runtime interpretation: ```json { "agent": { "name": "CoffeeShop", "displayName": "Coffee Shop Agent" }, "flows": { "OrderFlow": { "start": "Welcome", "states": { "Welcome": { "transitions": [...] } } } }, "messages": { "Welcome": { "type": "text", "text": "Hello! How can I help you today?" } } } ``` ### JavaScript Output [Section titled “JavaScript Output”](#javascript-output) ES6 module with convenient exports: ```javascript // Generated from coffee-shop.rcl export const agent = { name: "CoffeeShop", displayName: "Coffee Shop Agent" }; export const messages = { Welcome: { type: "text", text: "Hello! How can I help you today!" } }; export const flows = { OrderFlow: { start: "Welcome", states: { ... } } }; // Convenience export export default { agent, messages, flows }; ``` ### Diagram Formats [Section titled “Diagram Formats”](#diagram-formats) **D2 Diagrams:** ```d2 # Coffee Shop Agent Flow Welcome -> ChooseSize: "order coffee" Welcome -> ShowMenu: "view menu" ChooseSize -> ChooseDrink: "small" | "medium" | "large" ``` **Mermaid Diagrams:** ```mermaid graph TD Welcome --> ChooseSize Welcome --> ShowMenu ChooseSize --> ChooseDrink ``` ## Configuration [Section titled “Configuration”](#configuration) Create an `rcl.config.json` file in your project root: ```json { "outDir": "./dist", "compilerOptions": { "generateSourceMap": true, "preserveComments": false, "strict": true, "module": "esm", "emit": { "json": true, "javascript": true, "declarations": true } }, "include": ["**/*.rcl"], "exclude": ["node_modules", "**/*.test.rcl"] } ``` **Configuration Options:** * `outDir` - Output directory for compiled files * `compilerOptions.generateSourceMap` - Generate source maps for debugging * `compilerOptions.strict` - Enable strict validation mode * `compilerOptions.emit` - Control which output formats to generate * `include` - Glob patterns for files to include * `exclude` - Glob patterns for files to exclude ## Error Handling [Section titled “Error Handling”](#error-handling) The CLI provides detailed error messages with source locations: ```plaintext Error in coffee-shop.rcl: Line 15, Column 8: Missing required 'displayName' in agent definition 13 | agent CoffeeShop 14 | # Missing displayName here > 15 | flow OrderFlow | ^ 16 | start: Welcome ``` ### Exit Codes [Section titled “Exit Codes”](#exit-codes) The CLI uses specific exit codes for different error types: * `0` - Success * `1` - Compilation/syntax errors * `2` - Semantic/validation errors * `3` - File not found * `4` - Write permission error * `64` - Invalid command usage * `70` - Internal error ## Integration with Build Tools [Section titled “Integration with Build Tools”](#integration-with-build-tools) ### npm Scripts [Section titled “npm Scripts”](#npm-scripts) Add RCL compilation to your build process: ```json { "scripts": { "build:rcl": "rcl compile src/**/*.rcl --output dist/", "watch:rcl": "rcl compile src/**/*.rcl --output dist/ --watch", "validate:rcl": "rcl parse src/**/*.rcl", "diagram:rcl": "rcl diagram src/main.rcl --output docs/flow.d2" } } ``` ### CI/CD Integration [Section titled “CI/CD Integration”](#cicd-integration) ```yaml # GitHub Actions example - name: Compile RCL files run: | bun add -g @rcs-lang/cli rcl compile src/**/*.rcl --output dist/ - name: Validate RCL syntax run: rcl parse src/**/*.rcl --exclude location,source ``` ### Watch Mode [Section titled “Watch Mode”](#watch-mode) For development, use watch mode to automatically recompile when files change: ```bash rcl compile src/**/*.rcl --watch --output dist/ ``` This will: * Watch all `.rcl` files in the `src/` directory * Automatically recompile when files change * Output compiled files to `dist/` * Show compilation status and errors ## Programmatic Usage [Section titled “Programmatic Usage”](#programmatic-usage) You can also use the CLI programmatically in Node.js: ```typescript import { compileRCL, parseRCL, generateDiagram } from '@rcs-lang/cli'; // Compile a file const compileResult = await compileRCL('agent.rcl', { output: 'dist/', format: 'both', pretty: true }); // Parse a file const parseResult = await parseRCL('agent.rcl', { output: 'ast.json', pretty: true, exclude: ['location'] }); // Generate diagram await generateDiagram('agent.rcl', { output: 'flow.d2', type: 'd2', errorPaths: false }); ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Common Issues [Section titled “Common Issues”](#common-issues) **File not found:** ```bash ❌ Error: Input file not found: agent.rcl ``` * Check the file path is correct * Ensure the file exists and has `.rcl` extension **Permission errors:** ```bash ❌ Error: Failed to write output: permission denied ``` * Check write permissions on the output directory * Try running with appropriate permissions **Java required for development:** If you're building from source, Java 17+ is required for ANTLR grammar generation. ### Getting Help [Section titled “Getting Help”](#getting-help) ```bash # Show all available commands rcl --help # Show help for specific command rcl compile --help rcl parse --help rcl diagram --help ``` ## Examples [Section titled “Examples”](#examples) ### Basic Agent Compilation [Section titled “Basic Agent Compilation”](#basic-agent-compilation) Input file `coffee-shop.rcl`: ```rcl agent CoffeeShop displayName: "Coffee Shop Agent" flow OrderFlow start: Welcome on Welcome match @userInput "order coffee" -> ChooseSize "view menu" -> ShowMenu messages Messages text Welcome "Hello! How can I help you today?" text ShowMenu "Here's our menu: ..." ``` Compile: ```bash rcl compile coffee-shop.rcl ``` Generates: * `coffee-shop.json` - Runtime configuration * `coffee-shop.js` - JavaScript module ### Batch Processing [Section titled “Batch Processing”](#batch-processing) ```bash # Compile all RCL files in src/ rcl compile src/**/*.rcl --output dist/ # Generate diagrams for all agents for file in src/*.rcl; do rcl diagram "$file" --output "docs/$(basename "$file" .rcl).d2" done ``` ### Development Workflow [Section titled “Development Workflow”](#development-workflow) ```bash # Terminal 1: Watch and compile rcl compile src/**/*.rcl --watch --output dist/ # Terminal 2: Watch and generate diagrams rcl diagram src/main.rcl --watch --output docs/flow.d2 # Terminal 3: Your development server npm run dev ``` ## API Reference [Section titled “API Reference”](#api-reference) For detailed programmatic API documentation, see: * [Compiler API](/packages/compiler) * [Parser API](/packages/parser) * [Validation API](/packages/validation) # Compiler Package > RCL compilation pipeline # Compiler Package [Section titled “Compiler Package”](#compiler-package) The Compiler package provides the modern compilation pipeline using ANTLR AST for transforming RCL code into JavaScript/JSON output. ## Documentation [Section titled “Documentation”](#documentation) * [API Reference](/packages/compiler/compiler-api-reference) # Compiler API Reference > API documentation for RCL compilation pipeline # Compiler API Reference [Section titled “Compiler API Reference”](#compiler-api-reference) ## Overview [Section titled “Overview”](#overview) The `@rcs-lang/compiler` package provides a modern, modular compilation pipeline for RCL. This reference documents all classes, interfaces, and methods available in the public API. ## Core Classes [Section titled “Core Classes”](#core-classes) ### RCLCompiler [Section titled “RCLCompiler”](#rclcompiler) The main compiler class with sensible defaults for most use cases. ```typescript class RCLCompiler { constructor(options?: CompilerOptions) compile(source: string, fileName?: string): Promise compileFile(filePath: string): Promise compileFromAST(ast: RclFile, fileName?: string): Promise setOptions(options: Partial): void getOptions(): CompilerOptions dispose(): void } ``` #### Constructor Options [Section titled “Constructor Options”](#constructor-options) ```typescript interface CompilerOptions { // Output configuration output?: { formats?: OutputFormat[]; directory?: string; fileNames?: { json?: string; js?: string; mermaid?: string; d2?: string; }; }; // Parser configuration parser?: { strictMode?: boolean; maxErrors?: number; includeComments?: boolean; }; // Validation configuration validation?: { enabled?: boolean; strict?: boolean; rules?: ValidationRules; }; // Generation configuration generation?: { javascript?: JavaScriptGeneratorOptions; mermaid?: MermaidGeneratorOptions; d2?: D2GeneratorOptions; }; // Performance configuration performance?: { cache?: boolean; parallel?: boolean; timeout?: number; }; } type OutputFormat = 'json' | 'js' | 'mermaid' | 'd2'; ``` #### Methods [Section titled “Methods”](#methods) ##### compile() [Section titled “compile()”](#compile) Compiles RCL source code to the specified output formats. ```typescript async compile(source: string, fileName?: string): Promise ``` **Parameters:** * `source` - RCL source code as string * `fileName` - Optional file name for diagnostics **Returns:** Promise resolving to `CompilationResult` **Example:** ```typescript const compiler = new RCLCompiler(); const result = await compiler.compile(` agent MyAgent displayName: "My Agent" flow Main start: Welcome messages Messages text Welcome "Hello!" `); if (result.success) { console.log(result.output.json); // JSON output console.log(result.output.js); // JavaScript output } ``` ##### compileFile() [Section titled “compileFile()”](#compilefile) Compiles an RCL file from the file system. ```typescript async compileFile(filePath: string): Promise ``` **Parameters:** * `filePath` - Path to RCL file **Returns:** Promise resolving to `CompilationResult` **Example:** ```typescript const result = await compiler.compileFile('./agents/coffee-shop.rcl'); ``` ##### compileFromAST() [Section titled “compileFromAST()”](#compilefromast) Compiles from an existing AST (skips parsing stage). ```typescript async compileFromAST(ast: RclFile, fileName?: string): Promise ``` **Parameters:** * `ast` - Pre-parsed AST * `fileName` - Optional file name for diagnostics **Returns:** Promise resolving to `CompilationResult` ### CompilationPipeline [Section titled “CompilationPipeline”](#compilationpipeline) Advanced pipeline class for custom compilation workflows. ```typescript class CompilationPipeline { constructor(stages: ICompilationStage[]) execute(input: ICompilationInput): Promise> addStage(stage: ICompilationStage): void removeStage(stageName: string): void getStages(): ICompilationStage[] setParallel(parallel: boolean): void setTimeout(timeout: number): void } ``` #### Usage Example [Section titled “Usage Example”](#usage-example) ```typescript import { CompilationPipeline, ParseStage, ValidateStage, TransformStage, GenerateStage } from '@rcs-lang/compiler'; const pipeline = new CompilationPipeline([ new ParseStage(), new ValidateStage({ strict: true }), new TransformStage(), new GenerateStage({ formats: ['json', 'js'] }) ]); const result = await pipeline.execute({ source: rclSource, uri: 'file:///path/to/file.rcl' }); ``` ## Pipeline Stages [Section titled “Pipeline Stages”](#pipeline-stages) ### ICompilationStage [Section titled “ICompilationStage”](#icompilationstage) Base interface for all compilation stages. ```typescript interface ICompilationStage { readonly name: string; process(input: any): Promise>; } ``` ### ParseStage [Section titled “ParseStage”](#parsestage) Converts RCL source code to AST. ```typescript class ParseStage implements ICompilationStage { constructor(options?: ParseStageOptions) readonly name: 'parse' process(input: ICompilationInput): Promise> } interface ParseStageOptions { parser?: IParser; strictMode?: boolean; maxErrors?: number; includeComments?: boolean; } interface ParseOutput { ast: RclFile; diagnostics: Diagnostic[]; sourceMap?: SourceMap; } ``` ### ValidateStage [Section titled “ValidateStage”](#validatestage) Validates AST for correctness. ```typescript class ValidateStage implements ICompilationStage { constructor(options?: ValidateStageOptions) readonly name: 'validate' process(input: ValidateInput): Promise> } interface ValidateStageOptions { strict?: boolean; rules?: ValidationRules; validators?: IValidator[]; } interface ValidateInput { ast: RclFile; uri: string; source: string; diagnostics?: Diagnostic[]; } interface ValidateOutput extends ValidateInput { isValid: boolean; validationDiagnostics: Diagnostic[]; } ``` ### TransformStage [Section titled “TransformStage”](#transformstage) Transforms AST to intermediate representation. ```typescript class TransformStage implements ICompilationStage { constructor(options?: TransformStageOptions) readonly name: 'transform' process(input: TransformInput): Promise> } interface TransformStageOptions { transformers?: ITransformer[]; preserveComments?: boolean; optimizations?: OptimizationLevel; } interface TransformOutput { agent: AgentConfig; flows: Record; messages: Record; metadata: CompilationMetadata; } ``` ### GenerateStage [Section titled “GenerateStage”](#generatestage) Generates final output files. ```typescript class GenerateStage implements ICompilationStage { constructor(options?: GenerateStageOptions) readonly name: 'generate' process(input: GenerateInput): Promise> } interface GenerateStageOptions { formats: OutputFormat[]; generators?: Record; outputDirectory?: string; } interface GenerateOutput { files: Record; metadata: GenerationMetadata; } ``` ## Generators [Section titled “Generators”](#generators) ### IGenerator [Section titled “IGenerator”](#igenerator) Base interface for output generators. ```typescript interface IGenerator { readonly format: OutputFormat; generate(data: ICompilationOutput, fileName: string): Promise; configure(options: any): void; } ``` ### JavaScriptGenerator [Section titled “JavaScriptGenerator”](#javascriptgenerator) Generates ES6 modules compatible with @rcs-lang/csm. ```typescript class JavaScriptGenerator implements IGenerator { constructor(options?: JavaScriptGeneratorOptions) readonly format: 'js' generate(output: ICompilationOutput, fileName: string): Promise configure(options: JavaScriptGeneratorOptions): void } interface JavaScriptGeneratorOptions { // Module format moduleFormat?: 'es6' | 'cjs' | 'umd'; // Code style indentation?: string; quotes?: 'single' | 'double'; semicolons?: boolean; // Features includeComments?: boolean; includeSourceMap?: boolean; includeTypeDefinitions?: boolean; // CSM integration csmVersion?: string; includeHelper?: boolean; // Optimization minify?: boolean; removeUnused?: boolean; } ``` #### Generated JavaScript Structure [Section titled “Generated JavaScript Structure”](#generated-javascript-structure) ```javascript // Generated by RCL Compiler // Compatible with @rcs-lang/csm export const agent = { name: "MyAgent", displayName: "My Agent", // ... agent configuration }; export const messages = { Welcome: { type: "text", text: "Hello!" }, // ... message definitions }; export const flows = { MainFlow: { start: "Welcome", states: { Welcome: { transitions: [ // ... transitions ] } } } }; export default { agent, messages, flows }; // Helper function for CSM integration export function createAgent(options) { const { ConversationalAgent } = require("@rcs-lang/csm"); const agent = new ConversationalAgent({ id: agent.name, ...options }); Object.values(flows).forEach(flow => { agent.addFlow(flow); }); return agent; } ``` ### MermaidGenerator [Section titled “MermaidGenerator”](#mermaidgenerator) Generates Mermaid diagrams for flow visualization. ```typescript class MermaidGenerator implements IGenerator { constructor(options?: MermaidGeneratorOptions) readonly format: 'mermaid' generate(output: ICompilationOutput, fileName: string): Promise configure(options: MermaidGeneratorOptions): void } interface MermaidGeneratorOptions { // Diagram type diagramType?: 'flowchart' | 'stateDiagram' | 'graph'; // Layout direction?: 'TD' | 'TB' | 'BT' | 'RL' | 'LR'; // Styling theme?: 'default' | 'neutral' | 'dark' | 'forest' | 'base'; // Content includeMessages?: boolean; includeConditions?: boolean; showStateDetails?: boolean; // Formatting nodeShape?: 'rect' | 'round' | 'circle' | 'rhombus'; edgeStyle?: 'solid' | 'dotted' | 'thick'; } ``` ### D2Generator [Section titled “D2Generator”](#d2generator) Generates D2 diagrams with advanced layout options. ```typescript class D2Generator implements IGenerator { constructor(options?: D2GeneratorOptions) readonly format: 'd2' generate(output: ICompilationOutput, fileName: string): Promise configure(options: D2GeneratorOptions): void } interface D2GeneratorOptions { // Layout layout?: 'dagre' | 'elk' | 'tala'; // Styling theme?: 'default' | 'dark' | 'sketch' | 'cool-classics'; // Features includeTooltips?: boolean; includeLinks?: boolean; animate?: boolean; // Content showMessageContent?: boolean; showTransitionLabels?: boolean; groupByFlow?: boolean; } ``` ## Types and Interfaces [Section titled “Types and Interfaces”](#types-and-interfaces) ### CompilationResult [Section titled “CompilationResult”](#compilationresult) Result returned by the main compiler methods. ```typescript interface CompilationResult { success: boolean; output?: CompilerOutput; diagnostics: Diagnostic[]; metadata?: CompilationMetadata; performance?: PerformanceMetrics; } interface CompilerOutput { json: string; js?: string; mermaid?: string; d2?: string; } ``` ### ICompilationInput [Section titled “ICompilationInput”](#icompilationinput) Input to the compilation pipeline. ```typescript interface ICompilationInput { source: string; uri: string; ast?: RclFile; options?: CompilerOptions; } ``` ### ICompilationOutput [Section titled “ICompilationOutput”](#icompilationoutput) Intermediate compilation output. ```typescript interface ICompilationOutput { agent: AgentConfig; messages: Record; flows: Record; } interface AgentConfig { name: string; displayName?: string; config?: Record; defaults?: Record; } interface MessageConfig { type: MessageType; [key: string]: any; } interface FlowConfig { start: string; states: Record; } interface StateConfig { transitions?: TransitionConfig[]; actions?: ActionConfig[]; } ``` ### Diagnostic [Section titled “Diagnostic”](#diagnostic) Error and warning information. ```typescript interface Diagnostic { severity: DiagnosticSeverity; message: string; code?: string; source?: string; range?: Range; relatedInformation?: DiagnosticRelatedInformation[]; quickFixes?: QuickFix[]; } type DiagnosticSeverity = 'error' | 'warning' | 'info' | 'hint'; interface Range { start: Position; end: Position; } interface Position { line: number; character: number; } ``` ### Result\ [Section titled “Result\<T\>”](#resultt) Generic result type for error handling. ```typescript type Result = | { success: true; data: T } | { success: false; error: string; diagnostics?: Diagnostic[] }; // Utility functions function ok(data: T): Result; function err(error: string, diagnostics?: Diagnostic[]): Result; ``` ## Error Handling [Section titled “Error Handling”](#error-handling) ### CompilationError [Section titled “CompilationError”](#compilationerror) Specific error type for compilation failures. ```typescript class CompilationError extends Error { constructor( message: string, public readonly stage: string, public readonly diagnostics: Diagnostic[] = [] ) readonly name: 'CompilationError' } ``` ### Error Categories [Section titled “Error Categories”](#error-categories) ```typescript enum ErrorCategory { SYNTAX = 'syntax', SEMANTIC = 'semantic', VALIDATION = 'validation', GENERATION = 'generation', IO = 'io', INTERNAL = 'internal' } ``` ## Utilities [Section titled “Utilities”](#utilities) ### Factory Functions [Section titled “Factory Functions”](#factory-functions) ```typescript // Create compiler with presets function createStrictCompiler(): RCLCompiler; function createLenientCompiler(): RCLCompiler; function createDebugCompiler(): RCLCompiler; // Create pipeline with presets function createBasicPipeline(): CompilationPipeline; function createFullPipeline(): CompilationPipeline; function createValidationPipeline(): CompilationPipeline; ``` ### Configuration Helpers [Section titled “Configuration Helpers”](#configuration-helpers) ```typescript function mergeCompilerOptions( base: CompilerOptions, override: Partial ): CompilerOptions; function validateCompilerOptions(options: CompilerOptions): ValidationResult; function getDefaultCompilerOptions(): CompilerOptions; ``` ### Performance Monitoring [Section titled “Performance Monitoring”](#performance-monitoring) ```typescript interface PerformanceMetrics { totalTime: number; stageMetrics: Record; memoryUsage?: MemoryUsage; } interface StageMetrics { duration: number; inputSize: number; outputSize: number; cacheHit?: boolean; } function measurePerformance( operation: () => Promise, label: string ): Promise<{ result: T; metrics: PerformanceMetrics }>; ``` ## Advanced Usage [Section titled “Advanced Usage”](#advanced-usage) ### Custom Stages [Section titled “Custom Stages”](#custom-stages) ```typescript import { ICompilationStage, Result, ok, err } from '@rcs-lang/compiler'; class CustomOptimizationStage implements ICompilationStage { readonly name = 'custom-optimization'; async process(input: any): Promise> { try { // Custom optimization logic const optimized = this.optimize(input); return ok(optimized); } catch (error) { return err(`Optimization failed: ${error.message}`); } } private optimize(input: any): any { // Implementation } } // Use custom stage const pipeline = new CompilationPipeline([ new ParseStage(), new ValidateStage(), new CustomOptimizationStage(), new TransformStage(), new GenerateStage() ]); ``` ### Custom Generators [Section titled “Custom Generators”](#custom-generators) ```typescript import { IGenerator, ICompilationOutput } from '@rcs-lang/compiler'; class CustomGenerator implements IGenerator { readonly format = 'custom' as const; async generate( output: ICompilationOutput, fileName: string ): Promise { // Custom generation logic return this.createCustomOutput(output); } configure(options: any): void { // Configuration logic } private createCustomOutput(output: ICompilationOutput): string { // Implementation } } // Register custom generator const compiler = new RCLCompiler({ generation: { custom: new CustomGenerator() } }); ``` ### Plugin System [Section titled “Plugin System”](#plugin-system) ```typescript interface CompilerPlugin { name: string; install(compiler: RCLCompiler): void; uninstall?(compiler: RCLCompiler): void; } class MyPlugin implements CompilerPlugin { name = 'my-plugin'; install(compiler: RCLCompiler) { // Extend compiler functionality } } // Use plugin const compiler = new RCLCompiler(); compiler.use(new MyPlugin()); ``` # @rcs-lang/core > Core types and interfaces for RCL language infrastructure # @rcs-lang/core [Section titled “@rcs-lang/core”](#rcs-langcore) The `@rcs-lang/core` package provides the fundamental types, interfaces, and utilities that form the foundation of the RCL language infrastructure. It serves as the shared dependency for all other RCL packages, defining contracts for parsers, compilers, file systems, and other core components. ## Installation [Section titled “Installation”](#installation) ```bash bun add @rcs-lang/core ``` ## Overview [Section titled “Overview”](#overview) This package provides foundational abstractions and shared interfaces used across all RCL tools. It enables a modular and extensible architecture through well-defined contracts. ### Core Components [Section titled “Core Components”](#core-components) * **Parser Abstractions** - Generic interfaces for any parser implementation * **Compiler Pipeline** - Interfaces for compilation stages and results * **File System Abstraction** - Cross-platform file operations interface * **Result Type** - Robust error handling pattern * **Diagnostics System** - Standardized error/warning reporting * **Validation Framework** - Base classes for implementing validators * **Language Service Types** - Interfaces for IDE features ## Parser Abstraction [Section titled “Parser Abstraction”](#parser-abstraction) ```typescript import { IParser, IParserAdapter } from '@rcs-lang/core'; // Generic parser interface interface IParser { parse(source: string, fileName?: string): Promise>; } // Parser adapter for converting parser-specific ASTs interface IParserAdapter { adapt(parseTree: T): Promise>; } ``` ## Compiler Pipeline [Section titled “Compiler Pipeline”](#compiler-pipeline) ```typescript import { ICompilationStage, ICompilationInput, ICompilationResult } from '@rcs-lang/core'; // Compilation stage interface interface ICompilationStage { name: string; process(input: any): Promise>; } // Example: Custom validation stage class CustomValidator implements ICompilationStage { name = 'custom-validation'; async process(input: ICompilationInput): Promise> { // Implement custom validation logic return ok(input); } } ``` ## File System Abstraction [Section titled “File System Abstraction”](#file-system-abstraction) ```typescript import { IFileSystem } from '@rcs-lang/core'; // Cross-platform file system interface interface IFileSystem { readFile(path: string): Promise>; writeFile(path: string, content: string): Promise>; exists(path: string): Promise>; resolve(path: string): string; join(...paths: string[]): string; // ... more methods } ``` ## Result Type Pattern [Section titled “Result Type Pattern”](#result-type-pattern) The core package provides a robust Result type for error handling without exceptions: ```typescript import { Result, ok, err } from '@rcs-lang/core'; function divide(a: number, b: number): Result { if (b === 0) { return err('Division by zero'); } return ok(a / b); } // Usage const result = divide(10, 2); if (result.success) { console.log('Result:', result.value); // 5 } else { console.error('Error:', result.error); } // Chaining operations const chainedResult = result .map(x => x * 2) .flatMap(x => divide(x, 3)); ``` ## Diagnostics System [Section titled “Diagnostics System”](#diagnostics-system) Standardized diagnostic reporting across the toolchain: ```typescript import { Diagnostic, ErrorCode, ErrorCategory } from '@rcs-lang/core'; const diagnostic: Diagnostic = { severity: 'error', message: 'Missing required field', code: ErrorCode.MISSING_REQUIRED_FIELD, category: ErrorCategory.VALIDATION, range: { start: { line: 10, character: 5 }, end: { line: 10, character: 15 } }, source: 'semantic-validator' }; ``` ## Error Handling [Section titled “Error Handling”](#error-handling) Comprehensive error system with categorization and context: ```typescript import { RCLError, RCLErrorFactory } from '@rcs-lang/core'; // Create structured errors const error = RCLErrorFactory.syntaxError( 'Unexpected token', { line: 1, character: 10 }, 'Expected ":" after agent name' ); // Convert legacy errors const rclError = legacyErrorToRCLError(legacyError); ``` ## Validation Framework [Section titled “Validation Framework”](#validation-framework) Base classes for implementing validators: ```typescript import { BaseValidator, IValidationResult } from '@rcs-lang/core'; class MyValidator extends BaseValidator { name = 'my-validator'; async validate(ast: IASTNode): Promise { const diagnostics: Diagnostic[] = []; // Implement validation logic if (hasError) { diagnostics.push( this.createError('Validation failed', node, 'MY_ERROR') ); } return this.createResult(diagnostics); } } ``` ## Language Service Types [Section titled “Language Service Types”](#language-service-types) Interfaces for building language servers and IDE features: ```typescript import { ILanguageService, CompletionParams, HoverParams, DefinitionParams } from '@rcs-lang/core'; class MyLanguageService implements ILanguageService { async getCompletions(params: CompletionParams): Promise { // Implement completion logic return []; } async getHover(params: HoverParams): Promise { // Implement hover logic return null; } } ``` ## Utilities [Section titled “Utilities”](#utilities) ### Location and Range Utilities [Section titled “Location and Range Utilities”](#location-and-range-utilities) ```typescript import { Range, Position, isPositionInRange } from '@rcs-lang/core'; const range: Range = { start: { line: 5, character: 10 }, end: { line: 5, character: 20 } }; const position: Position = { line: 5, character: 15 }; if (isPositionInRange(position, range)) { console.log('Position is within range'); } ``` ### AST Utilities [Section titled “AST Utilities”](#ast-utilities) ```typescript import { walkAST, findNode } from '@rcs-lang/core'; // Walk AST with visitor pattern walkAST(ast, (node) => { if (node.type === 'AgentDefinition') { console.log('Found agent:', node.name); } }); // Find specific nodes const agentNodes = findNode(ast, (node) => node.type === 'AgentDefinition' ); ``` ## Type Guards [Section titled “Type Guards”](#type-guards) Runtime type checking utilities: ```typescript import { isCompilationInput, isValidationResult } from '@rcs-lang/core'; function processInput(input: unknown) { if (isCompilationInput(input)) { // TypeScript knows input is ICompilationInput console.log('Processing:', input.source); } } ``` ## Configuration [Section titled “Configuration”](#configuration) The core package supports configuration schemas: ```typescript import { ConfigSchema, validateConfig } from '@rcs-lang/core'; const config = { output: { format: 'json', directory: 'dist/' } }; const result = validateConfig(config, ConfigSchema); if (!result.success) { console.error('Invalid configuration:', result.errors); } ``` ## Integration with Other Packages [Section titled “Integration with Other Packages”](#integration-with-other-packages) The core package is used by: * **@rcs-lang/parser** - Implements IParser interface * **@rcs-lang/compiler** - Uses compilation pipeline interfaces * **@rcs-lang/validation** - Extends BaseValidator class * **@rcs-lang/language-service** - Implements ILanguageService * **@rcs-lang/file-system** - Implements IFileSystem interface ## API Reference [Section titled “API Reference”](#api-reference) For detailed API documentation, see the [TypeScript definitions](https://github.com/rcs-lang/rcl/tree/main/packages/core/src/index.ts). # @rcs-lang/csm > Lightweight conversation state machine for running RCS agents in production # @rcs-lang/csm [Section titled “@rcs-lang/csm”](#rcs-langcsm) A lightweight, TypeScript-first state machine library designed specifically for RCS conversational agents. CSM provides a simple, performant way to manage conversation flow state across stateless HTTP requests. ## Key Features [Section titled “Key Features”](#key-features) * 🪶 **Lightweight**: \~3KB minified, designed for serverless * 🔄 **State Persistence**: Serialize/deserialize state between requests * 🔗 **URL-Safe**: Compact state representation for URL parameters * 🎯 **Simple API**: Single callback for all state transitions * 🧩 **Composable**: Connect multiple flows into complex agents * 🌊 **Flow Invocations**: Flows can invoke other flows with result handling * 🔧 **JSON Logic Conditions**: Safe, serializable conditions with JS fallback * 📊 **Scoped Context**: Three-level context system (conversation/flow/params) * 🎚️ **Multi-Flow Machines**: Single machine definition with multiple flows * 📦 **Minimal Dependencies**: Only neverthrow and json-logic-js * 🏃 **Fast**: Optimized for request/response cycle performance ## Installation [Section titled “Installation”](#installation) * npm ```bash npm install @rcs-lang/csm ``` * pnpm ```bash pnpm add @rcs-lang/csm ``` * Yarn ```bash yarn add @rcs-lang/csm ``` * Bun ```bash bun add @rcs-lang/csm ``` ## Quick Start [Section titled “Quick Start”](#quick-start) ```typescript import { ConversationalAgent, type MachineDefinitionJSON } from '@rcs-lang/csm'; // Define your machine (usually generated from RCL) const coffeeShopMachine: MachineDefinitionJSON = { id: 'CoffeeShopBot', initialFlow: 'OrderFlow', flows: { OrderFlow: { id: 'OrderFlow', initial: 'Welcome', states: { Welcome: { transitions: [ { pattern: 'Order Coffee', target: 'ChooseSize' }, { pattern: 'View Menu', target: 'ShowMenu' } ] }, ChooseSize: { transitions: [ { pattern: 'Small', target: 'ChooseDrink', context: { size: 'small', price: 3.50 } }, { pattern: 'Medium', target: 'ChooseDrink', context: { size: 'medium', price: 4.50 } } ] } } } } }; // Create agent with state change handler const agent = new ConversationalAgent({ id: 'CoffeeBot', onStateChange: async (event) => { console.log(`Entering state: ${event.state}`); // Send message, log analytics, etc. await sendMessage(event.context.userId, messages[event.state]); } }); // Add machine (supports both single-flow and multi-flow machines) agent.addMachine(coffeeShopMachine); // Process user input const response = await agent.processInput('Order Coffee'); // response.state = 'ChooseSize' // response.machine = 'OrderFlow' // Serialize for next request const stateHash = agent.toURLHash(); // "Q29mZmVlQm90Ok9yZGVyRmxvdzpDaG9vc2VTaXplOnt9" // Restore in next request const restoredAgent = ConversationalAgent.fromURLHash(stateHash, { id: 'CoffeeBot', onStateChange: async (event) => { await sendMessage(event.context.userId, messages[event.state]); } }); ``` ## Machine Definition Schema [Section titled “Machine Definition Schema”](#machine-definition-schema) The core of the CSM package is the `MachineDefinitionJSON` interface, which defines the structure for conversational state machines. ### Basic Structure [Section titled “Basic Structure”](#basic-structure) A machine definition consists of: ```typescript interface MachineDefinitionJSON { id: string; // Unique identifier for the machine initial: string; // ID of the starting state states: Record; // Map of state definitions meta?: MachineMetadata; // Optional metadata } ``` ### State Definition [Section titled “State Definition”](#state-definition) Each state in the machine is defined by: ```typescript interface StateDefinitionJSON { transitions: TransitionJSON[]; // Array of possible transitions meta?: StateMetadata; // Optional state metadata } ``` ### Transition Definition [Section titled “Transition Definition”](#transition-definition) Transitions define how to move between states: ```typescript interface TransitionJSON { pattern?: string; // Pattern to match user input (optional for auto-transitions) target?: string; // Target reference using type:ID format (state:Name, flow:Name, @variable, :end/:cancel/:error) context?: Record; // Context updates to apply condition?: string | ConditionObject; // Condition for this transition (see Conditions section) priority?: number; // Priority for pattern matching (higher = first) flowInvocation?: { // Flow invocation with result handling flowId: string; // ID of the flow to invoke parameters?: Record; // Parameters to pass to the flow onResult: { // Handlers for different flow outcomes end?: { operations?: Array; // Operations before transitioning target: string; // Target after successful completion }; cancel?: { operations?: Array; // Operations before transitioning target: string; // Target if user cancels }; error?: { operations?: Array; // Operations before transitioning target: string; // Target if error occurs }; }; }; } // Condition types type ConditionObject = | { type: "code"; expression: string } // JavaScript code | { type: "jsonlogic"; rule: JSONLogicRule }; // JSON Logic rule ``` ### Metadata [Section titled “Metadata”](#metadata) Both machines and states can have optional metadata: ```typescript // Machine metadata interface MachineMetadata { name?: string; // Display name description?: string; // Description version?: string; // Version tags?: string[]; // Categorization tags custom?: Record; // Custom properties } // State metadata interface StateMetadata { messageId?: string; // Message to send when entering state transient?: boolean; // Auto-transition without user input tags?: string[]; // Categorization tags custom?: Record; // Custom properties } ``` ## Creating Machine Definitions [Section titled “Creating Machine Definitions”](#creating-machine-definitions) ### Simple Example [Section titled “Simple Example”](#simple-example) Here’s a basic machine definition for a greeting flow: ```json { "id": "GreetingFlow", "initial": "welcome", "states": { "welcome": { "transitions": [ { "pattern": "hello|hi|hey", "target": "greeting_response" }, { "pattern": ":default", "target": "help" } ], "meta": { "messageId": "welcome_message" } }, "greeting_response": { "transitions": [ { "target": "end" } ], "meta": { "messageId": "greeting_reply", "transient": true } }, "help": { "transitions": [ { "target": "welcome" } ], "meta": { "messageId": "help_message", "transient": true } }, "end": { "transitions": [], "meta": { "messageId": "goodbye" } } }, "meta": { "name": "Greeting Flow", "description": "Handles basic greetings and help", "version": "1.0.0", "tags": ["greeting", "basic"] } } ``` ### Advanced Example with Context [Section titled “Advanced Example with Context”](#advanced-example-with-context) ```json { "id": "UserProfileFlow", "initial": "collect_name", "states": { "collect_name": { "transitions": [ { "pattern": ".*", "target": "collect_email", "context": { "name": "$input" } } ], "meta": { "messageId": "ask_name" } }, "collect_email": { "transitions": [ { "pattern": "\\S+@\\S+\\.\\S+", "target": "confirmation", "context": { "email": "$input" } }, { "pattern": ".*", "target": "invalid_email" } ], "meta": { "messageId": "ask_email" } }, "invalid_email": { "transitions": [ { "target": "collect_email" } ], "meta": { "messageId": "invalid_email_message", "transient": true } }, "confirmation": { "transitions": [ { "pattern": "yes|confirm|ok", "target": "complete" }, { "pattern": "no|cancel", "target": "collect_name" } ], "meta": { "messageId": "confirm_details" } }, "complete": { "transitions": [], "meta": { "messageId": "profile_saved" } } } } ``` ### Reference Format and Flow Control [Section titled “Reference Format and Flow Control”](#reference-format-and-flow-control) CSM supports several target reference formats: * **State references**: `state:StateName` - Navigate to a state in the current flow * **Flow references**: `flow:FlowName` - Navigate to another flow * **Message references**: `message:MessageName` - Jump to a specific message * **Context variables**: `@variableName` - Dynamic targets from context * **Flow termination**: `:ok`, `:cancel`, `:error` - End flow with result ### Flow Invocation with Result Handling [Section titled “Flow Invocation with Result Handling”](#flow-invocation-with-result-handling) Use `flowInvocation` for complex flow control with explicit result handling: ```json { "id": "TopFlow", "initial": "Welcome", "states": { "Welcome": { "transitions": [ { "pattern": "Start Order", "flowInvocation": { "flowId": "CreateOrder", "onResult": { "ok": { "operations": [ { "append": { "to": "orders", "value": {"var": "result"} } } ], "target": "state:ConfirmAllOrders" }, "cancel": { "target": "state:Welcome" }, "error": { "target": "state:OrderError" } } } } ] } } } ``` ### Context Operations [Section titled “Context Operations”](#context-operations) Operations allow you to manipulate context data when handling flow results: * **Set**: `{"set": {"variable": "name", "value": {...}}}` * **Append**: `{"append": {"to": "arrayName", "value": {...}}}` * **Merge**: `{"merge": {"into": "objectName", "value": {...}}}` Values support JSONLogic expressions, including `{"var": "result"}` to access the flow’s return value. ### Context Variable Resolution [Section titled “Context Variable Resolution”](#context-variable-resolution) CSM supports dynamic context resolution using the `@variable` syntax: ```json { "transitions": [ { "pattern": "go", "target": "@nextState", "context": { "message": "Going to #{@nextState}" } } ] } ``` Context variables are resolved at runtime, and string interpolation supports `#{variable}` syntax for dynamic message content. ## Validation [Section titled “Validation”](#validation) Use the `validateMachineDefinition` function to validate machine definitions at runtime: ```typescript import { validateMachineDefinition, type MachineDefinitionJSON } from '@rcs-lang/csm'; const definition: MachineDefinitionJSON = { // ... your machine definition }; try { if (validateMachineDefinition(definition)) { console.log('Machine definition is valid'); } } catch (error) { console.error('Validation failed:', error.message); } ``` **Note**: Transitions must have either a `target` OR a `flowInvocation` - not both. This allows for both simple state transitions and complex flow invocations with result handling. ## Multi-Flow Machines [Section titled “Multi-Flow Machines”](#multi-flow-machines) CSM supports multi-flow machines, where a single machine definition contains multiple flows that can invoke each other: ```typescript interface MultiFlowMachineDefinitionJSON { id: string; initialFlow: string; // ID of the starting flow flows: Record; // Map of flow definitions meta?: MachineMetadata; } ``` ### Multi-Flow Example [Section titled “Multi-Flow Example”](#multi-flow-example) ```json { "id": "CoffeeShopBot", "initialFlow": "TopFlow", "flows": { "TopFlow": { "id": "TopFlow", "initial": "Welcome", "states": { "Welcome": { "transitions": [ { "pattern": "Start Order", "flowInvocation": { "flowId": "CreateOrder", "parameters": {"source": "welcome"}, "onResult": { "end": { "operations": [ {"append": {"to": "orders", "value": {"var": "result"}}} ], "target": "ConfirmAllOrders" }, "cancel": {"target": "Welcome"}, "error": {"target": "OrderError"} } } } ] } } }, "CreateOrder": { "id": "CreateOrder", "initial": "ChooseSize", "states": { "ChooseSize": { "transitions": [ {"pattern": "small", "target": "ChooseDrink", "context": {"size": "small"}}, {"pattern": "cancel", "target": ":cancel"} ] }, "ChooseDrink": { "transitions": [ {"pattern": "coffee", "target": ":end", "context": {"drink": "coffee"}} ] } } } } } ``` ## Conditions System [Section titled “Conditions System”](#conditions-system) CSM supports three types of conditions for controlling transitions: ### 1. Legacy String Conditions (Deprecated) [Section titled “1. Legacy String Conditions (Deprecated)”](#1-legacy-string-conditions-deprecated) ```typescript // Simple JavaScript expressions (generates deprecation warning) condition: "context.verified === true" condition: "context.user && context.user.age >= 18" ``` ### 2. Explicit JavaScript Code [Section titled “2. Explicit JavaScript Code”](#2-explicit-javascript-code) ```typescript // Recommended for complex JavaScript logic condition: { type: "code", expression: "context.user && context.user.points > 100 && context.user.verified" } ``` ### 3. JSON Logic (Recommended) [Section titled “3. JSON Logic (Recommended)”](#3-json-logic-recommended) ```typescript // Safe, serializable conditions using JSON Logic condition: { type: "jsonlogic", rule: { "and": [ {"==": [{"var": "user.verified"}, true]}, {">": [{"var": "user.points"}, 100]} ] } } ``` ### Condition Examples [Section titled “Condition Examples”](#condition-examples) ```json { "states": { "CheckAccess": { "transitions": [ { "pattern": "premium feature", "target": "PremiumContent", "condition": { "type": "jsonlogic", "rule": { "and": [ {"==": [{"var": "membership"}, "premium"]}, {">": [{"var": "points"}, 100]} ] } } }, { "pattern": "basic feature", "target": "BasicContent", "condition": { "type": "code", "expression": "context.membership === 'basic' || context.membership === 'premium'" } } ] } } } ``` ## Scoped Context System [Section titled “Scoped Context System”](#scoped-context-system) CSM implements a three-level context system for proper variable isolation: * **Conversation Context**: Persists across the entire agent session * **Flow Context**: Isolated per individual flow execution * **Parameters Context**: Temporary variables for current state/transition ```typescript interface ScopedContext { conversation: Record; // Persists for entire session flow: Record; // Isolated per flow params: Record; // Current state parameters } ``` This allows flows to maintain their own state while sharing conversation-level data. ## Flow Result Handling [Section titled “Flow Result Handling”](#flow-result-handling) Flows can terminate with three types of results: * **`:end`** - Successful completion with return value * **`:cancel`** - User-initiated cancellation * **`:error`** - Error condition occurred Each result type can have its own operations and target state in the parent flow. ## Pattern Matching [Section titled “Pattern Matching”](#pattern-matching) The CSM package supports several pattern types: * **Literal strings**: Match exact text * **Regular expressions**: Full regex support * **Special patterns**: * `:default` - Fallback pattern (lowest priority) * `.*` - Match any input * `$input` - Capture user input in context ## Usage with TypeScript [Section titled “Usage with TypeScript”](#usage-with-typescript) The package provides full TypeScript support: ```typescript import { type MachineDefinitionJSON, type AgentDefinitionJSON, validateMachineDefinition } from '@rcs-lang/csm'; // Type-safe machine definition const machine: MachineDefinitionJSON = { id: 'MyFlow', initial: 'start', states: { start: { transitions: [ { pattern: 'begin', target: 'processing' } ] }, processing: { transitions: [ { target: 'end' } ], meta: { transient: true } }, end: { transitions: [] } } }; // Validation with type checking if (validateMachineDefinition(machine)) { // Machine is valid and type-safe } ``` ## Real-World Example: Coffee Shop Agent [Section titled “Real-World Example: Coffee Shop Agent”](#real-world-example-coffee-shop-agent) Here’s a complete machine definition for a coffee shop ordering system with multiple flows: ```json { "id": "CoffeeShopAgent", "initial": "main_menu", "states": { "main_menu": { "transitions": [ { "pattern": "order|coffee|buy", "target": "machine:OrderFlow" }, { "pattern": "menu|options|what", "target": "show_menu" }, { "pattern": "help|support", "target": "machine:HelpFlow" }, { "pattern": ":default", "target": "welcome" } ], "meta": { "messageId": "main_menu" } }, "welcome": { "transitions": [ { "target": "main_menu" } ], "meta": { "messageId": "welcome_message", "transient": true } }, "show_menu": { "transitions": [ { "pattern": "order", "target": "machine:OrderFlow" }, { "target": "main_menu" } ], "meta": { "messageId": "menu_display", "transient": true } } }, "meta": { "name": "Coffee Shop Main Agent", "description": "Main entry point for coffee shop interactions", "version": "2.0.0" } } ``` And the OrderFlow machine: ```json { "id": "OrderFlow", "initial": "choose_size", "states": { "choose_size": { "transitions": [ { "pattern": "small|s", "target": "choose_drink", "context": { "size": "small", "price": 3.50 } }, { "pattern": "medium|m", "target": "choose_drink", "context": { "size": "medium", "price": 4.00 } }, { "pattern": "large|l", "target": "choose_drink", "context": { "size": "large", "price": 4.50 } }, { "pattern": ".*", "target": "invalid_size" } ], "meta": { "messageId": "choose_size" } }, "invalid_size": { "transitions": [ { "target": "choose_size" } ], "meta": { "messageId": "invalid_size_message", "transient": true } }, "choose_drink": { "transitions": [ { "pattern": "coffee|americano", "target": "customize", "context": { "drink": "coffee" } }, { "pattern": "latte", "target": "customize", "context": { "drink": "latte" } }, { "pattern": "cappuccino", "target": "customize", "context": { "drink": "cappuccino" } }, { "pattern": ".*", "target": "invalid_drink" } ], "meta": { "messageId": "choose_drink" } }, "invalid_drink": { "transitions": [ { "target": "choose_drink" } ], "meta": { "messageId": "invalid_drink_message", "transient": true } }, "customize": { "transitions": [ { "pattern": "regular|whole", "target": "confirm_order", "context": { "milk": "regular milk", "extraCharge": 0 } }, { "pattern": "almond|soy|oat", "target": "confirm_order", "context": { "milk": "$input milk", "extraCharge": 0.60 } }, { "pattern": "skip|no|none", "target": "confirm_order", "context": { "milk": "none", "extraCharge": 0 } }, { "pattern": ".*", "target": "invalid_milk" } ], "meta": { "messageId": "customize_message" } }, "invalid_milk": { "transitions": [ { "target": "customize" } ], "meta": { "messageId": "invalid_milk_message", "transient": true } }, "confirm_order": { "transitions": [ { "pattern": "yes|confirm|ok", "target": "place_order" }, { "pattern": "no|cancel|change", "target": "choose_size", "context": { "size": null, "drink": null, "milk": null, "price": 0, "extraCharge": 0 } } ], "meta": { "messageId": "confirm_order" } }, "place_order": { "transitions": [ { "target": "machine:CoffeeShopAgent", "context": { "orderComplete": true, "orderId": "$generateOrderId" } } ], "meta": { "messageId": "order_placed", "transient": true } } }, "meta": { "name": "Coffee Order Flow", "description": "Handles the complete coffee ordering process", "version": "1.2.0", "tags": ["ordering", "coffee", "ecommerce"] } } ``` ## Multi-Machine Agent Definition [Section titled “Multi-Machine Agent Definition”](#multi-machine-agent-definition) For complex agents with multiple flows, use `AgentDefinitionJSON`: ```json { "id": "CoffeeShopBot", "initial": "CoffeeShopAgent", "machines": { "CoffeeShopAgent": { "id": "CoffeeShopAgent", "initial": "main_menu", "states": { // ... main agent states } }, "OrderFlow": { "id": "OrderFlow", "initial": "choose_size", "states": { // ... order flow states } }, "HelpFlow": { "id": "HelpFlow", "initial": "help_menu", "states": { "help_menu": { "transitions": [ { "pattern": "hours|time", "target": "show_hours" }, { "pattern": "location|address", "target": "show_location" }, { "pattern": "back|menu", "target": "machine:CoffeeShopAgent" } ], "meta": { "messageId": "help_options" } }, "show_hours": { "transitions": [ { "target": "help_menu" } ], "meta": { "messageId": "store_hours", "transient": true } }, "show_location": { "transitions": [ { "target": "help_menu" } ], "meta": { "messageId": "store_location", "transient": true } } } } }, "meta": { "name": "Coffee Shop Bot", "description": "Complete coffee shop ordering and support system", "version": "2.0.0" } } ``` ## Usage Patterns [Section titled “Usage Patterns”](#usage-patterns) ### Serverless Function [Section titled “Serverless Function”](#serverless-function) Perfect for AWS Lambda, Vercel, Netlify Functions, or similar: ```typescript export async function handleMessage(request: Request) { const { stateHash, userInput } = await request.json(); // Restore agent state const agent = stateHash ? ConversationalAgent.fromURLHash(stateHash, { id: 'CoffeeBot', onStateChange: async (event) => { // Log state change await logAnalytics(event); // Get message for state const message = getMessageForState(event.state); // Store response to send back response.message = message; } }) : createNewAgent(); // Process input const result = await agent.processInput(userInput); // Return response with new state return Response.json({ message: response.message, stateHash: agent.toURLHash(), suggestions: getSuggestionsForState(result.state) }); } ``` ### Express.js Integration [Section titled “Express.js Integration”](#expressjs-integration) ```typescript app.post('/conversation', async (req, res) => { const agent = createOrRestoreAgent(req.body.stateHash); const result = await agent.processInput(req.body.input); res.json({ state: result, hash: agent.toURLHash() }); }); ``` ### Multi-Flow Composition [Section titled “Multi-Flow Composition”](#multi-flow-composition) ```typescript // Import reusable flows import { ContactSupportFlow } from '@rcs-lang/common-flows'; // Define custom flow const customFlow: FlowDefinition = { id: 'MainMenu', initial: 'Welcome', states: { Welcome: { transitions: [ { pattern: 'Support', target: 'machine:ContactSupport' } ] } } }; // Compose agent const agent = new ConversationalAgent({ id: 'MyBot', onStateChange }); agent.addFlow(customFlow); agent.addFlow(ContactSupportFlow); ``` ## API Reference [Section titled “API Reference”](#api-reference) The ConversationalAgent class provides the main interface: ```typescript class ConversationalAgent { constructor(options: AgentOptions); // Machine management (supports both single-flow and multi-flow machines) addMachine(machine: MachineDefinitionJSON): void; addFlow(flow: FlowDefinition): void; // Legacy support for single flows removeFlow(flowId: string): void; // State processing processInput(input: string): Promise; // Serialization toURLHash(): string; static fromURLHash(hash: string, options: AgentOptions): ConversationalAgent; // State access getCurrentState(): { machine: string; state: string }; getContext(): Context; updateContext(updates: Partial): void; setState(machineId: string, stateId: string): void; // For restoration } ``` ### Performance [Section titled “Performance”](#performance) * **Minimal Overhead**: \~1ms to process typical state transition * **Compact State**: Average URL hash \~100-200 characters * **Memory Efficient**: No persistence between requests * **Fast Serialization**: Optimized JSON encoding * **Pattern Caching**: Compiled patterns cached per flow For detailed API documentation, see the CSM package README and source code. # CSM API Reference > API documentation for Conversational State Machine # CSM API Reference [Section titled “CSM API Reference”](#csm-api-reference) ## Overview [Section titled “Overview”](#overview) The `@rcs-lang/csm` package provides a lightweight conversation state machine for RCS agents. This is the core runtime that executes RCL-compiled conversation flows with support for multi-flow machines, flow invocations, JSON Logic conditions, and scoped context management. ## Core Classes [Section titled “Core Classes”](#core-classes) ### ConversationalAgent [Section titled “ConversationalAgent”](#conversationalagent) Main class for running conversation flows. ```typescript class ConversationalAgent { constructor(options: AgentOptions) // Machine/Flow management (supports both single-flow and multi-flow machines) addMachine(machine: MachineDefinitionJSON): void addFlow(flow: FlowDefinition): void // Legacy support removeFlow(flowId: string): void // State management getCurrentState(): { machine: string; state: string } setState(machineId: string, stateId: string): void // For restoration // Message processing processInput(input: string): Promise // Context management getContext(): Context updateContext(updates: Partial): void // Serialization toURLHash(): string static fromURLHash(hash: string, options: AgentOptions): ConversationalAgent } ``` ### FlowMachine [Section titled “FlowMachine”](#flowmachine) Executes individual conversation flows. ```typescript class FlowMachine { constructor(flow: FlowDefinition, context?: Context) // State transitions transition(event: Event): Promise getCurrentState(): string // Context management getContext(): Context updateContext(updates: Partial): void // Flow control start(): Promise stop(): void reset(): void } ``` ## Key Interfaces [Section titled “Key Interfaces”](#key-interfaces) ### MachineDefinitionJSON [Section titled “MachineDefinitionJSON”](#machinedefinitionjson) Supports both single-flow and multi-flow machines: ```typescript type MachineDefinitionJSON = SingleFlowMachineDefinitionJSON | MultiFlowMachineDefinitionJSON; interface SingleFlowMachineDefinitionJSON { id: string; initial: string; states: Record; meta?: MachineMetadata; } interface MultiFlowMachineDefinitionJSON { id: string; initialFlow: string; flows: Record; meta?: MachineMetadata; } ``` ### StateDefinitionJSON [Section titled “StateDefinitionJSON”](#statedefinitionjson) ```typescript interface StateDefinitionJSON { transitions: TransitionJSON[]; meta?: StateMetadata; } ``` ### TransitionJSON [Section titled “TransitionJSON”](#transitionjson) ```typescript interface TransitionJSON { pattern?: string; // Pattern to match user input target?: string; // Target state/flow reference context?: Record; // Context updates condition?: string | ConditionObject; // Transition condition priority?: number; // Pattern matching priority flowInvocation?: FlowInvocationDefinition; // Flow invocation config } type ConditionObject = | { type: "code"; expression: string } | { type: "jsonlogic"; rule: JSONLogicRule }; ``` ### FlowInvocationDefinition [Section titled “FlowInvocationDefinition”](#flowinvocationdefinition) ```typescript interface FlowInvocationDefinition { flowId: string; // ID of flow to invoke parameters?: Record; // Parameters to pass onResult: { // Result handlers end?: ResultHandler; cancel?: ResultHandler; error?: ResultHandler; }; } interface ResultHandler { operations?: ContextOperation[]; // Context operations target: string; // Target state } interface ContextOperation { set?: { variable: string; value: any }; append?: { to: string; value: any }; merge?: { into: string; value: any }; } ``` ### ScopedContext [Section titled “ScopedContext”](#scopedcontext) ```typescript interface ScopedContext { conversation: Record; // Session-wide context flow: Record; // Flow-scoped context params: Record; // Parameter context } ``` ### ProcessResult [Section titled “ProcessResult”](#processresult) ```typescript interface ProcessResult { state: string; // Current state ID machine: string; // Current machine/flow ID transitioned: boolean; // Whether transition occurred transition?: Transition; // The transition taken context: Context; // Updated context } ``` ## Usage Examples [Section titled “Usage Examples”](#usage-examples) ### Basic Agent Setup [Section titled “Basic Agent Setup”](#basic-agent-setup) ```typescript import { ConversationalAgent, type MachineDefinitionJSON } from '@rcs-lang/csm'; // Multi-flow machine definition const coffeeShopMachine: MachineDefinitionJSON = { id: 'CoffeeShopBot', initialFlow: 'MainFlow', flows: { MainFlow: { id: 'MainFlow', initial: 'Welcome', states: { Welcome: { transitions: [ { pattern: 'order coffee', flowInvocation: { flowId: 'OrderFlow', onResult: { end: { target: 'OrderComplete' }, cancel: { target: 'Welcome' } } } } ] } } }, OrderFlow: { id: 'OrderFlow', initial: 'ChooseSize', states: { ChooseSize: { transitions: [ { pattern: 'small', target: ':end', context: { size: 'small' } } ] } } } } }; const agent = new ConversationalAgent({ id: 'coffee-bot', onStateChange: async (event) => { console.log(`State: ${event.state} in ${event.machine}`); await sendMessage(getMessageForState(event.state)); } }); // Add machine (supports both single-flow and multi-flow) agent.addMachine(coffeeShopMachine); // Process user input const response = await agent.processInput('order coffee'); ``` ### JSON Logic Conditions [Section titled “JSON Logic Conditions”](#json-logic-conditions) ```typescript const machineWithConditions: MachineDefinitionJSON = { id: 'ConditionalBot', initial: 'CheckAccess', states: { CheckAccess: { transitions: [ { pattern: 'premium feature', target: 'PremiumContent', condition: { type: 'jsonlogic', rule: { 'and': [ { '==': [{ 'var': 'membership' }, 'premium'] }, { '>': [{ 'var': 'points' }, 100] } ] } } }, { pattern: 'basic feature', target: 'BasicContent', condition: { type: 'code', expression: 'context.membership !== "guest"' } } ] } } }; ``` ### Context Operations [Section titled “Context Operations”](#context-operations) ```typescript // Flow invocation with context operations { "flowInvocation": { "flowId": "CreateOrder", "parameters": { "source": "menu" }, "onResult": { "end": { "operations": [ { "append": { "to": "orders", "value": { "var": "result" } } }, { "set": { "variable": "lastOrderTime", "value": { "var": "now" } } } ], "target": "OrderHistory" } } } } ``` See the main README for more detailed examples. # @rcs-lang/file-system > File system abstraction for RCL tooling # @rcs-lang/file-system [Section titled “@rcs-lang/file-system”](#rcs-langfile-system) The `@rcs-lang/file-system` package provides a unified file system abstraction layer for all RCL tooling. It enables consistent file operations across different environments (Node.js, browser, virtual file systems) and platforms. ## Installation [Section titled “Installation”](#installation) ```bash bun add @rcs-lang/file-system ``` ## Overview [Section titled “Overview”](#overview) This package offers: * **Cross-platform file operations** - Works on Windows, macOS, and Linux * **Virtual file system support** - For in-memory operations and testing * **Async and sync APIs** - Choose based on your needs * **Path normalization** - Handles path differences across platforms * **File watching** - Monitor RCL files for changes * **Encoding support** - UTF-8, UTF-16, and other encodings ## Features [Section titled “Features”](#features) ### File System Abstraction [Section titled “File System Abstraction”](#file-system-abstraction) ```typescript import { FileSystem, createFileSystem } from '@rcs-lang/file-system'; // Create platform-specific file system const fs = createFileSystem(); // Read RCL file const content = await fs.readFile('/path/to/agent.rcl', 'utf8'); // Write compiled output await fs.writeFile('/path/to/output.json', JSON.stringify(compiled)); // Check if file exists if (await fs.exists('/path/to/config.rcl')) { // Process configuration } ``` ### Virtual File System [Section titled “Virtual File System”](#virtual-file-system) Perfect for testing and browser environments: ```typescript import { createVirtualFileSystem } from '@rcs-lang/file-system'; const vfs = createVirtualFileSystem({ '/src/agent.rcl': 'agent CustomerSupport { ... }', '/src/messages.rcl': 'messages Messages { ... }' }); // Use like regular file system const files = await vfs.readdir('/src'); console.log(files); // ['agent.rcl', 'messages.rcl'] ``` ### File Watching [Section titled “File Watching”](#file-watching) Monitor RCL files for changes: ```typescript import { watchFiles } from '@rcs-lang/file-system'; const watcher = watchFiles('**/*.rcl', { onChange: (path, eventType) => { console.log(`File ${path} was ${eventType}`); // Recompile on change }, ignorePatterns: ['**/node_modules/**', '**/dist/**'] }); // Stop watching watcher.close(); ``` ### Path Utilities [Section titled “Path Utilities”](#path-utilities) ```typescript import { normalizePath, joinPath, relativePath, isAbsolute, getExtension } from '@rcs-lang/file-system'; // Normalize paths across platforms const normalized = normalizePath('src\\agents\\customer.rcl'); // Result: 'src/agents/customer.rcl' // Join path segments safely const fullPath = joinPath(projectRoot, 'src', 'agents', 'customer.rcl'); // Get relative paths const rel = relativePath('/project/src', '/project/src/agents/customer.rcl'); // Result: 'agents/customer.rcl' ``` ### Workspace Discovery [Section titled “Workspace Discovery”](#workspace-discovery) Find RCL files in a workspace: ```typescript import { findRCLFiles, WorkspaceScanner } from '@rcs-lang/file-system'; // Find all RCL files const files = await findRCLFiles('/path/to/project', { recursive: true, includePatterns: ['**/*.rcl'], excludePatterns: ['**/test/**'] }); // Advanced workspace scanning const scanner = new WorkspaceScanner({ rootPath: '/path/to/project', fileTypes: ['.rcl', '.rcl.json'] }); const workspace = await scanner.scan(); console.log(workspace.files); // All RCL-related files console.log(workspace.dependencies); // File dependencies ``` ## Integration [Section titled “Integration”](#integration) The file system package is used by: * **@rcs-lang/cli** - Reading source files and writing output * **@rcs-lang/compiler** - File I/O operations * **@rcs-lang/language-service** - Workspace file management * **VSCode Extension** - File operations in the editor ## Configuration [Section titled “Configuration”](#configuration) ```typescript interface FileSystemConfig { // Default encoding for text files encoding?: BufferEncoding; // Enable file caching cache?: boolean; // Maximum file size to read (in bytes) maxFileSize?: number; // Follow symbolic links followSymlinks?: boolean; } const fs = createFileSystem({ encoding: 'utf8', cache: true, maxFileSize: 10 * 1024 * 1024, // 10MB followSymlinks: true }); ``` ## Error Handling [Section titled “Error Handling”](#error-handling) ```typescript import { FileSystemError, isFileSystemError } from '@rcs-lang/file-system'; try { await fs.readFile('/path/to/file.rcl'); } catch (error) { if (isFileSystemError(error)) { switch (error.code) { case 'ENOENT': console.error('File not found'); break; case 'EACCES': console.error('Permission denied'); break; default: console.error(`File system error: ${error.message}`); } } } ``` ## API Reference [Section titled “API Reference”](#api-reference) ### Main Interfaces [Section titled “Main Interfaces”](#main-interfaces) * `FileSystem` - Core file system interface * `VirtualFileSystem` - In-memory file system * `FileWatcher` - File watching interface * `WorkspaceScanner` - Workspace analysis ### Factory Functions [Section titled “Factory Functions”](#factory-functions) * `createFileSystem(config?)` - Create platform file system * `createVirtualFileSystem(files?)` - Create virtual file system * `watchFiles(pattern, options)` - Start watching files ### Path Utilities [Section titled “Path Utilities”](#path-utilities-1) * `normalizePath(path)` - Normalize path separators * `joinPath(...segments)` - Join path segments * `relativePath(from, to)` - Get relative path * `isAbsolute(path)` - Check if path is absolute * `getExtension(path)` - Get file extension # @rcs-lang/language-service > Advanced language service providers for RCL # @rcs-lang/language-service [Section titled “@rcs-lang/language-service”](#rcs-langlanguage-service) Advanced language service implementation for RCL (Rich Communication Language) providing IDE features like code completion, diagnostics, hover information, and more. Powers the RCL VSCode extension and can be integrated into other editors. ## Installation [Section titled “Installation”](#installation) ```bash bun add @rcs-lang/language-service ``` ## Features [Section titled “Features”](#features) * 🔍 **Go to Definition** - Navigate to symbol definitions across files * 📝 **Code Completion** - Context-aware suggestions for agents, flows, messages * 🔎 **Find References** - Locate all usages of symbols * 💡 **Hover Information** - Rich tooltips with documentation and type info * ⚠️ **Diagnostics** - Real-time error and warning detection * 🔄 **Rename** - Safe symbol renaming across entire workspace * 📑 **Document Symbols** - Outline view support for navigation * 🎨 **Semantic Highlighting** - Enhanced syntax coloring based on semantics ## Quick Start [Section titled “Quick Start”](#quick-start) ```typescript import { LanguageService } from '@rcs-lang/language-service'; const service = new LanguageService(); // Initialize with workspace await service.initialize({ workspaceFolders: ['/path/to/workspace'] }); // Get completions const completions = await service.getCompletions({ uri: 'file:///example.rcl', position: { line: 10, character: 15 } }); // Get diagnostics const diagnostics = await service.getDiagnostics('file:///example.rcl'); // Go to definition const definition = await service.getDefinition({ uri: 'file:///example.rcl', position: { line: 5, character: 10 } }); ``` ## Architecture [Section titled “Architecture”](#architecture) The language service is built on several key components working together: ### RclProgram [Section titled “RclProgram”](#rclprogram) Central coordinator that manages the compilation state and provides unified access to language features: ```typescript import { RclProgram } from '@rcs-lang/language-service'; const program = new RclProgram({ workspaceFolder: '/path/to/workspace', fileSystem: fileSystemInstance }); // Add files to program await program.addFile('file:///agent.rcl'); // Get parsed file const file = program.getFile('file:///agent.rcl'); // Get all symbols in workspace const symbols = program.getSymbols(); ``` ### WorkspaceIndex [Section titled “WorkspaceIndex”](#workspaceindex) Maintains an index of all symbols across the workspace for fast lookups and cross-file references: ```typescript import { WorkspaceIndex } from '@rcs-lang/language-service'; const index = new WorkspaceIndex(); // Index files await index.indexFile('file:///agent.rcl', ast); // Find symbol definitions const definitions = index.findDefinitions('AgentName'); // Find all references const references = index.findReferences('MessageName'); // Get symbols in file const fileSymbols = index.getSymbolsInFile('file:///agent.rcl'); ``` ## Language Providers [Section titled “Language Providers”](#language-providers) Modular providers implement specific language features: ### CompletionProvider [Section titled “CompletionProvider”](#completionprovider) Provides context-aware code completion: ```typescript import { CompletionProvider } from '@rcs-lang/language-service'; const provider = new CompletionProvider(program); const completions = await provider.getCompletions({ uri: 'file:///example.rcl', position: { line: 10, character: 15 } }); // Returns different completions based on context: // - Agent section: flow names, config options // - Flow section: state names, transition patterns // - Message section: message types, RCS features // - Match block: pattern suggestions ``` ### DefinitionProvider [Section titled “DefinitionProvider”](#definitionprovider) Implements go-to-definition functionality: ```typescript import { DefinitionProvider } from '@rcs-lang/language-service'; const provider = new DefinitionProvider(program); const definition = await provider.getDefinition({ uri: 'file:///example.rcl', position: { line: 5, character: 10 } }); // Returns definition location for: // - Agent references // - Flow references // - Message references // - State references // - Variable references ``` ### HoverProvider [Section titled “HoverProvider”](#hoverprovider) Provides rich tooltip information: ```typescript import { HoverProvider } from '@rcs-lang/language-service'; const provider = new HoverProvider(program); const hover = await provider.getHover({ uri: 'file:///example.rcl', position: { line: 8, character: 12 } }); // Returns hover info with: // - Symbol documentation // - Type information // - Usage examples // - Quick actions ``` ### ReferencesProvider [Section titled “ReferencesProvider”](#referencesprovider) Finds all references to a symbol: ```typescript import { ReferencesProvider } from '@rcs-lang/language-service'; const provider = new ReferencesProvider(program); const references = await provider.getReferences({ uri: 'file:///example.rcl', position: { line: 5, character: 10 }, includeDeclaration: true }); // Returns all locations where symbol is used ``` ### RenameProvider [Section titled “RenameProvider”](#renameprovider) Safe symbol renaming across workspace: ```typescript import { RenameProvider } from '@rcs-lang/language-service'; const provider = new RenameProvider(program); // Check if rename is valid const prepareResult = await provider.prepareRename({ uri: 'file:///example.rcl', position: { line: 5, character: 10 } }); // Perform rename const workspaceEdit = await provider.rename({ uri: 'file:///example.rcl', position: { line: 5, character: 10 }, newName: 'NewAgentName' }); // Returns workspace edit with all necessary changes ``` ## Validators [Section titled “Validators”](#validators) Built-in validators provide real-time diagnostics: ### SemanticValidator [Section titled “SemanticValidator”](#semanticvalidator) Validates semantic correctness: ```typescript import { SemanticValidator } from '@rcs-lang/language-service'; const validator = new SemanticValidator(program); const diagnostics = await validator.validate('file:///example.rcl'); // Checks for: // - Undefined message references // - Unreachable flow states // - Type mismatches // - Circular dependencies // - Unused symbols ``` ### ImportResolver [Section titled “ImportResolver”](#importresolver) Validates imports and module resolution: ```typescript import { ImportResolver } from '@rcs-lang/language-service'; const resolver = new ImportResolver(program); // Resolve import path const resolved = await resolver.resolve('shared/common', 'file:///agent.rcl'); // Validate all imports in file const diagnostics = await resolver.validateImports('file:///agent.rcl'); ``` ## Language Server Protocol Integration [Section titled “Language Server Protocol Integration”](#language-server-protocol-integration) ### VSCode Extension [Section titled “VSCode Extension”](#vscode-extension) ```typescript import { createConnection, TextDocuments, ProposedFeatures } from 'vscode-languageserver/node'; import { LanguageService } from '@rcs-lang/language-service'; const connection = createConnection(ProposedFeatures.all); const documents = new TextDocuments(TextDocument); const service = new LanguageService(); // Initialize connection.onInitialize(async (params) => { await service.initialize(params); return { capabilities: { completionProvider: { triggerCharacters: ['.', '@', ':'] }, definitionProvider: true, hoverProvider: true, referencesProvider: true, renameProvider: true, diagnosticProvider: true } }; }); // Handle LSP requests connection.onCompletion(async (params) => { return service.getCompletions(params); }); connection.onDefinition(async (params) => { return service.getDefinition(params); }); ``` ## Configuration [Section titled “Configuration”](#configuration) ### Language Service Config [Section titled “Language Service Config”](#language-service-config) ```typescript interface LanguageServiceConfig { // Enable/disable specific features features?: { completion?: boolean; hover?: boolean; definition?: boolean; references?: boolean; rename?: boolean; diagnostics?: boolean; semanticHighlighting?: boolean; }; // Validation settings validation?: { syntaxErrors?: boolean; semanticErrors?: boolean; styleWarnings?: boolean; unusedSymbols?: boolean; }; // Performance tuning indexing?: { maxFileSize?: number; excludePatterns?: string[]; debounceMs?: number; }; } ``` ## Documentation [Section titled “Documentation”](#documentation) * [API Reference](/packages/language-service/language-service-api-reference) # Language Service API Reference > API documentation for IDE integration features # Language Service API Reference [Section titled “Language Service API Reference”](#language-service-api-reference) ## Overview [Section titled “Overview”](#overview) The `@rcs-lang/language-service` package provides advanced IDE features for RCL through the Language Server Protocol. ## Core Classes [Section titled “Core Classes”](#core-classes) ### LanguageService [Section titled “LanguageService”](#languageservice) Main service class providing all language features. ```typescript class LanguageService { constructor(options?: LanguageServiceOptions) // Initialization initialize(params: InitializeParams): Promise // Core features getCompletions(params: CompletionParams): Promise getHover(params: HoverParams): Promise getDefinition(params: DefinitionParams): Promise getReferences(params: ReferenceParams): Promise // Document management updateDocument(uri: string, content: string): Promise closeDocument(uri: string): void // Diagnostics getDiagnostics(uri: string): Promise // Advanced features rename(params: RenameParams): Promise getDocumentSymbols(uri: string): Promise getSemanticTokens(uri: string): Promise } ``` ## Provider Classes [Section titled “Provider Classes”](#provider-classes) ### CompletionProvider [Section titled “CompletionProvider”](#completionprovider) Provides context-aware code completion. ```typescript class CompletionProvider { getCompletions( document: TextDocument, position: Position, context?: CompletionContext ): Promise } ``` ### DefinitionProvider [Section titled “DefinitionProvider”](#definitionprovider) Enables "Go to Definition" functionality. ```typescript class DefinitionProvider { getDefinition( document: TextDocument, position: Position ): Promise } ``` ### HoverProvider [Section titled “HoverProvider”](#hoverprovider) Provides rich hover information. ```typescript class HoverProvider { getHover( document: TextDocument, position: Position ): Promise } ``` ## Integration Example [Section titled “Integration Example”](#integration-example) ```typescript import { LanguageService } from '@rcs-lang/language-service'; const service = new LanguageService(); // Initialize with workspace await service.initialize({ workspaceFolders: ['/path/to/workspace'] }); // Get completions const completions = await service.getCompletions({ uri: 'file:///example.rcl', position: { line: 10, character: 15 } }); // Get diagnostics const diagnostics = await service.getDiagnostics('file:///example.rcl'); ``` See the main README for detailed usage examples and integration patterns. # @rcs-lang/parser > ANTLR4-based grammar and parser for RCL # @rcs-lang/parser [Section titled “@rcs-lang/parser”](#rcs-langparser) ANTLR4-based grammar and parser for RCL (Rich Communication Language) that converts source code into Abstract Syntax Trees for further processing. ## Installation [Section titled “Installation”](#installation) ```bash bun add @rcs-lang/parser ``` ## Overview [Section titled “Overview”](#overview) This package provides the primary parser for RCL, built on ANTLR4 with support for: * **Python-like indentation** - Significant whitespace handling * **Context-aware parsing** - Proper scope and section handling * **Error recovery** - Graceful handling of syntax errors * **Position tracking** - Source locations for diagnostics * **Symbol extraction** - Identifier and reference extraction ## Quick Start [Section titled “Quick Start”](#quick-start) ```typescript import { AntlrRclParser } from '@rcs-lang/parser'; const parser = new AntlrRclParser(); // Initialize parser (required for ANTLR) await parser.initialize(); // Parse RCL source code const result = await parser.parse(` agent CoffeeShop displayName: "Coffee Shop Agent" flow OrderFlow start: Welcome on Welcome match @userInput "order coffee" -> ChooseSize "view menu" -> ShowMenu messages Messages text Welcome "Hello! How can I help you today?" `); if (result.success) { console.log('AST:', result.value.ast); console.log('Symbols:', result.value.symbols); } else { console.error('Parse error:', result.error); } ``` ## Grammar Structure [Section titled “Grammar Structure”](#grammar-structure) The RCL parser is built from two ANTLR4 grammar files: ### Lexer Grammar (`RclLexer.g4`) [Section titled “Lexer Grammar (RclLexer.g4)”](#lexer-grammar-rcllexerg4) Defines tokenization rules for: * **Keywords** - `agent`, `flow`, `messages`, `match`, etc. * **Literals** - strings, numbers, booleans, atoms * **Identifiers** - names and variables * **Operators** - `->`, `:`, `...`, etc. * **Indentation** - Python-like INDENT/DEDENT tokens ### Parser Grammar (`RclParser.g4`) [Section titled “Parser Grammar (RclParser.g4)”](#parser-grammar-rclparserg4) Defines syntax rules for: * **Document structure** - imports, sections, attributes * **Agent definitions** - configuration and flows * **Flow definitions** - states and transitions * **Message definitions** - text, rich cards, carousels * **Value expressions** - literals, variables, collections ## Python-like Indentation [Section titled “Python-like Indentation”](#python-like-indentation) The parser handles significant whitespace through a custom lexer base class: ```typescript // RclLexerBase.ts provides indentation handling class RclLexerBase extends Lexer { // Generates INDENT/DEDENT tokens based on indentation levels // Maintains an indentation stack for proper nesting // Handles mixed tabs/spaces with error reporting } ``` Example indentation handling: ```rcl agent MyAgent # Level 0 displayName: "..." # Level 1 - INDENT flow Main # Level 1 start: Welcome # Level 2 - INDENT on Welcome # Level 2 -> End # Level 3 - INDENT # Level 0 - DEDENT DEDENT DEDENT ``` ## Parser API [Section titled “Parser API”](#parser-api) ### AntlrRclParser [Section titled “AntlrRclParser”](#antlrrclparser) Main parser class implementing the `IParser` interface: ```typescript class AntlrRclParser implements IParser { // Initialize parser (required for ANTLR setup) async initialize(): Promise; // Parse source code into AST async parse(source: string, fileName?: string): Promise>; // Check if parser is initialized isInitialized(): boolean; } interface ParseResult { ast: RclFile; // Root AST node symbols: SymbolTable; // Extracted symbols parseTree?: any; // Raw ANTLR parse tree (debug) } ``` ### Symbol Extraction [Section titled “Symbol Extraction”](#symbol-extraction) The parser extracts symbols during parsing for language service features: ```typescript interface SymbolTable { agents: AgentSymbol[]; flows: FlowSymbol[]; messages: MessageSymbol[]; states: StateSymbol[]; variables: VariableSymbol[]; } interface AgentSymbol { name: string; displayName?: string; range: Range; flows: string[]; } ``` ## Error Handling [Section titled “Error Handling”](#error-handling) The parser provides detailed error information: ```typescript // Parse errors include location information const result = await parser.parse(invalidSource); if (!result.success) { const error = result.error; console.log(`Error at line ${error.line}, column ${error.column}`); console.log(`Message: ${error.message}`); console.log(`Context: ${error.context}`); } ``` Common error types: * **Syntax errors** - Invalid tokens or grammar violations * **Indentation errors** - Inconsistent or invalid indentation * **Context errors** - Invalid section nesting or structure ## Integration with Compilation Pipeline [Section titled “Integration with Compilation Pipeline”](#integration-with-compilation-pipeline) The parser integrates seamlessly with the compilation pipeline: ```typescript import { RCLCompiler } from '@rcs-lang/compiler'; import { AntlrRclParser } from '@rcs-lang/parser'; const compiler = new RCLCompiler({ parser: new AntlrRclParser() }); const result = await compiler.compile(source); ``` ## Build Requirements [Section titled “Build Requirements”](#build-requirements) The parser requires Java to generate TypeScript files from ANTLR grammar: ### Prerequisites [Section titled “Prerequisites”](#prerequisites) * **Java 17 or later** must be installed * Run `./install-java.sh` for installation instructions ### Build Process [Section titled “Build Process”](#build-process) ```bash # Install dependencies bun install # Generate parser and build TypeScript bun run build ``` This process: 1. Generates TypeScript parser files from ANTLR grammar 2. Fixes import paths in generated files 3. Compiles TypeScript to JavaScript ### Generated Files [Section titled “Generated Files”](#generated-files) The `src/generated/` directory contains ANTLR-generated files: * `RclLexer.ts` - Tokenizer implementation * `RclParser.ts` - Parser implementation * `RclParserListener.ts` - Parse tree listener interface * `RclParserVisitor.ts` - Parse tree visitor interface ⚠️ **Do not edit generated files manually** - they will be overwritten on rebuild. ## Development [Section titled “Development”](#development) ### Testing Grammar Changes [Section titled “Testing Grammar Changes”](#testing-grammar-changes) ```bash # Test the parser bun test # Trace token generation node trace-tokens.js input.rcl # Trace grammar rules node trace-comment.js input.rcl ``` ### Grammar Debugging [Section titled “Grammar Debugging”](#grammar-debugging) Use ANTLR tools for grammar development: ```bash # Visualize parse tree (requires ANTLRWorks) antlr4-parse RclParser rclFile -gui input.rcl # Generate parse tree text antlr4-parse RclParser rclFile -tree input.rcl ``` ## Performance Considerations [Section titled “Performance Considerations”](#performance-considerations) * **Initialization cost** - Call `initialize()` once per parser instance * **Memory usage** - Parser instances hold ANTLR runtime state * **Parse speed** - \~1000 lines/second for typical RCL files * **Error recovery** - Performance degrades with many syntax errors ## Documentation [Section titled “Documentation”](#documentation) * [API Reference](/packages/parser/parser-api-reference) # Parser API Reference > API documentation for ANTLR4-based RCL parser # Parser API Reference [Section titled “Parser API Reference”](#parser-api-reference) ## Overview [Section titled “Overview”](#overview) The `@rcs-lang/parser` package provides a high-performance ANTLR4-based parser for RCL with TypeScript AST generation. ## Core Classes [Section titled “Core Classes”](#core-classes) ### RCLParser [Section titled “RCLParser”](#rclparser) Main parser class for converting RCL source to AST. ```typescript class RCLParser { constructor(options?: ParsingOptions) // Parsing methods parse(source: string, fileName?: string): Promise parseFile(filePath: string): Promise parseIncremental( source: string, fileName: string, changes: TextChange[] ): Promise // Configuration setOptions(options: Partial): void getOptions(): ParsingOptions // Cache management clearCache(): void dispose(): void } ``` ## Key Interfaces [Section titled “Key Interfaces”](#key-interfaces) ### ParsingOptions [Section titled “ParsingOptions”](#parsingoptions) ```typescript interface ParsingOptions { // Error handling maxErrors?: number continueOnError?: boolean // Performance enableCaching?: boolean incrementalMode?: boolean // Features includeComments?: boolean preserveWhitespace?: boolean // Validation strictMode?: boolean allowExperimentalFeatures?: boolean } ``` ### ParseResult [Section titled “ParseResult”](#parseresult) ```typescript interface ParseResult { success: boolean data?: RclFile diagnostics: Diagnostic[] sourceMap?: SourceMap performance?: ParseMetrics } ``` ## Visitor Pattern [Section titled “Visitor Pattern”](#visitor-pattern) ```typescript import { RCLBaseVisitor } from '@rcs-lang/parser'; class CustomVisitor extends RCLBaseVisitor { visitFlowDefinition(ctx: FlowDefinitionContext): void { console.log('Found flow:', ctx.IDENTIFIER().getText()); this.visitChildren(ctx); } } // Usage const visitor = new CustomVisitor(); visitor.visit(parseTree); ``` ## Listener Pattern [Section titled “Listener Pattern”](#listener-pattern) ```typescript import { RCLBaseListener, ParseTreeWalker } from '@rcs-lang/parser'; class CustomListener extends RCLBaseListener { enterMessageDefinition(ctx: MessageDefinitionContext): void { console.log('Entering message:', ctx.IDENTIFIER().getText()); } } // Usage const listener = new CustomListener(); const walker = new ParseTreeWalker(); walker.walk(listener, parseTree); ``` ## Usage Examples [Section titled “Usage Examples”](#usage-examples) ### Basic Parsing [Section titled “Basic Parsing”](#basic-parsing) ```typescript import { RCLParser } from '@rcs-lang/parser'; const parser = new RCLParser(); const result = await parser.parse(rclSource, 'example.rcl'); if (result.success) { const ast = result.data; console.log('Agent:', ast.agent.name); } else { result.diagnostics.forEach(diagnostic => { console.error(`Error: ${diagnostic.message}`); }); } ``` ### Incremental Parsing [Section titled “Incremental Parsing”](#incremental-parsing) ```typescript const parser = new RCLParser({ incrementalMode: true }); // Initial parse const result1 = await parser.parse(source, 'file.rcl'); // Update with changes const result2 = await parser.parseIncremental( updatedSource, 'file.rcl', textChanges ); ``` See the main README for comprehensive examples and build requirements. # @rcs-lang/types > TypeScript type definitions for RCS Business Messaging (RBM) based on Google's official API reference # @rcs-lang/types [Section titled “@rcs-lang/types”](#rcs-langtypes) The `@rcs-lang/types` package provides comprehensive TypeScript type definitions for working with RCS Business Messaging APIs. All types are based on the official Google RBM API reference documentation. ## Installation [Section titled “Installation”](#installation) * npm ```bash npm install @rcs-lang/types ``` * pnpm ```bash pnpm add @rcs-lang/types ``` * Yarn ```bash yarn add @rcs-lang/types ``` * Bun ```bash bun add @rcs-lang/types ``` ## Overview [Section titled “Overview”](#overview) This package provides comprehensive TypeScript types for working with RCS Business Messaging APIs. All types are based on the official Google RBM API reference documentation. ### Key Features [Section titled “Key Features”](#key-features) * 🎯 **Complete Type Coverage** - All RBM API types including agents, messages, brands, testers, events, files, and integrations * 📘 **Fully Documented** - Extensive TSDoc comments with links to official documentation * 🔒 **Type Safety** - Branded types for enhanced type safety (PhoneNumber, EmailAddress, etc.) * 🚀 **Zero Runtime** - Pure TypeScript types with no runtime overhead * ✅ **Official Spec** - Based directly on Google’s RBM API reference ## Basic Usage [Section titled “Basic Usage”](#basic-usage) ### Importing Types [Section titled “Importing Types”](#importing-types) ```typescript import type { AgentMessage, RcsBusinessMessagingAgent, Brand, Tester, AgentEvent, } from '@rcs-lang/types'; ``` ### Creating Messages [Section titled “Creating Messages”](#creating-messages) The package provides types for all RCS message types: ```typescript import type { AgentMessage, AgentContentMessage, Suggestion } from '@rcs-lang/types'; // Create a text message with suggestions const message: AgentMessage = { contentMessage: { text: 'Hello! How can I help you today?', suggestions: [ { reply: { text: 'Check order status', postbackData: 'CHECK_ORDER_STATUS', }, }, { action: { text: 'Call support', postbackData: 'CALL_SUPPORT', dialAction: { phoneNumber: '+1234567890', }, }, }, ], }, messageTrafficType: 'TRANSACTION', }; ``` ## Working with Rich Cards [Section titled “Working with Rich Cards”](#working-with-rich-cards) ### Standalone Cards [Section titled “Standalone Cards”](#standalone-cards) ```typescript import type { RichCard, StandaloneCard } from '@rcs-lang/types'; const standaloneCard: RichCard = { standaloneCard: { cardOrientation: 'VERTICAL', cardContent: { title: 'Product Name', description: 'Product description here', media: { height: 'MEDIUM', contentInfo: { fileUrl: 'https://example.com/image.jpg', }, }, suggestions: [ { reply: { text: 'Buy now', postbackData: 'BUY_PRODUCT_123', }, }, ], }, }, }; ``` ### Carousel Cards [Section titled “Carousel Cards”](#carousel-cards) ```typescript import type { RichCard, CarouselCard } from '@rcs-lang/types'; const carousel: RichCard = { carouselCard: { cardWidth: 'MEDIUM', cardContents: [ { title: 'Product 1', description: 'Description 1', media: { height: 'MEDIUM', contentInfo: { fileUrl: 'https://example.com/product1.jpg', }, }, }, { title: 'Product 2', description: 'Description 2', media: { height: 'MEDIUM', contentInfo: { fileUrl: 'https://example.com/product2.jpg', }, }, }, ], }, }; ``` ## Agent Configuration [Section titled “Agent Configuration”](#agent-configuration) Configure RCS agents with full type safety: ```typescript import type { RcsBusinessMessagingAgent, HostingRegion, AgentUseCase } from '@rcs-lang/types'; const agent: RcsBusinessMessagingAgent = { description: 'Customer support agent for ACME Corp', logoUri: 'https://example.com/logo.png', heroUri: 'https://example.com/hero.jpg', phoneNumbers: [ { phoneNumber: '+1234567890', label: 'Support', }, ], emails: [ { address: 'support@example.com', label: 'Customer Support', }, ], websites: [ { uri: 'https://example.com', label: 'Main Website', }, ], privacy: { uri: 'https://example.com/privacy', label: 'Privacy Policy', }, termsConditions: { uri: 'https://example.com/terms', label: 'Terms of Service', }, color: '#0000FF', billingConfig: { billingCategory: 'CONVERSATIONAL', }, agentUseCase: 'MULTI_USE', hostingRegion: 'NORTH_AMERICA', }; ``` ## Suggestions and Actions [Section titled “Suggestions and Actions”](#suggestions-and-actions) ### Reply Suggestions [Section titled “Reply Suggestions”](#reply-suggestions) ```typescript import type { Suggestion, SuggestedReply } from '@rcs-lang/types'; const replySuggestion: Suggestion = { reply: { text: 'Yes, please!', postbackData: 'USER_RESPONSE_YES', }, }; ``` ### Action Suggestions [Section titled “Action Suggestions”](#action-suggestions) ```typescript import type { Suggestion, SuggestedAction } from '@rcs-lang/types'; // Dial action const dialSuggestion: Suggestion = { action: { text: 'Call us', postbackData: 'DIAL_SUPPORT', dialAction: { phoneNumber: '+1234567890', }, }, }; // Open URL action const urlSuggestion: Suggestion = { action: { text: 'Visit website', postbackData: 'OPEN_WEBSITE', openUrlAction: { url: 'https://example.com', }, }, }; // Location actions const viewLocationSuggestion: Suggestion = { action: { text: 'View on map', postbackData: 'VIEW_LOCATION', viewLocationAction: { latLong: { latitude: 37.4220579, longitude: -122.0840897, }, label: 'Our Office', }, }, }; ``` ## Branded Types [Section titled “Branded Types”](#branded-types) The package includes branded types for enhanced type safety: ```typescript import type { PhoneNumber, EmailAddress, Url, HexColor } from '@rcs-lang/types'; // These provide compile-time type safety const phone: PhoneNumber = '+1234567890' as PhoneNumber; const email: EmailAddress = 'user@example.com' as EmailAddress; const url: Url = 'https://example.com' as Url; const color: HexColor = '#FF0000' as HexColor; // TypeScript will prevent mixing up types function sendToPhone(number: PhoneNumber) { // Implementation } // This would cause a TypeScript error: // sendToPhone(email); // Error: EmailAddress is not assignable to PhoneNumber ``` ## Type Categories [Section titled “Type Categories”](#type-categories) ### Agent Types [Section titled “Agent Types”](#agent-types) * `RcsBusinessMessagingAgent` - Complete agent configuration * `AgentUseCase` - Agent use case enumeration * `HostingRegion` - Hosting region enumeration * `BillingCategory` - Billing category enumeration ### Message Types [Section titled “Message Types”](#message-types) * `AgentMessage` - Complete agent message structure * `AgentContentMessage` - Message content with various formats * `MessageTrafficType` - Message traffic type enumeration * `Suggestion` - Reply suggestions and actions * `RichCard` - Rich card messages (standalone or carousel) ### Action Types [Section titled “Action Types”](#action-types) * `DialAction` - Phone dialing action * `ViewLocationAction` - Location viewing action * `CreateCalendarEventAction` - Calendar event creation * `OpenUrlAction` - URL opening action * `ShareLocationAction` - Location sharing request ### Event Types [Section titled “Event Types”](#event-types) * `AgentEvent` - Agent-initiated events (typing, read receipts) * `EventType` - Event type enumeration ### Brand & Testing [Section titled “Brand & Testing”](#brand--testing) * `Brand` - Brand configuration * `BrandState` - Brand state enumeration * `Tester` - Tester configuration * `InvitationStatus` - Tester invitation status ### Integration Types [Section titled “Integration Types”](#integration-types) * `Integration` - Dialogflow integration configuration * `IntegrationType` - Integration type enumeration ## Integration with RCL [Section titled “Integration with RCL”](#integration-with-rcl) When using with RCL compiler and runtime: ```typescript import { RCLCompiler } from '@rcs-lang/compiler'; import type { AgentMessage } from '@rcs-lang/types'; // Compile RCL to get messages const compiler = new RCLCompiler(); const result = await compiler.compile(rclSource); if (result.success) { // Access typed messages const messages: Record = result.data.messages; // Use with full type safety Object.entries(messages).forEach(([name, message]) => { console.log(`Message ${name}:`, message.contentMessage?.text); }); } ``` ## Type Safety Best Practices [Section titled “Type Safety Best Practices”](#type-safety-best-practices) ### Using Discriminated Unions [Section titled “Using Discriminated Unions”](#using-discriminated-unions) Many types use discriminated unions for type safety: ```typescript import type { Suggestion } from '@rcs-lang/types'; function processSuggestion(suggestion: Suggestion) { if ('reply' in suggestion) { // TypeScript knows this is a SuggestedReply console.log('Reply text:', suggestion.reply.text); } else { // TypeScript knows this is a SuggestedAction console.log('Action text:', suggestion.action.text); if (suggestion.action.dialAction) { console.log('Dial number:', suggestion.action.dialAction.phoneNumber); } } } ``` ### Exhaustive Type Checking [Section titled “Exhaustive Type Checking”](#exhaustive-type-checking) ```typescript import type { MessageTrafficType } from '@rcs-lang/types'; function getMessagePriority(trafficType: MessageTrafficType): number { switch (trafficType) { case 'TRANSACTION': return 1; case 'UPDATE': return 2; case 'OTP': return 0; case 'PROMOTION': return 3; default: // TypeScript will error if we miss a case const exhaustive: never = trafficType; throw new Error(`Unhandled traffic type: ${exhaustive}`); } } ``` ## API Reference [Section titled “API Reference”](#api-reference) For detailed API documentation of all interfaces, types, and enums, see the API Reference section in the documentation. ## Official Google RBM References [Section titled “Official Google RBM References”](#official-google-rbm-references) * [Agent Messages](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest/v1/phones.agentMessages) * [Agent Configuration](https://developers.google.com/business-communications/rcs-business-messaging/reference/business-communications/rest/v1/brands.agents) * [Brands](https://developers.google.com/business-communications/rcs-business-messaging/reference/business-communications/rest/v1/brands) * [Testers](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest/v1/phones.testers) * [Agent Events](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest/v1/phones.agentEvents) * [File Operations](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest/v1/files) * [Integrations](https://developers.google.com/business-communications/rcs-business-messaging/reference/business-communications/rest/v1/brands.agents.integrations) # @rcs-lang/validation > Validation pipeline for RCL language # @rcs-lang/validation [Section titled “@rcs-lang/validation”](#rcs-langvalidation) The `@rcs-lang/validation` package provides comprehensive validation capabilities for RCL (Rich Communication Language) documents. It performs semantic analysis, type checking, and constraint validation on parsed RCL ASTs. ## Installation [Section titled “Installation”](#installation) ```bash bun add @rcs-lang/validation ``` ## Overview [Section titled “Overview”](#overview) The validation package ensures RCL documents are: * **Syntactically correct** - Valid according to RCL grammar * **Semantically valid** - References resolve correctly * **Type-safe** - Values match expected types * **Constraint-compliant** - Meets all RCL specification requirements ## Features [Section titled “Features”](#features) ### Validation Rules [Section titled “Validation Rules”](#validation-rules) * **Agent validation** * Valid agent names (Title Case identifiers) * Required `displayName` field * At least one flow definition * Messages section present * **Flow validation** * Valid state names and transitions * Reachable states * No circular dependencies * Valid action references * **Message validation** * Valid message IDs * Proper template syntax * Type tag validation * Variable reference checking * **Type validation** * URL format validation * Phone number format checking * Date/time format validation * Custom type constraints ### Error Reporting [Section titled “Error Reporting”](#error-reporting) The validator provides detailed error messages with: * Precise source locations * Error severity levels (error, warning, info) * Suggested fixes when possible * Related information links ## Usage Example [Section titled “Usage Example”](#usage-example) ```typescript import { validate, ValidationResult } from '@rcs-lang/validation'; import { parse } from '@rcs-lang/parser'; // Parse RCL document const ast = parse(rclSource); // Validate the AST const result: ValidationResult = validate(ast); if (result.isValid) { console.log('Document is valid!'); } else { // Handle validation errors result.diagnostics.forEach(diagnostic => { console.error(`${diagnostic.severity}: ${diagnostic.message}`); console.error(` at ${diagnostic.range.start.line}:${diagnostic.range.start.column}`); }); } ``` ## Validation Pipeline [Section titled “Validation Pipeline”](#validation-pipeline) ```typescript import { ValidationPipeline } from '@rcs-lang/validation'; // Create custom validation pipeline const pipeline = new ValidationPipeline() .addRule(customBusinessRule) .addRule(organizationSpecificRule) .configure({ strictMode: true, allowDeprecated: false }); const result = pipeline.validate(ast); ``` ## Custom Validation Rules [Section titled “Custom Validation Rules”](#custom-validation-rules) ```typescript import { ValidationRule, ValidationContext } from '@rcs-lang/validation'; const customRule: ValidationRule = { name: 'no-test-agents', validate(node, context: ValidationContext) { if (node.type === 'Agent' && node.name.includes('Test')) { context.reportError( 'Test agents not allowed in production', node.location ); } } }; ``` ## Integration [Section titled “Integration”](#integration) The validation package integrates with: * **@rcs-lang/parser** - Validates parsed ASTs * **@rcs-lang/compiler** - Pre-compilation validation * **@rcs-lang/language-service** - Real-time validation in editors * **@rcs-lang/cli** - Command-line validation ## Configuration [Section titled “Configuration”](#configuration) ```typescript interface ValidationConfig { // Enable strict validation mode strictMode?: boolean; // Allow deprecated features allowDeprecated?: boolean; // Maximum errors before stopping maxErrors?: number; // Custom validation rules customRules?: ValidationRule[]; } ``` ## API Reference [Section titled “API Reference”](#api-reference) ### Main Functions [Section titled “Main Functions”](#main-functions) * `validate(ast: RCLAst, config?: ValidationConfig): ValidationResult` * `validateFile(filePath: string, config?: ValidationConfig): Promise` * `createValidator(config?: ValidationConfig): Validator` ### Types [Section titled “Types”](#types) * `ValidationResult` - Overall validation result * `Diagnostic` - Individual validation issue * `ValidationRule` - Custom rule interface * `ValidationContext` - Rule execution context # RCL Formal Specification > Complete EBNF grammar specification for RCL including flow control extensions # Rich Communication Language (RCL) - Formal Specification [Section titled “Rich Communication Language (RCL) - Formal Specification”](#rich-communication-language-rcl---formal-specification) ## 1. Introduction [Section titled “1. Introduction”](#1-introduction) This document provides the formal specification for the Rich Communication Language (RCL) using an Extended Backus-Naur Form (EBNF)-like notation. RCL is a data language designed to express any JSON-representable structure through a human-friendly syntax. It provides a generic Section/Attribute model where sections correspond to objects and can represent any hierarchical data. The language emphasizes simplicity, readability, and extensibility. ### Design Philosophy [Section titled “Design Philosophy”](#design-philosophy) * **Generic Data Language**: Any JSON structure can be expressed using Sections (objects) and Attributes (properties) * **Indentation-based**: Blocks are defined by indentation (like Python/YAML), no explicit end keywords * **Extensible**: New section types can be added without changing the core syntax * **Type-aware**: Built-in type tags for common data types with validation ### Notation Conventions [Section titled “Notation Conventions”](#notation-conventions) * `RuleName ::= Definition` : Defines a rule * `'literal'` : Literal string or keyword (e.g., `'agent'`, `':'`) * `TERMINAL_NAME` : Terminal symbol/token (e.g., `IDENTIFIER`, `STRING`) * `RuleName` : Non-terminal symbol reference * `A | B` : Alternative (A or B) * `(A B)` : Sequence of A followed by B * `A?` : Zero or one occurrence (optional) * `A*` : Zero or more occurrences * `A+` : One or more occurrences * `// comment` : Explanatory comments ## 2. Lexical Specification (Terminals) [Section titled “2. Lexical Specification (Terminals)”](#2-lexical-specification-terminals) ### 2.1 Block Delimiters [Section titled “2.1 Block Delimiters”](#21-block-delimiters) RCL uses indentation-based blocks (Python-style) without explicit end keywords. ```ebnf INDENT ::= // Increase in indentation level DEDENT ::= // Decrease in indentation level ``` ### 2.2 Hidden Terminals [Section titled “2.2 Hidden Terminals”](#22-hidden-terminals) ```ebnf WS ::= /[ ]+/ // Whitespace (spaces/tabs), not newlines NL ::= /[ ]+/ // Newlines SL_COMMENT ::= /#.*/ // Single-line comments ``` ### 2.3 Common Terminals [Section titled “2.3 Common Terminals”](#23-common-terminals) ```ebnf IDENTIFIER ::= /[A-Z]([A-Za-z0-9-_]|(\s(?=[A-Z0-9]))*/ // Title Case with spaces ATTRIBUTE_KEY ::= /[a-z][a-zA-Z0-9_]*/ // lowerCamelCase SECTION_TYPE ::= /[a-z][a-zA-Z0-9]*/ // lowercase section types VARIABLE ::= /@[a-zA-Z_][a-zA-Z0-9_]*/ // @variable PROPERTY_ACCESS ::= VARIABLE ('.' ATTRIBUTE_KEY)* // @obj.property ATOM ::= /:[a-zA-Z_][a-zA-Z0-9_]*/ // :symbol STRING ::= /"(\.|[^"\])*"/ // Double-quoted strings TRIPLE_STRING_DELIM ::= /"""/ // Triple quote delimiter NUMBER ::= /[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?/ // Numbers with optional decimals/exponents ISO_DURATION ::= /(P((\d+Y)|(\d+M)|(\d+W)|(\d+D)|(T((\d+H)|(\d+M)|(\d+(\.\d+)?S))+))+)|([0-9]+(\.[0-9]+)?s)/ SPREAD ::= /\.\.\./ // Spread operator ``` ### 2.4 String Interpolation [Section titled “2.4 String Interpolation”](#24-string-interpolation) ```ebnf INTERPOLATION_START ::= /#\{/ INTERPOLATION_END ::= /\}/ ``` ### 2.5 Embedded Code Terminals [Section titled “2.5 Embedded Code Terminals”](#25-embedded-code-terminals) ```ebnf EMBEDDED_CODE ::= /\$((js|ts)?>)\s*[^ ]*/ // $js> code or $> expr MULTI_LINE_CODE_START ::= /\$((js|ts)?)>>>/ // $js>>> or $>>> MULTI_LINE_CODE_END ::= /<\$/ // End marker ``` ### 2.6 Multi-line String Terminals [Section titled “2.6 Multi-line String Terminals”](#26-multi-line-string-terminals) ```ebnf MULTILINE_STR_CLEAN ::= /\|\s*$/ // | (clean) MULTILINE_STR_TRIM ::= /\|-\s*$/ // |- (trim trailing) MULTILINE_STR_PRESERVE ::= /\+\|\s*$/ // +| (preserve leading) MULTILINE_STR_PRESERVE_ALL ::= /\+\|\+\s*$/ // +|+ (preserve all) MULTILINE_STR_END ::= /^\s*\|$/ // Line with only | ``` ### 2.7 Type Tag Terminals [Section titled “2.7 Type Tag Terminals”](#27-type-tag-terminals) ```ebnf TYPE_TAG_NAME ::= /[a-zA-Z]+/ // email, phone, url, etc. ``` ## 3. Syntactic Specification (Parser Rules) [Section titled “3. Syntactic Specification (Parser Rules)”](#3-syntactic-specification-parser-rules) ### 3.0 Core Value Rules [Section titled “3.0 Core Value Rules”](#30-core-value-rules) ```ebnf BooleanLiteral ::= 'True' | 'Yes' | 'On' | 'False' | 'No' | 'Off' NullLiteral ::= 'Null' | 'None' | 'Void' PrimitiveValue ::= STRING | MultiLineString | NUMBER | BooleanLiteral | NullLiteral | ATOM | TypeTag InterpolatedContent ::= PlainText | (INTERPOLATION_START (VARIABLE | PROPERTY_ACCESS | Value) INTERPOLATION_END) TypeTag ::= '<' TYPE_TAG_NAME (STRING | NUMBER | IDENTIFIER | ISO_DURATION) ('|' STRING)? '>' Value ::= PrimitiveValue | IDENTIFIER | VARIABLE | PROPERTY_ACCESS | List | Dictionary | EmbeddedCode ContextualizedValue ::= Value ('with' ParameterList)? Parameter ::= ATTRIBUTE_KEY ':' Value | Value // Positional parameter ParameterList ::= Parameter (',' Parameter)* ``` ### 3.1 Collection Rules [Section titled “3.1 Collection Rules”](#31-collection-rules) ```ebnf List ::= ParenthesesList | InlineList | BlockList ParenthesesList ::= '(' (Value (',' Value)*)? ')' InlineList ::= Value (',' Value)+ // 2+ items, parentheses optional BlockList ::= INDENT (BlockListItem)+ DEDENT BlockListItem ::= '-' Value Dictionary ::= BraceDictionary | BlockDictionary BraceDictionary ::= '{' (DictEntry (',' DictEntry)*)? '}' BlockDictionary ::= INDENT (DictEntry)+ DEDENT DictEntry ::= (ATTRIBUTE_KEY | STRING) ':' Value ``` ### 3.2 String Rules [Section titled “3.2 String Rules”](#32-string-rules) MultiLineString ::= ( // Pipe-style (MULTILINE\_STR\_CLEAN | MULTILINE\_STR\_TRIM | MULTILINE\_STR\_PRESERVE | MULTILINE\_STR\_PRESERVE\_ALL) INDENT StringContent DEDENT MULTILINE\_STR\_END ) | ( // Triple-quote style TRIPLE\_STRING\_DELIM (InterpolatedContent)\* TRIPLE\_STRING\_DELIM ) StringContent ::= // Raw text content with proper indentation handling ### 3.3 Embedded Code Rules [Section titled “3.3 Embedded Code Rules”](#33-embedded-code-rules) ```ebnf EmbeddedCode ::= SingleLineCode | MultiLineCode SingleLineCode ::= EMBEDDED_CODE MultiLineCode ::= MULTI_LINE_CODE_START INDENT CodeContent DEDENT MULTI_LINE_CODE_END CodeContent ::= // Raw code content ``` ### 3.4 Section Rules [Section titled “3.4 Section Rules”](#34-section-rules) ```ebnf Section ::= SECTION_TYPE IDENTIFIER? ParameterList? (INDENT (SpreadDirective | Attribute | Section | MatchBlock | Value)* DEDENT)? SpreadDirective ::= SPREAD IDENTIFIER Attribute ::= ATTRIBUTE_KEY ':' Value MatchBlock ::= 'match' Value INDENT (MatchCase)+ DEDENT MatchCase ::= (STRING | NUMBER | ATOM) '->' Consequence | ':default' '->' Consequence Consequence ::= ContextualizedValue | FlowInvocation | FlowTermination FlowInvocation ::= 'start' IDENTIFIER ('with' ParameterList)? ('on' FlowResult '->' ResultHandler)* FlowResult ::= ':end' | ':cancel' | ':error' ResultHandler ::= ContextOperation? TargetReference ContextOperation ::= 'append' 'result' 'to' ContextVariable | 'set' ContextVariable 'to' 'result' | 'merge' 'result' 'into' ContextVariable ContextVariable ::= VARIABLE | PROPERTY_ACCESS TargetReference ::= IDENTIFIER | VARIABLE | PROPERTY_ACCESS | FlowTermination FlowTermination ::= ':end' | ':cancel' | ':error' ``` ### 3.5 File Structure [Section titled “3.5 File Structure”](#35-file-structure) ```ebnf RclFile ::= (ImportStatement)* (Section)* ImportStatement ::= 'import' ImportPath ('as' IDENTIFIER)? ImportPath ::= IDENTIFIER ('/' IDENTIFIER)* ``` ## 4. Type System [Section titled “4. Type System”](#4-type-system) ### 4.1 Identifier Rules [Section titled “4.1 Identifier Rules”](#41-identifier-rules) **IDENTIFIER** (Title Case): * Must start with uppercase letter (A-Z) * Can contain letters, numbers, hyphens, underscores * Spaces allowed between Title Case words * Examples: `Welcome Message`, `User-Profile`, `Order ID 123` **ATTRIBUTE\_KEY** (lowerCamelCase): * Must start with lowercase letter (a-z) * Can contain letters, numbers, underscore * Examples: `displayName`, `messageType`, `user_id` **SECTION\_TYPE** (lowercase): * Must start with lowercase letter * Examples: `agent`, `config`, `flow`, `messages`, `on` ### 4.2 Type Tags [Section titled “4.2 Type Tags”](#42-type-tags) | Type | Aliases | Examples | Notes | | ---------- | ------------ | ----------------------------------------- | ------------------------ | | `email` | - | `` | | | `phone` | `msisdn` | `` | | | `url` | - | `` | | | `time` | `t` | `