You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by ar...@apache.org on 2021/03/04 06:02:32 UTC

[incubator-nlpcraft] branch NLPCRAFT-206 updated: WIP (does NOT compile).

This is an automated email from the ASF dual-hosted git repository.

aradzinski pushed a commit to branch NLPCRAFT-206
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


The following commit(s) were added to refs/heads/NLPCRAFT-206 by this push:
     new e00d7ff  WIP (does NOT compile).
e00d7ff is described below

commit e00d7fff40914acf9a6cdbd2220c5378fb29cc9a
Author: Aaron Radzinzski <ar...@datalingvo.com>
AuthorDate: Wed Mar 3 22:02:22 2021 -0800

    WIP (does NOT compile).
---
 .../apache/nlpcraft/model/NCDialogFlowItem.java    |  26 +-
 .../scala/org/apache/nlpcraft/model/NCRequest.java |   2 +-
 .../impl/{ver2 => }/NCIntentDslBaselCompiler.scala |   9 +-
 .../model/intent/impl/NCIntentDslCompiler.scala    | 652 ++++++++++++---------
 .../impl/{ver2 => }/NCIntentDslFragmentCache.scala |   4 +-
 .../model/intent/impl/NCIntentSolverEngine.scala   |  26 +-
 .../intent/impl/ver2/NCIntentDslCompiler.scala     | 485 ---------------
 .../intent/utils/{ver2 => }/NCDslFragment.scala    |   2 +-
 .../nlpcraft/model/intent/utils/NCDslIntent.scala  |  65 +-
 .../nlpcraft/model/intent/utils/NCDslTerm.java     | 131 -----
 .../model/intent/utils/{ver2 => }/NCDslTerm.scala  |   2 +-
 .../intent/utils/{ver2 => }/NCDslTermContext.scala |   2 +-
 .../intent/utils/{ver2 => }/NCDslTermRetVal.scala  |   2 +-
 .../model/intent/utils/ver2/NCDslIntent.scala      |  55 --
 .../mgrs/dialogflow/NCDialogFlowManager.scala      |  18 +-
 .../probe/mgrs/nlp/NCProbeEnrichmentManager.scala  |   2 +-
 .../model/intent/dsl/NCIntentDslCompilerSpec.scala |   3 +-
 17 files changed, 453 insertions(+), 1033 deletions(-)

diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java
index a32ba76..a08bbf3 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java
@@ -21,8 +21,8 @@ import java.util.*;
 
 /**
  * An item of the dialog flow. Dialog flow is a chronologically ordered list of dialog flow
- * items. Each item represents a snapshot of winning intent's match data. An instance of this interface
- * is passed into user-defined dialog flow match method.
+ * items. Each item represents a snapshot of winning intent's match and its associated data. An instance
+ * of this interface is passed into a custom user-defined dialog flow match method.
  * <p>
  * Read full documentation in <a target=_ href="https://nlpcraft.apache.org/intent-matching.html">Intent Matching</a> section and review
  * <a target=_ href="https://github.com/apache/incubator-nlpcraft/tree/master/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/">examples</a>.
@@ -78,12 +78,12 @@ public interface NCDialogFlowItem {
     List<NCToken> getTermTokens(String termId);
 
     /**
-     * Gets sentence parsing variant that produced the matching for this intent. Returned variant is one of the
+     * Gets sentence parsing variant that produced the matching for the winning intent. Returned variant is one of the
      * variants provided by {@link NCContext#getVariants()} methods. Note that tokens returned by this method are
      * a superset of the tokens returned by {@link #getIntentTokens()} method, i.e. not all tokens
      * from this variant may have been used in matching of the winning intent.
      *
-     * @return Sentence parsing variant that produced the matching for this intent.
+     * @return Sentence parsing variant that produced the matching for the winning intent.
      * @see #getIntentTokens()
      */
     NCVariant getVariant();
@@ -92,12 +92,10 @@ public interface NCDialogFlowItem {
      * Indicates whether or not the intent match was ambiguous (not exact).
      * <p>
      * An exact match means that for the intent to match it has to use all non-free word tokens
-     * in the user input, i.e. only free word tokens can be left after the match. An ambiguous match
+     * in the user input, i.e. only free word tokens can be left unused after the match. An ambiguous match
      * doesn't have this restriction. Note that an ambiguous match should be used with a great care.
      * An ambiguous match completely ignores extra found user or system tokens (which are not part
      * of the intent template) which could have altered the matching outcome had they been considered.
-     * <p>
-     * Intent callbacks that check this property should always provide custom rejection message.
      *
      * @return {@code True} if the intent match was exact, {@code false} otherwise.
      */
@@ -120,7 +118,7 @@ public interface NCDialogFlowItem {
     /**
      * Gets globally unique server ID of the input request.
      * <p>
-     * Server request is defined as a processing of a one user input request (a session).
+     * Server request is defined as a processing of a one user input request.
      * Note that the model can be accessed multiple times during processing of a single user request
      * and therefore multiple instances of this interface can return the same server
      * request ID. In fact, users of this interfaces can use this fact by using this ID,
@@ -138,29 +136,29 @@ public interface NCDialogFlowItem {
     String getNormalizedText();
 
     /**
-     * Gets UTC/GMT timestamp in ms when user input was received.
+     * Gets UTC/GMT timestamp in milliseconds when user input was received.
      *
-     * @return UTC/GMT timestamp in ms when user input was received.
+     * @return UTC/GMT timestamp in milliseconds when user input was received.
      */
     long getReceiveTimestamp();
 
     /**
-     * Gets optional address of the remote client.
+     * Gets optional address of the remote client that made the initial REST request.
      *
      * @return Optional address of the remote client.
      */
     Optional<String> getRemoteAddress();
 
     /**
-     * Gets string representation of the user client agent that made the call with
-     * this request.
+     * Gets string representation of the user client agent that made the initial REST
+     * request .
      *
      * @return User agent string from user client (web browser, REST client, etc.).
      */
     Optional<String> getClientAgent();
 
     /**
-     * Gets optional JSON data passed in with the user request.
+     * Gets optional JSON data passed in with the initial REST request.
      *
      * @return Optional JSON data.
      */
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java
index ebca5f2..74d16ee 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java
@@ -42,7 +42,7 @@ public interface NCRequest {
     /**
      * Gets globally unique server ID of the current request.
      * <p>
-     * Server request is defined as a processing of a one user input request (a session).
+     * Server request is defined as a processing of a one user input request.
      * Note that the model can be accessed multiple times during processing of a single user request
      * and therefore multiple instances of this interface can return the same server
      * request ID. In fact, users of this interfaces can use this fact by using this ID,
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslBaselCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslBaselCompiler.scala
similarity index 99%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslBaselCompiler.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslBaselCompiler.scala
index 794ad1e..16db816 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslBaselCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslBaselCompiler.scala
@@ -15,14 +15,15 @@
  * limitations under the License.
  */
 
-package org.apache.nlpcraft.model.intent.impl.ver2
+package org.apache.nlpcraft.model.intent.impl
 
-import org.antlr.v4.runtime.{ParserRuleContext ⇒ PRC}
 import org.antlr.v4.runtime.tree.{TerminalNode ⇒ TN}
+import org.antlr.v4.runtime.{ParserRuleContext ⇒ PRC}
 import org.apache.commons.lang3.StringUtils
-import org.apache.nlpcraft.model.NCToken
-import org.apache.nlpcraft.model.intent.utils.ver2.{NCDslTermContext, NCDslTermRetVal}
 import org.apache.nlpcraft.common._
+import org.apache.nlpcraft.model.NCToken
+import org.apache.nlpcraft.model.intent.utils.{NCDslTermContext, NCDslTermRetVal}
+import org.apache.nlpcraft.model.intent.utils.ver2.NCDslTermRetVal
 
 import java.lang.{Double ⇒ JDouble, Long ⇒ JLong}
 import java.time.LocalDate
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala
index 47d1c76..9aae4c8 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala
@@ -19,68 +19,82 @@ package org.apache.nlpcraft.model.intent.impl
 
 import com.typesafe.scalalogging.LazyLogging
 import org.antlr.v4.runtime._
-import org.antlr.v4.runtime.tree._
-import org.apache.nlpcraft.model.NCToken
-import org.apache.nlpcraft.model.intent.impl.antlr4.{NCIntentDslBaseListener, NCIntentDslLexer, NCIntentDslParser}
-import org.apache.nlpcraft.model.intent.utils.{NCDslIntent, NCDslTerm}
+import org.antlr.v4.runtime.tree.ParseTreeWalker
 import org.apache.nlpcraft.common._
+import org.apache.nlpcraft.model._
+import org.apache.nlpcraft.model.intent.impl.antlr4.{NCIntentDslParser ⇒ IDP, _}
+import org.apache.nlpcraft.model.intent.impl.{NCIntentDslFragmentCache ⇒ FragCache}
+import org.apache.nlpcraft.model.intent.utils._
 
+import java.nio.file.Path
+import java.util.Optional
+import java.util.regex.{Pattern, PatternSyntaxException}
 import scala.collection.JavaConverters._
 import scala.collection.mutable
 import scala.collection.mutable.ArrayBuffer
 
-/**
-  * Intent DSL compiler.
-  */
 object NCIntentDslCompiler extends LazyLogging {
     // Compiler cache.
-    private val cache = new java.util.concurrent.ConcurrentHashMap[String, NCDslIntent]().asScala
-    
-    private var mdlId: String = _
-    
+    private val cache = new mutable.HashMap[String, Set[NCDslIntent]]
+
     /**
-      * 
-      */
-    class FiniteStateMachine extends NCIntentDslBaseListener {
+     *
+     * @param dsl
+     * @param mdlId
+     */
+    class FiniteStateMachine(dsl: String, mdlId: String) extends NCIntentDslBaseListener with NCIntentDslBaselCompiler {
+        // Accumulator for parsed intents.
+        private val intents = ArrayBuffer.empty[NCDslIntent]
+
+        // Fragment components.
+        private var fragId: String = _
+        private var fragMeta: Map[String, Any] = _
+
         // Intent components.
+        private var intentId: String = _
         private var ordered: Boolean = false
-        private var id: String = _
-        private val terms = ArrayBuffer.empty[NCDslTerm] // Accumulator for parsed terms.
         private var flowRegex: Option[String] = None
+        private var intentMeta: Map[String, Any] = _
+
+        // Accumulator for parsed terms.
+        private val terms = ArrayBuffer.empty[NCDslTerm]
 
         // Currently term.
         private var termId: String = _
         private var termConv: Boolean = _
         private var min = 1
         private var max = 1
-    
-        private val predStack = new mutable.ArrayStack[NCToken ⇒ Boolean] // Stack of predicates.
-        private val lvalParts = ArrayBuffer.empty[String] // lval parts collector.
-        private val rvalList = ArrayBuffer.empty[String] // rval list collector.
-        private var rval: String = _
-    
-        /**
-          *
-          * @return
-          */
-        def getBuiltIntent: NCDslIntent = {
-            require(id != null)
-            require(terms.nonEmpty)
-            
-            NCDslIntent(id, ordered, flowRegex, terms.toArray)
-        }
-    
+
+        // Current method reference.
+        private var refClsName: Option[String] = None
+        private var refMtdName: Option[String] = None
+
+        // Current term's code, i.e. list of instructions.
+        private var termInstrs = mutable.Buffer.empty[Instr]
+
+        /*
+         * Shared/common implementation.
+         */
+        override def exitUnaryExpr(ctx: IDP.UnaryExprContext): Unit = termInstrs += parseUnaryExpr(ctx.MINUS(), ctx.NOT())(ctx)
+        override def exitMultExpr(ctx: IDP.MultExprContext): Unit = termInstrs += parseMultExpr(ctx.MULT(), ctx.MOD(), ctx.DIV())(ctx)
+        override def exitPlusExpr(ctx: IDP.PlusExprContext): Unit = termInstrs += parsePlusExpr(ctx.PLUS(), ctx.MINUS())(ctx)
+        override def exitCompExpr(ctx: IDP.CompExprContext): Unit = termInstrs += parseCompExpr(ctx.LT(), ctx.GT(), ctx.LTEQ(), ctx.GTEQ())(ctx)
+        override def exitLogExpr(ctx: IDP.LogExprContext): Unit = termInstrs += parseLogExpr(ctx.AND, ctx.OR())(ctx)
+        override def exitEqExpr(ctx: IDP.EqExprContext): Unit = termInstrs += parseEqExpr(ctx.EQ, ctx.NEQ())(ctx)
+        override def exitCallExpr(ctx: IDP.CallExprContext): Unit = termInstrs += parseCallExpr(ctx.FUN_NAME())(ctx)
+        override def exitAtom(ctx: IDP.AtomContext): Unit = termInstrs += parseAtom(ctx.getText)(ctx)
+
         /**
-          *
-          * @param min
-          * @param max
-          */
+         *
+         * @param min
+         * @param max
+         */
         private def setMinMax(min: Int, max: Int): Unit = {
             this.min = min
             this.max = max
         }
-    
-        override def exitMinMaxShortcut(ctx: NCIntentDslParser.MinMaxShortcutContext): Unit = {
+
+        override def exitMinMaxShortcut(ctx: IDP.MinMaxShortcutContext): Unit = {
             if (ctx.PLUS() != null)
                 setMinMax(1, Integer.MAX_VALUE)
             else if (ctx.MULT() != null)
@@ -91,22 +105,10 @@ object NCIntentDslCompiler extends LazyLogging {
                 assert(false)
         }
     
-//        override def exitLvalPart(ctx: NCIntentDslParser.LvalPartContext): Unit = {
-//            lvalParts += ctx.ID().getText.trim()
-//        }
-    
-        override def exitTermId(ctx: NCIntentDslParser.TermIdContext): Unit = {
-            termId = ctx.id().getText.trim
-        }
-
-        override def exitTermEq(ctx: NCIntentDslParser.TermEqContext): Unit = {
-            termConv = ctx.TILDA() != null
-        }
-
-        override def exitMinMaxRange(ctx: NCIntentDslParser.MinMaxRangeContext): Unit = {
+        override def exitMinMaxRange(ctx: IDP.MinMaxRangeContext): Unit = {
             val minStr = ctx.getChild(1).getText.trim
             val maxStr = ctx.getChild(3).getText.trim
-            
+        
             try
                 setMinMax(java.lang.Integer.parseInt(minStr), java.lang.Integer.parseInt(maxStr))
             catch {
@@ -115,261 +117,369 @@ object NCIntentDslCompiler extends LazyLogging {
             }
         }
 
-        override def exitFlowDecl(ctx: NCIntentDslParser.FlowDeclContext): Unit = {
-            val qRegex = ctx.qstring().getText.trim
-
-            if (qRegex != null && qRegex.length > 2) {
-                val regex = qRegex.substring(1, qRegex.length - 1).strip // Remove single quotes.
+        override def exitMtdRef(ctx: IDP.MtdRefContext): Unit = {
+            if (ctx.javaFqn() != null)
+                refClsName = Some(ctx.javaFqn().getText)
 
-                flowRegex = if (regex.nonEmpty) Some(regex) else None
-            }
+            refMtdName = Some(ctx.id().getText)
         }
 
-        override def exitIntentId(ctx: NCIntentDslParser.IntentIdContext): Unit = {
-            id = ctx.id().getText.trim
+        override def exitTermId(ctx: IDP.TermIdContext): Unit = {
+            termId = ctx.id().getText
+    
+            if (terms.exists(t ⇒ t.id != null && t.id == termId))
+                throw newSyntaxError(s"Duplicate term ID: $termId")(ctx.id())
         }
     
-        override def exitOrderedDecl(ctx: NCIntentDslParser.OrderedDeclContext): Unit = {
-            ordered = ctx.BOOL().getText.strip == "true"
+        override def exitIntentId(ctx: IDP.IntentIdContext): Unit = {
+            intentId = ctx.id().getText
+    
+            if (intents.exists(i ⇒ i.id != null && i.id == intentId))
+                throw newSyntaxError(s"Duplicate intent ID: $intentId")(ctx.id())
         }
     
-        override def exitTerm(ctx: NCIntentDslParser.TermContext): Unit = {
-            require(predStack.size == 1)
-            
-            val p = predStack.pop
-            
-            terms += new NCDslTerm(
+        override def exitFragId(ctx: IDP.FragIdContext): Unit = {
+            fragId = ctx.id().getText
+    
+            if (FragCache.get(mdlId, fragId).isDefined)
+                throw newSyntaxError(s"Duplicate fragment ID: $fragId")(ctx.id())
+        }
+
+        override def exitTermEq(ctx: IDP.TermEqContext): Unit =  termConv = ctx.TILDA() != null
+        override def exitFragMeta(ctx: IDP.FragMetaContext): Unit = fragMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
+        override def exitMetaDecl(ctx: IDP.MetaDeclContext): Unit = intentMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
+        override def exitOrderedDecl(ctx: IDP.OrderedDeclContext): Unit = ordered = ctx.BOOL().getText == "true"
+
+        override def exitFragRef(ctx: IDP.FragRefContext): Unit = {
+            val id = ctx.id().getText
+
+            FragCache.get(mdlId, id) match {
+                case Some(frag) ⇒
+                    val meta = if (fragMeta == null) Map.empty[String, Any] else fragMeta
+
+                    for (fragTerm ← frag.terms)
+                         if (terms.exists(t ⇒ t.id != null && t.id == fragTerm.id))
+                            throw newSyntaxError(s"Duplicate term ID '${fragTerm.id}' in fragment '$id'.")(ctx.id())
+                        else
+                            terms += fragTerm.cloneWithMeta(meta)
+
+                case None ⇒ throw newSyntaxError(s"Unknown intent fragment ID: $id")(ctx.id())
+            }
+
+            fragMeta = null
+        }
+
+        override def exitFlowDecl(ctx: IDP.FlowDeclContext): Unit = {
+            implicit val evidence: ParserRuleContext = ctx
+
+            if (ctx.qstring() != null) {
+                val regex = ctx.qstring().getText
+
+                if (regex != null && regex.length > 2)
+                    flowRegex = if (regex.nonEmpty) Some(regex) else None
+
+                if (flowRegex.isDefined) // Pre-check.
+                    try
+                        Pattern.compile(flowRegex.get)
+                    catch {
+                        case e: PatternSyntaxException ⇒
+                            newSyntaxError(s"${e.getDescription} in intent flow regex '${e.getPattern}' near index ${e.getIndex}.")(ctx.qstring())
+                    }
+            }
+        }
+
+        override def exitTerm(ctx: IDP.TermContext): Unit = {
+            implicit val c: ParserRuleContext = ctx
+
+            if (min < 0 || min > max)
+                throw newSyntaxError(s"Invalid intent term min quantifiers: $min (must be min >= 0 && min <= max).")(ctx.minMax())
+            if (max < 1)
+                throw newSyntaxError(s"Invalid intent term max quantifiers: $max (must be max >= 1).")(ctx.minMax())
+
+            val pred =
+                if (refMtdName != null) { // User-code defined term.
+                    // Closure copies.
+                    val clsName = refClsName.orNull
+                    val mtdName = refMtdName.orNull
+
+                    (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
+                        val javaCtx: NCTokenPredicateContext = new NCTokenPredicateContext {
+                            override lazy val getRequest: NCRequest = termCtx.req
+                            override lazy val getToken: NCToken = tok
+                            override lazy val getIntentMeta: Optional[NCMetadata] =
+                                if (termCtx.intentMeta != null)
+                                    Optional.of(NCMetadata.apply(termCtx.intentMeta.asJava))
+                                else
+                                    Optional.empty()
+                        }
+
+                        val mdl = tok.getModel
+                        val mdlCls = if (clsName == null) mdl.meta[String](MDL_META_MODEL_CLASS_KEY) else clsName
+
+                        try {
+                            val obj = if (clsName == null) mdl else U.mkObject(clsName)
+                            val mtd = Thread.currentThread().getContextClassLoader.loadClass(mdlCls)
+                                .getMethod(mtdName, classOf[NCTokenPredicateContext])
+
+                            var flag = mtd.canAccess(mdl)
+
+                            val res = try {
+                                if (!flag) {
+                                    mtd.setAccessible(true)
+
+                                    flag = true
+                                }
+                                else
+                                    flag = false
+
+                                mtd.invoke(obj, javaCtx).asInstanceOf[NCTokenPredicateResult]
+                            }
+                            finally {
+                                if (flag)
+                                    try
+                                        mtd.setAccessible(false)
+                                    catch {
+                                        case e: SecurityException ⇒
+                                            throw new NCE(s"Access or security error in custom intent term: $mdlCls.$mtdName", e)
+                                    }
+                            }
+
+                            (res.getResult, res.wasTokenUsed())
+                        }
+                        catch {
+                            case e: Exception ⇒
+                                throw newRuntimeError(s"Failed to invoke custom intent term: $mdlCls.$mtdName", e)
+                        }
+                    }
+                }
+                else { // DSL-defined term.
+                    val instrs = mutable.Buffer.empty[Instr]
+
+                    instrs ++= termInstrs
+
+                    (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
+                        val stack = new mutable.ArrayStack[NCDslTermRetVal]()
+
+                        // Execute all instructions.
+                        instrs.foreach(_(tok, stack, termCtx))
+
+                        // Pop final result from stack.
+                        val x = stack.pop()
+
+                        if (!isBoolean(x.retVal))
+                            throw newRuntimeError(s"Intent term does not return boolean value: ${ctx.getText}")
+
+                        (asBool(x.retVal), x.usedTok)
+                    }
+
+                }
+                
+            // Add term.
+            terms += NCDslTerm(
                 termId,
-                new java.util.function.Function[NCToken, java.lang.Boolean]() {
-                    override def apply(tok: NCToken): java.lang.Boolean = p.apply(tok)
-                    override def toString: String = p.toString().strip //ctx.item().getText
-                },
+                pred,
                 min,
                 max,
-                termConv)
-            
-            // Reset.
-            termId = null
+                termConv
+            )
+
+            // Reset term vars.
             setMinMax(1, 1)
+            termId = null
+            termInstrs.clear()
+            refClsName = None
+            refMtdName = None
         }
-    
-//        override def exitRvalSingle(ctx: NCIntentDslParser.RvalSingleContext): Unit = {
-//            rval = ctx.getText.trim()
-//        }
-    
-//        override def exitRvalList(ctx: NCIntentDslParser.RvalListContext): Unit = {
-//            rvalList += rval
-//        }
-    
-//        override def exitItem(ctx: NCIntentDslParser.ItemContext): Unit = {
-//            if (ctx.EXCL() != null) {
-//                val p = predStack.pop
-//
-//                predStack.push(new Function[NCToken, Boolean] {
-//                    override def apply(tok: NCToken): Boolean = !p.apply(tok)
-//                    override def toString: String = s"!$p"
-//                })
-//            }
-//            else if (ctx.AND() != null) {
-//                // Note that stack is LIFO so order is flipped.
-//                val p2 = predStack.pop
-//                val p1 = predStack.pop
-//
-//                predStack.push(new Function[NCToken, Boolean] {
-//                    override def apply(tok: NCToken): Boolean = {
-//                        // To bypass any possible compiler optimizations.
-//                        if (!p1.apply(tok))
-//                            false
-//                        else if (!p2.apply(tok))
-//                            false
-//                        else
-//                            true
-//                    }
-//                    override def toString: String = s"$p1 && $p2"
-//                })
-//            }
-//            else if (ctx.OR() != null) {
-//                // Note that stack is LIFO so order is flipped.
-//                val p2 = predStack.pop
-//                val p1 = predStack.pop
-//
-//                predStack.push(new Function[NCToken, Boolean] {
-//                    override def apply(tok: NCToken): Boolean = {
-//                        // To bypass any possible compiler optimizations.
-//                        if (p1.apply(tok))
-//                            true
-//                        else if (p2.apply(tok))
-//                            true
-//                        else
-//                            false
-//                    }
-//                    override def toString: String = s"$p1 || $p2"
-//                })
-//            }
-//            else if (ctx.RPAREN() != null && ctx.LPAREN() != null) {
-//                val p = predStack.pop
-//
-//                predStack.push(new Function[NCToken, Boolean] {
-//                    override def apply(tok: NCToken): Boolean = p.apply(tok)
-//                    override def toString: String = s"($p)"
-//                })
-//            }
-//
-//            // In all other cases the current predicate is already on the top of the stack.
-//        }
-    
+
+        override def exitFrag(ctx: IDP.FragContext): Unit = {
+            FragCache.add(mdlId, NCDslFragment(fragId, terms.toList))
+
+            terms.clear()
+        }
+        
+        override def exitIntent(ctx: IDP.IntentContext): Unit = {
+            intents += NCDslIntent(
+                dsl,
+                intentId,
+                ordered,
+                if (intentMeta == null) Map.empty else intentMeta,
+                flowRegex,
+                refClsName,
+                refMtdName,
+                terms.toList
+            )
+
+            refClsName = None
+            refMtdName = None
+            intentMeta = null
+            terms.clear()
+        }
+
         /**
          *
-         * @param rv
          * @return
          */
-        private def mkRvalObject(rv: String): Any = {
-            if (rv == "null") null // Try 'null'.
-            else if (rv == "true") true // Try 'boolean'.
-            else if (rv == "false") false // Try 'boolean'.
-            // Only numeric values below...
-            else {
-                // Strip '_' from numeric values.
-                val rvalNum = rv.replaceAll("_", "")
-            
-                try
-                    java.lang.Integer.parseInt(rvalNum) // Try 'int'.
-                catch {
-                    case _: NumberFormatException ⇒
-                        try
-                            java.lang.Long.parseLong(rvalNum) // Try 'long'.
-                        catch {
-                            case _: NumberFormatException ⇒
-                                try
-                                    java.lang.Double.parseDouble(rvalNum) // Try 'double'.
-                                catch {
-                                    case _: NumberFormatException ⇒ rv // String by default.
-                                }
-                        }
-                }
-            }
-        }
-    
-//        override def exitPredicate(ctx: NCIntentDslParser.PredicateContext): Unit = {
-//            var lval: String = null
-//            var lvalFunc: String = null
-//            var op: String = null
-//
-//            def getLvalNode(tree: ParseTree): String =
-//                tree.getChild(if (tree.getChildCount == 1) 0 else 1).getText.trim
-//
-//            if (ctx.children.size() == 3) {
-//                lval = getLvalNode(ctx.getChild(0))
-//                op = ctx.getChild(1).getText.trim
-//            }
-//            else {
-//                lvalFunc = ctx.getChild(0).getText.trim
-//                lval = getLvalNode(ctx.getChild(2))
-//                op = ctx.getChild(4).getText.trim
-//            }
-//
-//            val pred = new NCDslTokenPredicate(
-//                lvalParts.asJava,
-//                lvalFunc,
-//                lval,
-//                op,
-//                if (rvalList.isEmpty) mkRvalObject(rval) else rvalList.map(mkRvalObject).asJava
-//            )
-//
-//            predStack.push(new Function[NCToken, Boolean] {
-//                override def apply(tok: NCToken): Boolean = pred.apply(tok)
-//                override def toString: String = pred.toString
-//            })
-//
-//            // Reset.
-//            lvalParts.clear()
-//            rvalList.clear()
-//            rval = null
-//        }
+        def getBuiltIntents: Set[NCDslIntent] = intents.toSet
+        
+        override def syntaxError(errMsg: String, srcName: String, line: Int, pos: Int): NCE =
+            throw new NCE(mkSyntaxError(errMsg, srcName, line, pos, dsl, mdlId))
+        override def runtimeError(errMsg: String, srcName: String, line: Int, pos: Int, cause: Exception = null): NCE =
+            throw new NCE(mkRuntimeError(errMsg, srcName, line, pos, dsl, mdlId), cause)
     }
-    
+
+    /**
+     *
+     * @param msg
+     * @param line
+     * @param charPos
+     * @param dsl Original DSL text (input).
+     * @param mdlId
+     * @return
+     */
+    private def mkSyntaxError(
+        msg: String,
+        srcName: String,
+        line: Int, // 1, 2, ...
+        charPos: Int, // 0, 1, 2, ...
+        dsl: String,
+        mdlId: String): String = mkError("syntax", msg, srcName, line, charPos, dsl, mdlId)
+
     /**
-      * Custom error handler.
+      *
+      * @param msg
+      * @param dsl
+      * @param mdlId
+      * @param srcName
+      * @param line
+      * @param charPos
+      * @return
       */
-    class CompilerErrorListener(dsl: String) extends BaseErrorListener {
-        /**
-          *
-          * @param len
-          * @param pos
-          * @return
-          */
-        private def makeCharPosPointer(len: Int, pos: Int): String = {
-            val s = (for (_ ← 1 to len) yield '-').mkString("")
-            
-            s.substring(0, pos - 1) + '^' + s.substring(pos)
-        }  
+    private def mkRuntimeError(
+        msg: String,
+        srcName: String,
+        line: Int, // 1, 2, ...
+        charPos: Int, // 0, 1, 2, ...
+        dsl: String,
+        mdlId: String): String = mkError("runtime", msg, srcName, line, charPos, dsl, mdlId)
+
+    private def mkError(
+        kind: String,
+        msg: String,
+        srcName: String,
+        line: Int,
+        charPos: Int,
+        dsl: String,
+        mdlId: String): String = {
+        val dslLine = dsl.split("\n")(line - 1)
+        val dash = "-" * dslLine.length
+        val pos = Math.max(0, charPos)
+        val posPtr = dash.substring(0, pos) + r("^") + y(dash.substring(pos + 1))
+        val dslPtr = dslLine.substring(0, pos) + r(dslLine.charAt(pos)) + y(dslLine.substring(pos + 1))
+        val aMsg = U.decapitalize(msg) match {
+            case s: String if s.last == '.' ⇒ s
+            case s: String ⇒ s + '.'
+        }
         
+        s"Intent DSL $kind error in '$srcName' at line $line:${charPos + 1} - $aMsg\n" +
+        s"  |-- ${c("Model:")}    $mdlId\n" +
+        s"  |-- ${c("Line:")}     $dslPtr\n" +
+        s"  +-- ${c("Position:")} $posPtr"
+    }
+    
+    /**
+     * Custom error handler.
+     *
+     * @param dsl
+     * @param mdlId
+     */
+    class CompilerErrorListener(dsl: String, mdlId: String) extends BaseErrorListener {
         /**
-          *
-          * @param recognizer
-          * @param offendingSymbol
-          * @param line
-          * @param charPos
-          * @param msg
-          * @param e
-          */
+         *
+         * @param recog
+         * @param badSymbol
+         * @param line
+         * @param charPos
+         * @param msg
+         * @param e
+         */
         override def syntaxError(
-            recognizer: Recognizer[_, _],
-            offendingSymbol: scala.Any,
-            line: Int,
-            charPos: Int,
+            recog: Recognizer[_, _],
+            badSymbol: scala.Any,
+            line: Int, // 1, 2, ...
+            charPos: Int, // 1, 2, ...
             msg: String,
-            e: RecognitionException): Unit = {
-            
-            val errMsg = s"Intent DSL syntax error at line $line:$charPos - $msg\n" +
-                s"  |-- ${c("Model:")}  $mdlId\n" +
-                s"  |-- ${c("Intent:")} $dsl\n" +
-                s"  +-- ${c("Error:")}  ${makeCharPosPointer(dsl.length, charPos)}"
-            
-            throw new NCE(errMsg)
-        }
+            e: RecognitionException): Unit =
+            throw new NCE(mkSyntaxError(msg, recog.getInputStream.getSourceName, line, charPos - 1, dsl, mdlId))
     }
-
+    
     /**
       *
-      * @param dsl Intent DSL to parse.
-      * @param mdlId ID of the model the intent belongs to.
+      * @param dsl
+      * @param mdlId
+      * @param srcName
       * @return
       */
-    def compile(dsl: String, mdlId: String): NCDslIntent = {
+    private def antlr4(
+        dsl: String,
+        mdlId: String,
+        srcName: String
+    ): Set[NCDslIntent] = {
         require(dsl != null)
-        
-        this.mdlId = mdlId
-        
-        val intent: NCDslIntent = cache.getOrElseUpdate(dsl, {
+        require(mdlId != null)
+        require(srcName != null)
+    
+        val aDsl = dsl.strip()
+    
+        val intents: Set[NCDslIntent] = cache.getOrElseUpdate(aDsl, {
             // ANTLR4 armature.
-            val lexer = new NCIntentDslLexer(CharStreams.fromString(dsl))
+            val lexer = new NCIntentDslLexer(CharStreams.fromString(aDsl, srcName))
             val tokens = new CommonTokenStream(lexer)
-            val parser = new NCIntentDslParser(tokens)
-    
+            val parser = new IDP(tokens)
+        
             // Set custom error handlers.
             lexer.removeErrorListeners()
             parser.removeErrorListeners()
-            lexer.addErrorListener(new CompilerErrorListener(dsl))
-            parser.addErrorListener(new CompilerErrorListener(dsl))
-            
+            lexer.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
+            parser.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
+        
             // State automata.
-            val fsm = new FiniteStateMachine
-    
+            val fsm = new FiniteStateMachine(aDsl, mdlId)
+        
             // Parse the input DSL and walk built AST.
-            (new ParseTreeWalker).walk(fsm, parser.intent())
-            
+            (new ParseTreeWalker).walk(fsm, parser.dsl())
+        
             // Return the built intent.
-            val newIntent = fsm.getBuiltIntent
-    
-            // Log for visual verification.
-            logger.debug(s"Intent compiler:")
-            logger.debug(s"  |-- IN  $dsl")
-            logger.debug(s"  |-- OUT ${newIntent.toDslString}")
-    
-            newIntent
+            fsm.getBuiltIntents
         })
-        
-        intent
+    
+        intents
     }
+    
+    /**
+      * Compiles inline (supplied) fragments and/or intents from given file. Note that fragments are
+      * accumulated in a static map keyed by model ID. Only intents are returned, if any.
+      *
+      * @param filePath *.nc DSL file to compile.
+      * @param mdlId ID of the model *.nc file belongs to.
+      * @return
+      */
+    @throws[NCE]
+    def compilePath(
+        filePath: Path,
+        mdlId: String
+    ): Set[NCDslIntent] = antlr4(U.readFile(filePath.toFile).mkString("\n"), mdlId, filePath.getFileName.toString)
+    
+    /**
+      * Compiles inline (supplied) fragments and/or intents. Note that fragments are accumulated in a static
+      * map keyed by model ID. Only intents are returned, if any.
+      *
+      * @param dsl DSL to compile.
+      * @param mdlId ID of the model DSL belongs to.
+      * @return
+      */
+    @throws[NCE]
+    def compile(
+        dsl: String,
+        mdlId: String
+    ): Set[NCDslIntent] = antlr4(dsl, mdlId, "<inline>")
 }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslFragmentCache.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslFragmentCache.scala
similarity index 94%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslFragmentCache.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslFragmentCache.scala
index b079321..601a817 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslFragmentCache.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslFragmentCache.scala
@@ -15,9 +15,9 @@
  * limitations under the License.
  */
 
-package org.apache.nlpcraft.model.intent.impl.ver2
+package org.apache.nlpcraft.model.intent.impl
 
-import org.apache.nlpcraft.model.intent.utils.ver2.NCDslFragment
+import org.apache.nlpcraft.model.intent.utils.NCDslFragment
 
 import scala.collection.concurrent.TrieMap
 import scala.collection.mutable
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala
index 7452555..8c44d00 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala
@@ -219,7 +219,7 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
 
                         // Isolated conversation tokens.
                         val convToks =
-                            if (intent.terms.exists(_.isConversational))
+                            if (intent.terms.exists(_.conv))
                                 Seq.empty[UsedToken] ++
                                     // We shouldn't mix tokens with same group from conversation
                                     // history and processed sentence.
@@ -461,7 +461,7 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
         varIdx: Int
     ): Option[IntentMatch] = {
         val intentId = intent.id
-        val hist = NCDialogFlowManager.getDialogFlow(ctx.getRequest.getUser.getId, ctx.getModel.getId)
+        val flow = NCDialogFlowManager.getDialogFlow(ctx.getRequest.getUser.getId, ctx.getModel.getId)
         val varStr = s"(variant #${varIdx + 1})"
         val flowRegex = intent.flowRegex
 
@@ -470,6 +470,12 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
             logger.info(s"  |-- ${c("Dialog flow:")} ${hist.mkString(" ")}")
             logger.info(s"  +-- ${c("Match regex:")} ${flowRegex.get.toString}")
         }
+        
+        if (intent.)
+        
+        
+        
+        
 
         // Check dialog flow first.
         if (intent.flowRegex.isDefined && !flowRegex.get.matcher(hist.mkString(" ")).find(0)) {
@@ -594,10 +600,10 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
         senToks: Seq[UsedToken],
         convToks: Seq[UsedToken]
     ): Option[TermMatch] =
-        solvePredicate(term.getPredicate, term.getMin, term.getMax, senToks, convToks) match {
+        solvePredicate(term.pred, term.min, term.max, senToks, convToks) match {
             case Some((usedToks, predWeight)) ⇒ Some(
                 TermMatch(
-                    term.getId,
+                    term.id,
                     usedToks,
                     if (usedToks.nonEmpty) {
                         // If term match is non-empty we add the following weights:
@@ -605,19 +611,19 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
                         //   - delta between specified max and normalized max (how close the actual quantity was to the specified one).
                         //   - normalized max
                         predWeight
-                            .append(term.getMin)
-                            .append(-(term.getMax - usedToks.size))
+                            .append(term.min)
+                            .append(-(term.max - usedToks.size))
                             // Normalize max quantifier in case of unbound max.
-                            .append(if (term.getMax == Integer.MAX_VALUE) usedToks.size else term.getMax)
+                            .append(if (term.max == Integer.MAX_VALUE) usedToks.size else term.max)
                     } else {
                         // Term is optional (found but empty).
-                        require(term.getMin == 0)
+                        require(term.min == 0)
 
                         predWeight
                             .append(0)
-                            .append(-term.getMax)
+                            .append(-term.max)
                             // Normalize max quantifier in case of unbound max.
-                            .append(if (term.getMax == Integer.MAX_VALUE) 0 else term.getMax)
+                            .append(if (term.max == Integer.MAX_VALUE) 0 else term.max)
                     }
                 )
             )
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslCompiler.scala
deleted file mode 100644
index 3cdd22d..0000000
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslCompiler.scala
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.nlpcraft.model.intent.impl.ver2
-
-import com.typesafe.scalalogging.LazyLogging
-import org.antlr.v4.runtime._
-import org.antlr.v4.runtime.tree.ParseTreeWalker
-import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.model.intent.impl.antlr4.{NCIntentDslParser ⇒ IDP, _}
-import org.apache.nlpcraft.model.intent.utils.ver2._
-import org.apache.nlpcraft.model._
-import org.apache.nlpcraft.model.intent.impl.ver2.{NCIntentDslFragmentCache ⇒ FragCache}
-
-import java.nio.file.Path
-import java.util.Optional
-import java.util.regex.{Pattern, PatternSyntaxException}
-import scala.collection.mutable
-import scala.collection.mutable.ArrayBuffer
-import scala.collection.JavaConverters._
-
-object NCIntentDslCompiler extends LazyLogging {
-    // Compiler cache.
-    private val cache = new mutable.HashMap[String, Set[NCDslIntent]]
-
-    /**
-     *
-     * @param dsl
-     * @param mdlId
-     */
-    class FiniteStateMachine(dsl: String, mdlId: String) extends NCIntentDslBaseListener with NCIntentDslBaselCompiler {
-        // Accumulator for parsed intents.
-        private val intents = ArrayBuffer.empty[NCDslIntent]
-
-        // Fragment components.
-        private var fragId: String = _
-        private var fragMeta: Map[String, Any] = _
-
-        // Intent components.
-        private var intentId: String = _
-        private var ordered: Boolean = false
-        private var flowRegex: Option[String] = None
-        private var intentMeta: Map[String, Any] = _
-
-        // Accumulator for parsed terms.
-        private val terms = ArrayBuffer.empty[NCDslTerm]
-
-        // Currently term.
-        private var termId: String = _
-        private var termConv: Boolean = _
-        private var min = 1
-        private var max = 1
-
-        // Current method reference.
-        private var refClsName: Option[String] = None
-        private var refMtdName: Option[String] = None
-
-        // Current term's code, i.e. list of instructions.
-        private var termInstrs = mutable.Buffer.empty[Instr]
-
-        /*
-         * Shared/common implementation.
-         */
-        override def exitUnaryExpr(ctx: IDP.UnaryExprContext): Unit = termInstrs += parseUnaryExpr(ctx.MINUS(), ctx.NOT())(ctx)
-        override def exitMultExpr(ctx: IDP.MultExprContext): Unit = termInstrs += parseMultExpr(ctx.MULT(), ctx.MOD(), ctx.DIV())(ctx)
-        override def exitPlusExpr(ctx: IDP.PlusExprContext): Unit = termInstrs += parsePlusExpr(ctx.PLUS(), ctx.MINUS())(ctx)
-        override def exitCompExpr(ctx: IDP.CompExprContext): Unit = termInstrs += parseCompExpr(ctx.LT(), ctx.GT(), ctx.LTEQ(), ctx.GTEQ())(ctx)
-        override def exitLogExpr(ctx: IDP.LogExprContext): Unit = termInstrs += parseLogExpr(ctx.AND, ctx.OR())(ctx)
-        override def exitEqExpr(ctx: IDP.EqExprContext): Unit = termInstrs += parseEqExpr(ctx.EQ, ctx.NEQ())(ctx)
-        override def exitCallExpr(ctx: IDP.CallExprContext): Unit = termInstrs += parseCallExpr(ctx.FUN_NAME())(ctx)
-        override def exitAtom(ctx: IDP.AtomContext): Unit = termInstrs += parseAtom(ctx.getText)(ctx)
-
-        /**
-         *
-         * @param min
-         * @param max
-         */
-        private def setMinMax(min: Int, max: Int): Unit = {
-            this.min = min
-            this.max = max
-        }
-
-        override def exitMinMaxShortcut(ctx: IDP.MinMaxShortcutContext): Unit = {
-            if (ctx.PLUS() != null)
-                setMinMax(1, Integer.MAX_VALUE)
-            else if (ctx.MULT() != null)
-                setMinMax(0, Integer.MAX_VALUE)
-            else if (ctx.QUESTION() != null)
-                setMinMax(0, 1)
-            else
-                assert(false)
-        }
-    
-        override def exitMinMaxRange(ctx: IDP.MinMaxRangeContext): Unit = {
-            val minStr = ctx.getChild(1).getText.trim
-            val maxStr = ctx.getChild(3).getText.trim
-        
-            try
-                setMinMax(java.lang.Integer.parseInt(minStr), java.lang.Integer.parseInt(maxStr))
-            catch {
-                // Errors should be caught during compilation phase.
-                case _: NumberFormatException ⇒ assert(false)
-            }
-        }
-
-        override def exitMtdRef(ctx: IDP.MtdRefContext): Unit = {
-            if (ctx.javaFqn() != null)
-                refClsName = Some(ctx.javaFqn().getText)
-
-            refMtdName = Some(ctx.id().getText)
-        }
-
-        override def exitTermId(ctx: IDP.TermIdContext): Unit = {
-            termId = ctx.id().getText
-    
-            if (terms.exists(t ⇒ t.id != null && t.id == termId))
-                throw newSyntaxError(s"Duplicate term ID: $termId")(ctx.id())
-        }
-    
-        override def exitIntentId(ctx: IDP.IntentIdContext): Unit = {
-            intentId = ctx.id().getText
-    
-            if (intents.exists(i ⇒ i.id != null && i.id == intentId))
-                throw newSyntaxError(s"Duplicate intent ID: $intentId")(ctx.id())
-        }
-    
-        override def exitFragId(ctx: IDP.FragIdContext): Unit = {
-            fragId = ctx.id().getText
-    
-            if (FragCache.get(mdlId, fragId).isDefined)
-                throw newSyntaxError(s"Duplicate fragment ID: $fragId")(ctx.id())
-        }
-
-        override def exitTermEq(ctx: IDP.TermEqContext): Unit =  termConv = ctx.TILDA() != null
-        override def exitFragMeta(ctx: IDP.FragMetaContext): Unit = fragMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
-        override def exitMetaDecl(ctx: IDP.MetaDeclContext): Unit = intentMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
-        override def exitOrderedDecl(ctx: IDP.OrderedDeclContext): Unit = ordered = ctx.BOOL().getText == "true"
-
-        override def exitFragRef(ctx: IDP.FragRefContext): Unit = {
-            val id = ctx.id().getText
-
-            FragCache.get(mdlId, id) match {
-                case Some(frag) ⇒
-                    val meta = if (fragMeta == null) Map.empty[String, Any] else fragMeta
-
-                    for (fragTerm ← frag.terms)
-                         if (terms.exists(t ⇒ t.id != null && t.id == fragTerm.id))
-                            throw newSyntaxError(s"Duplicate term ID '${fragTerm.id}' in fragment '$id'.")(ctx.id())
-                        else
-                            terms += fragTerm.cloneWithMeta(meta)
-
-                case None ⇒ throw newSyntaxError(s"Unknown intent fragment ID: $id")(ctx.id())
-            }
-
-            fragMeta = null
-        }
-
-        override def exitFlowDecl(ctx: IDP.FlowDeclContext): Unit = {
-            implicit val evidence: ParserRuleContext = ctx
-
-            if (ctx.qstring() != null) {
-                val regex = ctx.qstring().getText
-
-                if (regex != null && regex.length > 2)
-                    flowRegex = if (regex.nonEmpty) Some(regex) else None
-
-                if (flowRegex.isDefined) // Pre-check.
-                    try
-                        Pattern.compile(flowRegex.get)
-                    catch {
-                        case e: PatternSyntaxException ⇒
-                            newSyntaxError(s"${e.getDescription} in intent flow regex '${e.getPattern}' near index ${e.getIndex}.")(ctx.qstring())
-                    }
-            }
-        }
-
-        override def exitTerm(ctx: IDP.TermContext): Unit = {
-            implicit val c: ParserRuleContext = ctx
-
-            if (min < 0 || min > max)
-                throw newSyntaxError(s"Invalid intent term min quantifiers: $min (must be min >= 0 && min <= max).")(ctx.minMax())
-            if (max < 1)
-                throw newSyntaxError(s"Invalid intent term max quantifiers: $max (must be max >= 1).")(ctx.minMax())
-
-            val pred =
-                if (refMtdName != null) { // User-code defined term.
-                    // Closure copies.
-                    val clsName = refClsName.orNull
-                    val mtdName = refMtdName.orNull
-
-                    (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
-                        val javaCtx: NCTokenPredicateContext = new NCTokenPredicateContext {
-                            override lazy val getRequest: NCRequest = termCtx.req
-                            override lazy val getToken: NCToken = tok
-                            override lazy val getIntentMeta: Optional[NCMetadata] =
-                                if (termCtx.intentMeta != null)
-                                    Optional.of(NCMetadata.apply(termCtx.intentMeta.asJava))
-                                else
-                                    Optional.empty()
-                        }
-
-                        val mdl = tok.getModel
-                        val mdlCls = if (clsName == null) mdl.meta[String](MDL_META_MODEL_CLASS_KEY) else clsName
-
-                        try {
-                            val obj = if (clsName == null) mdl else U.mkObject(clsName)
-                            val mtd = Thread.currentThread().getContextClassLoader.loadClass(mdlCls)
-                                .getMethod(mtdName, classOf[NCTokenPredicateContext])
-
-                            var flag = mtd.canAccess(mdl)
-
-                            val res = try {
-                                if (!flag) {
-                                    mtd.setAccessible(true)
-
-                                    flag = true
-                                }
-                                else
-                                    flag = false
-
-                                mtd.invoke(obj, javaCtx).asInstanceOf[NCTokenPredicateResult]
-                            }
-                            finally {
-                                if (flag)
-                                    try
-                                        mtd.setAccessible(false)
-                                    catch {
-                                        case e: SecurityException ⇒
-                                            throw new NCE(s"Access or security error in custom intent term: $mdlCls.$mtdName", e)
-                                    }
-                            }
-
-                            (res.getResult, res.wasTokenUsed())
-                        }
-                        catch {
-                            case e: Exception ⇒
-                                throw newRuntimeError(s"Failed to invoke custom intent term: $mdlCls.$mtdName", e)
-                        }
-                    }
-                }
-                else { // DSL-defined term.
-                    val instrs = mutable.Buffer.empty[Instr]
-
-                    instrs ++= termInstrs
-
-                    (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
-                        val stack = new mutable.ArrayStack[NCDslTermRetVal]()
-
-                        // Execute all instructions.
-                        instrs.foreach(_(tok, stack, termCtx))
-
-                        // Pop final result from stack.
-                        val x = stack.pop()
-
-                        if (!isBoolean(x.retVal))
-                            throw newRuntimeError(s"Intent term does not return boolean value: ${ctx.getText}")
-
-                        (asBool(x.retVal), x.usedTok)
-                    }
-
-                }
-                
-            // Add term.
-            terms += NCDslTerm(
-                termId,
-                pred,
-                min,
-                max,
-                termConv
-            )
-
-            // Reset term vars.
-            setMinMax(1, 1)
-            termId = null
-            termInstrs.clear()
-            refClsName = None
-            refMtdName = None
-        }
-
-        override def exitFrag(ctx: IDP.FragContext): Unit = {
-            FragCache.add(mdlId, NCDslFragment(fragId, terms.toList))
-
-            terms.clear()
-        }
-        
-        override def exitIntent(ctx: IDP.IntentContext): Unit = {
-            intents += NCDslIntent(
-                dsl,
-                intentId,
-                ordered,
-                if (intentMeta == null) Map.empty else intentMeta,
-                flowRegex,
-                refClsName,
-                refMtdName,
-                terms.toList
-            )
-
-            refClsName = None
-            refMtdName = None
-            intentMeta = null
-            terms.clear()
-        }
-
-        /**
-         *
-         * @return
-         */
-        def getBuiltIntents: Set[NCDslIntent] = intents.toSet
-        
-        override def syntaxError(errMsg: String, srcName: String, line: Int, pos: Int): NCE =
-            throw new NCE(mkSyntaxError(errMsg, srcName, line, pos, dsl, mdlId))
-        override def runtimeError(errMsg: String, srcName: String, line: Int, pos: Int, cause: Exception = null): NCE =
-            throw new NCE(mkRuntimeError(errMsg, srcName, line, pos, dsl, mdlId), cause)
-    }
-
-    /**
-     *
-     * @param msg
-     * @param line
-     * @param charPos
-     * @param dsl Original DSL text (input).
-     * @param mdlId
-     * @return
-     */
-    private def mkSyntaxError(
-        msg: String,
-        srcName: String,
-        line: Int, // 1, 2, ...
-        charPos: Int, // 0, 1, 2, ...
-        dsl: String,
-        mdlId: String): String = mkError("syntax", msg, srcName, line, charPos, dsl, mdlId)
-
-    /**
-      *
-      * @param msg
-      * @param dsl
-      * @param mdlId
-      * @param srcName
-      * @param line
-      * @param charPos
-      * @return
-      */
-    private def mkRuntimeError(
-        msg: String,
-        srcName: String,
-        line: Int, // 1, 2, ...
-        charPos: Int, // 0, 1, 2, ...
-        dsl: String,
-        mdlId: String): String = mkError("runtime", msg, srcName, line, charPos, dsl, mdlId)
-
-    private def mkError(
-        kind: String,
-        msg: String,
-        srcName: String,
-        line: Int,
-        charPos: Int,
-        dsl: String,
-        mdlId: String): String = {
-        val dslLine = dsl.split("\n")(line - 1)
-        val dash = "-" * dslLine.length
-        val pos = Math.max(0, charPos)
-        val posPtr = dash.substring(0, pos) + r("^") + y(dash.substring(pos + 1))
-        val dslPtr = dslLine.substring(0, pos) + r(dslLine.charAt(pos)) + y(dslLine.substring(pos + 1))
-        val aMsg = U.decapitalize(msg) match {
-            case s: String if s.last == '.' ⇒ s
-            case s: String ⇒ s + '.'
-        }
-        
-        s"Intent DSL $kind error in '$srcName' at line $line:${charPos + 1} - $aMsg\n" +
-        s"  |-- ${c("Model:")}    $mdlId\n" +
-        s"  |-- ${c("Line:")}     $dslPtr\n" +
-        s"  +-- ${c("Position:")} $posPtr"
-    }
-    
-    /**
-     * Custom error handler.
-     *
-     * @param dsl
-     * @param mdlId
-     */
-    class CompilerErrorListener(dsl: String, mdlId: String) extends BaseErrorListener {
-        /**
-         *
-         * @param recog
-         * @param badSymbol
-         * @param line
-         * @param charPos
-         * @param msg
-         * @param e
-         */
-        override def syntaxError(
-            recog: Recognizer[_, _],
-            badSymbol: scala.Any,
-            line: Int, // 1, 2, ...
-            charPos: Int, // 1, 2, ...
-            msg: String,
-            e: RecognitionException): Unit =
-            throw new NCE(mkSyntaxError(msg, recog.getInputStream.getSourceName, line, charPos - 1, dsl, mdlId))
-    }
-    
-    /**
-      *
-      * @param dsl
-      * @param mdlId
-      * @param srcName
-      * @return
-      */
-    private def antlr4(
-        dsl: String,
-        mdlId: String,
-        srcName: String
-    ): Set[NCDslIntent] = {
-        require(dsl != null)
-        require(mdlId != null)
-        require(srcName != null)
-    
-        val aDsl = dsl.strip()
-    
-        val intents: Set[NCDslIntent] = cache.getOrElseUpdate(aDsl, {
-            // ANTLR4 armature.
-            val lexer = new NCIntentDslLexer(CharStreams.fromString(aDsl, srcName))
-            val tokens = new CommonTokenStream(lexer)
-            val parser = new IDP(tokens)
-        
-            // Set custom error handlers.
-            lexer.removeErrorListeners()
-            parser.removeErrorListeners()
-            lexer.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
-            parser.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
-        
-            // State automata.
-            val fsm = new FiniteStateMachine(aDsl, mdlId)
-        
-            // Parse the input DSL and walk built AST.
-            (new ParseTreeWalker).walk(fsm, parser.dsl())
-        
-            // Return the built intent.
-            fsm.getBuiltIntents
-        })
-    
-        intents
-    }
-    
-    /**
-      * Compiles inline (supplied) fragments and/or intents from given file. Note that fragments are
-      * accumulated in a static map keyed by model ID. Only intents are returned, if any.
-      *
-      * @param filePath *.nc DSL file to compile.
-      * @param mdlId ID of the model *.nc file belongs to.
-      * @return
-      */
-    @throws[NCE]
-    def compilePath(
-        filePath: Path,
-        mdlId: String
-    ): Set[NCDslIntent] = antlr4(U.readFile(filePath.toFile).mkString("\n"), mdlId, filePath.getFileName.toString)
-    
-    /**
-      * Compiles inline (supplied) fragments and/or intents. Note that fragments are accumulated in a static
-      * map keyed by model ID. Only intents are returned, if any.
-      *
-      * @param dsl DSL to compile.
-      * @param mdlId ID of the model DSL belongs to.
-      * @return
-      */
-    @throws[NCE]
-    def compile(
-        dsl: String,
-        mdlId: String
-    ): Set[NCDslIntent] = antlr4(dsl, mdlId, "<inline>")
-}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslFragment.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslFragment.scala
similarity index 95%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslFragment.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslFragment.scala
index beb1e74..9831fe9 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslFragment.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslFragment.scala
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
 
 /**
   * DSL fragment.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala
index fd3b32e..6a20e09 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala
@@ -17,50 +17,39 @@
 
 package org.apache.nlpcraft.model.intent.utils
 
-import java.util.regex.{Pattern, PatternSyntaxException}
+import java.util.regex.Pattern
 
 /**
- * Intent from intent DSL.
- *
- * @param id Intent ID.
- * @param ordered Whether or not the order of terms is important for matching.
- * @param flow Optional flow matching regex.
- * @param terms Array of terms comprising this intent.
- */
-case class NCDslIntent(id: String, ordered: Boolean, flow: Option[String], terms: Array[NCDslTerm]) {
-    if (id == null)
-        throw new IllegalArgumentException("Intent ID must be provided.")
-    if (terms.length == 0)
-        throw new IllegalArgumentException("Intent should have at least one term.")
+ * DSL intent.
+  *
+  * @param dsl Original DSL of this intent.
+  * @param id
+  * @param ordered
+  * @param meta
+  * @param flow
+  * @param terms
+  */
+case class NCDslIntent(
+    dsl: String,
+    id: String,
+    ordered: Boolean,
+    meta: Map[String, Any],
+    flow: Option[String],
+    flowClsName: Option[String],
+    flowMtdName: Option[String],
+    terms: List[NCDslTerm]
+) {
+    require(id != null)
+    require(terms.nonEmpty)
+    require(meta != null)
 
     // Flow regex as a compiled pattern.
-    val flowRegex = flow match {
-        case Some(r) ⇒
-            try
-                Some(Pattern.compile(r))
-            catch {
-                case e: PatternSyntaxException ⇒
-                    throw new IllegalArgumentException(s"${e.getDescription} in flow regex '${e.getPattern}' near index ${e.getIndex}.")
-            }
-
+    // Regex validity check is already done during intent compilation.
+    lazy val flowRegex = flow match {
+        case Some(r) ⇒ Some(Pattern.compile(r))
         case None ⇒ None
     }
 
     override def toString: String =
-        s"Intent: '$id'"
-
-    /**
-     * Gets full intent string representation in text DSL format.
-     *
-     * @return Full intent string representation in text DSL format.
-     */
-    def toDslString: String = {
-        val orderedStr = if (!ordered) "" else " ordered=true"
-        val flowStr = flow match {
-            case Some(r) ⇒ s" flow='$r'"
-            case None ⇒ ""
-        }
-
-        s"intent=$id$orderedStr$flowStr ${terms.mkString(" ")}"
-    }
+        s"intent=$id"
 }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.java
deleted file mode 100644
index 4192da8..0000000
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.nlpcraft.model.intent.utils;
-
-import org.apache.nlpcraft.model.*;
-import java.io.*;
-import java.util.function.*;
-
-/**
- * Internal DSL intent term representation.
- */
-public class NCDslTerm implements Serializable {
-    // Term's predicate.
-    final private Function<NCToken, Boolean> pred;
-
-    // Conversational or not.
-    final private boolean conv;
-
-    // Terms quantifiers.
-    final private int min, max;
-
-    // Optional term ID.
-    final private String id;
-
-    /**
-     * Creates new term with given predicate and quantifiers.
-     *
-     * @param id Optional term ID.
-     * @param pred Token predicate.
-     * @param min Minimum quantifier for the predicate (inclusive).
-     * @param max Maximum quantifier for the predicate (inclusive).
-     * @param conv Whether or not this term is conversational.
-     */
-    public NCDslTerm(String id, Function<NCToken, Boolean> pred, int min, int max, boolean conv) {
-        if (pred == null)
-            throw new IllegalArgumentException("Intent DSL term predicate cannot be null.");
-        if (min < 0 || min > max)
-            throw new IllegalArgumentException(String.format(
-                "Invalid intent DSL term min quantifiers: %d (must be min >= 0 && min <= max).", min));
-        if (max < 1)
-            throw new IllegalArgumentException(String.format(
-                "Invalid intent DSL term max quantifiers: %d (must be max >= 1).", max));
-
-        this.id = id;
-        this.pred = pred;
-        this.min = min;
-        this.max = max;
-        this.conv = conv;
-    }
-
-    /**
-     * Gets term's predicate.
-     *
-     * @return Term's predicate.
-     */
-    public Function<NCToken, Boolean> getPredicate() {
-        return pred;
-    }
-
-    /**
-     * Gets optional term ID.
-     *
-     * @return Term ID or {@code null} if not specified.
-     */
-    public String getId() {
-        return id;
-    }
-
-    /**
-     * Gets min quantifier for this term.
-     *
-     * @return Min quantifier for this term.
-     */
-    public int getMin() {
-        return min;
-    }
-
-    /**
-     * Gets max quantifier for this term.
-     *
-     * @return Max quantifier for this term.
-     */
-    public int getMax() {
-        return max;
-    }
-
-    /**
-     * Whether or not this term support conversational context.
-     *
-     * @return {@code true} if this term supports conversational context, {@code false} otherwise.
-     */
-    public boolean isConversational() { return conv; }
-
-    @Override
-    public String toString() {
-        String minMax;
-
-        if (min == 1 && max == 1)
-            minMax = "";
-        else if (min == 0 && max == 1)
-            minMax = "?";
-        else if (min == 0 && max == Integer.MAX_VALUE)
-            minMax = "*";
-        else if (min == 1 && max == Integer.MAX_VALUE)
-            minMax = "+";
-        else
-            minMax = String.format("[%d,%d]", min, max);
-
-        String eq = conv ? "~" : "=";
-
-        if (id == null)
-            return String.format("term%s{%s}%s", eq, pred, minMax);
-        else
-            return String.format("term(%s)%s{%s}%s", id, eq, pred, minMax);
-    }
-}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTerm.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.scala
similarity index 96%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTerm.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.scala
index 79a5ed2..f757511 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTerm.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.scala
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
 
 import org.apache.nlpcraft.model.NCToken
 
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermContext.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermContext.scala
similarity index 96%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermContext.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermContext.scala
index 291ae9a..e903854 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermContext.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermContext.scala
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
 
 import org.apache.nlpcraft.common.ScalaMeta
 import org.apache.nlpcraft.model.NCRequest
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermRetVal.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermRetVal.scala
similarity index 94%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermRetVal.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermRetVal.scala
index 1030416..8eb3a7c 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermRetVal.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermRetVal.scala
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
 
 /**
  *
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslIntent.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslIntent.scala
deleted file mode 100644
index 5053661..0000000
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslIntent.scala
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.nlpcraft.model.intent.utils.ver2
-
-import java.util.regex.Pattern
-
-/**
- * DSL intent.
-  *
-  * @param dsl Original DSL of this intent.
-  * @param id
-  * @param ordered
-  * @param meta
-  * @param flow
-  * @param terms
-  */
-case class NCDslIntent(
-    dsl: String,
-    id: String,
-    ordered: Boolean,
-    meta: Map[String, Any],
-    flow: Option[String],
-    flowClsName: Option[String],
-    flowMtdName: Option[String],
-    terms: List[NCDslTerm]
-) {
-    require(id != null)
-    require(terms.nonEmpty)
-    require(meta != null)
-
-    // Flow regex as a compiled pattern.
-    // Regex validity check is already done during intent compilation.
-    lazy val flowRegex = flow match {
-        case Some(r) ⇒ Some(Pattern.compile(r))
-        case None ⇒ None
-    }
-
-    override def toString: String =
-        s"intent=$id"
-}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala
index 825c556..3ab3d6a 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala
@@ -134,28 +134,14 @@ object NCDialogFlowManager extends NCService {
     }
 
     /**
-     * Gets sequence of intent ID sorted from oldest to newest (i.e. dialog flow) for given user and model IDs.
-     *
-     * @param usrId User ID.
-     * @param mdlId Model ID.
-     * @return Dialog flow.
-     */
-    def getStringFlow(usrId: Long, mdlId: String, parent: Span = null): Seq[String] =
-        startScopedSpan("getStringFlow", parent, "usrId" → usrId, "mdlId" → mdlId) { _ ⇒
-            flow.synchronized {
-                flow.getOrElseUpdate(Key(usrId, mdlId), mutable.ArrayBuffer.empty[NCDialogFlowItem]).map(_.getIntentId)
-            }
-        }
-    
-    /**
       * Gets sequence of dialog flow items sorted from oldest to newest (i.e. dialog flow) for given user and model IDs.
       *
       * @param usrId User ID.
       * @param mdlId Model ID.
       * @return Dialog flow.
       */
-    def getItemFlow(usrId: Long, mdlId: String, parent: Span = null): Seq[NCDialogFlowItem] =
-        startScopedSpan("getItemFlow", parent, "usrId" → usrId, "mdlId" → mdlId) { _ ⇒
+    def getDialogFlow(usrId: Long, mdlId: String, parent: Span = null): Seq[NCDialogFlowItem] =
+        startScopedSpan("getDialogFlow", parent, "usrId" → usrId, "mdlId" → mdlId) { _ ⇒
             flow.synchronized {
                 flow.getOrElseUpdate(Key(usrId, mdlId), mutable.ArrayBuffer.empty[NCDialogFlowItem])
             }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala
index 2a70932..9aec9cc 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala
@@ -586,7 +586,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats {
 
             override lazy val getConversation: NCConversation = new NCConversation {
                 override def getTokens: util.List[NCToken] = conv.getTokens()
-                override def getDialogFlow: util.List[NCDialogFlowItem] = NCDialogFlowManager.getItemFlow(usrId, mdlId, span).asJava
+                override def getDialogFlow: util.List[NCDialogFlowItem] = NCDialogFlowManager.getDialogFlow(usrId, mdlId, span).asJava
                 override def clearStm(filter: Predicate[NCToken]): Unit = conv.clearTokens(filter)
                 override def clearDialog(filter: Predicate[String]): Unit = NCDialogFlowManager.clear(usrId, mdlId, span)
                 override def getMetadata = conv.getUserData
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala
index 2f592ee..fdbcb31 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala
@@ -18,7 +18,8 @@
 package org.apache.nlpcraft.model.intent.dsl
 
 import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.model.intent.impl.ver2.{NCIntentDslCompiler, NCIntentDslFragmentCache}
+import org.apache.nlpcraft.model.intent.impl.{NCIntentDslCompiler, NCIntentDslFragmentCache}
+import org.apache.nlpcraft.model.intent.impl.ver2.NCIntentDslFragmentCache
 import org.junit.jupiter.api.Test
 
 import java.nio.file.{Path, Paths}