Skip to content

Commit 8cac16a

Browse files
Switch to native support for `..."<NLD>" and multiline string expressions
1 parent c3a8f63 commit 8cac16a

File tree

8 files changed

+105
-25
lines changed

8 files changed

+105
-25
lines changed

examples/v2_x/language_reference/use_llms/interaction_loop/main.co

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ flow main
1010
when unhandled user intent
1111
llm continue interaction
1212
or when user was silent 12.0
13-
$response = i"A random fun fact"
13+
$response = ..."A random fun fact"
1414
bot say $response
1515
or when user expressed greeting
1616
bot say "Hi there!"

examples/v2_x/tutorial/guardrails_1/rails.co

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ flow input rails $input_text
2424
abort
2525

2626
flow check user utterance $input_text -> $input_safe
27-
$is_safe = i"Consider the following user utterance: '{$input_text}'. Assign 'True' if appropriate, 'False' if inappropriate."
27+
$is_safe = ..."Consider the following user utterance: '{$input_text}'. Assign 'True' if appropriate, 'False' if inappropriate."
2828
print $is_safe
2929
return $is_safe

nemoguardrails/colang/v2_x/lang/expansion.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@
4141
)
4242
from nemoguardrails.colang.v2_x.runtime.errors import ColangSyntaxError
4343
from nemoguardrails.colang.v2_x.runtime.flows import FlowConfig, InternalEvents
44-
from nemoguardrails.colang.v2_x.runtime.utils import new_var_uid
44+
from nemoguardrails.colang.v2_x.runtime.utils import (
45+
escape_special_string_characters,
46+
new_var_uid,
47+
)
4548

4649

4750
def expand_elements(
@@ -653,11 +656,12 @@ def _expand_assignment_stmt_element(element: Assignment) -> List[ElementType]:
653656
new_elements: List[ElementType] = []
654657

655658
# Check if the expression is an NLD instruction
656-
nld_instruction_pattern = r"^\s*i\"(.*)\"|^\s*i'(.*)'"
659+
nld_instruction_pattern = r'\.\.\.("""|\'\'\'|"|\')((?:\\\1|(?!\1)[\s\S])*?)\1'
657660
match = re.search(nld_instruction_pattern, element.expression)
658661

659662
if match:
660663
# Replace the assignment with the GenerateValueAction system action
664+
instruction = escape_special_string_characters(match.group(2))
661665
new_elements.append(
662666
SpecOp(
663667
op="await",
@@ -666,7 +670,7 @@ def _expand_assignment_stmt_element(element: Assignment) -> List[ElementType]:
666670
spec_type=SpecType.ACTION,
667671
arguments={
668672
"var_name": f'"{element.key}"',
669-
"instructions": f'"{match.group(1) or match.group(2)}"',
673+
"instructions": f'"{instruction}"',
670674
},
671675
),
672676
return_var_name=element.key,

nemoguardrails/colang/v2_x/lang/grammar/colang.lark

+2-2
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ _NEWLINE: (/\r?\n[\t ]*/)+
221221

222222
// Primitive values
223223

224-
STRING: /i?("(?!"").*?(?<!\\)(\\\\)*?"|i?'(?!'').*?(?<!\\)(\\\\)*?')/i
225-
LONG_STRING: /(""".*?(?<!\\)(\\\\)*?"""|'''.*?(?<!\\)(\\\\)*?''')/is
224+
STRING: /(\.\.\.)?("(?!"").*?(?<!\\)(\\\\)*?"|(\.\.\.)?'(?!'').*?(?<!\\)(\\\\)*?')/i
225+
LONG_STRING: /(\.\.\.)?(""".*?(?<!\\)(\\\\)*?"""|(\.\.\.)?'''.*?(?<!\\)(\\\\)*?''')/is
226226

227227
_SPECIAL_DEC: "0".."9" ("_"? "0".."9" )*
228228
DEC_NUMBER: "1".."9" ("_"? "0".."9" )*

nemoguardrails/colang/v2_x/lang/parser.py

-3
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@ def _apply_pre_parsing_expansions(content: str):
5959
6060
Currently, only the "..." is expanded.
6161
"""
62-
# Replace ..."NLD" with i"NLD"
63-
content = re.sub(r"\.\.\.(['\"])(.*?)\1", r'i"\2"', content)
64-
6562
# We make sure to capture the correct indentation level and use that.
6663
content = re.sub(
6764
r"\n( +)\.\.\.",

nemoguardrails/colang/v2_x/runtime/eval.py

+8-15
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
from nemoguardrails.colang.v2_x.runtime import system_functions
2727
from nemoguardrails.colang.v2_x.runtime.errors import ColangValueError
2828
from nemoguardrails.colang.v2_x.runtime.flows import FlowState, State
29-
from nemoguardrails.colang.v2_x.runtime.utils import AttributeDict
29+
from nemoguardrails.colang.v2_x.runtime.utils import (
30+
AttributeDict,
31+
escape_special_string_characters,
32+
)
3033
from nemoguardrails.eval.cli.simplify_formatter import SimplifyFormatter
3134
from nemoguardrails.utils import new_uid
3235

@@ -90,20 +93,10 @@ def eval_expression(expr: str, context: dict) -> Any:
9093
f"Error evaluating inner expression: '{inner_expression}'"
9194
) from ex
9295

93-
# Escape quotation characters
94-
value = str(value).replace("'", "\\'").replace('"', '\\"')
95-
96-
# Escape escaped characters
97-
escaped_characters_map = {
98-
"\n": "\\n",
99-
"\t": "\\t",
100-
"\r": "\\r",
101-
"\b": "\\b",
102-
"\f": "\\f",
103-
"\v": "\\v",
104-
}
105-
for c, s in escaped_characters_map.items():
106-
value = str(value).replace(c, s)
96+
value = str(value)
97+
98+
# Escape special characters
99+
value = escape_special_string_characters(value)
107100

108101
inner_expression_values.append(value)
109102
string_expression = re.sub(

nemoguardrails/colang/v2_x/runtime/utils.py

+21
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16+
import re
1617
import uuid
1718

1819

@@ -40,3 +41,23 @@ def new_readable_uid(name: str) -> str:
4041
def new_var_uid() -> str:
4142
"""Creates a new uuid that is compatible with variable names."""
4243
return str(uuid.uuid4()).replace("-", "_")
44+
45+
46+
def escape_special_string_characters(string: str) -> str:
47+
"""Escapes all occurrences of special characters."""
48+
# Replace " or ' with \\" or \\' if not already escaped
49+
string = re.sub(r"(^|[^\\])('|\")", r"\1\\\2", string)
50+
# Replace other special characters
51+
escaped_characters_map = {
52+
"\n": "\\n",
53+
"\t": "\\t",
54+
"\r": "\\r",
55+
"\b": "\\b",
56+
"\f": "\\f",
57+
"\v": "\\v",
58+
}
59+
60+
for c, s in escaped_characters_map.items():
61+
string = str(string).replace(c, s)
62+
63+
return string
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import logging
17+
18+
from rich.logging import RichHandler
19+
20+
from nemoguardrails import RailsConfig
21+
from tests.utils import TestChat
22+
23+
FORMAT = "%(message)s"
24+
logging.basicConfig(
25+
level=logging.DEBUG,
26+
format=FORMAT,
27+
datefmt="[%X,%f]",
28+
handlers=[RichHandler(markup=True)],
29+
)
30+
31+
32+
def test_1():
33+
"""Test use of expression as statements."""
34+
config = RailsConfig.from_content(
35+
colang_content="""
36+
flow main
37+
match UtteranceUserActionFinished()
38+
$v1 = ..."Generate the company' name\\" from users input"
39+
$v2 = ...'Generate the company\\' name" from users input'
40+
$v3 = ...'''Generate the company' name" from users input'''
41+
$v4 = ...'''Generate the company'
42+
name" from users input'''
43+
44+
await UtteranceBotAction(script="{$v1}{$v2}{$v3}{$v4}")
45+
""",
46+
yaml_content="""
47+
colang_version: "2.x"
48+
models:
49+
- type: main
50+
engine: openai
51+
model: gpt-3.5-turbo-instruct
52+
""",
53+
)
54+
55+
chat = TestChat(
56+
config,
57+
llm_completions=["'1'", "'2'", "'3'", "'4'"],
58+
)
59+
60+
chat >> "hi"
61+
chat << "1234"
62+
63+
64+
if __name__ == "__main__":
65+
test_1()

0 commit comments

Comments
 (0)