Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/colang various improvements #431

Merged
merged 6 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions examples/v2_x/tutorial/guardrails_1/rails.co
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import guardrails
import core
import llm
import utils


flow user express greeting
flow user expressed greeting
user said "hi" or user said "hello"

flow bot expressed greeting
flow bot express greeting
bot say "Hello world!"

flow greeting
user express greeting
bot expressed greeting
user expressed greeting
bot express greeting

flow input rails $input_text
$input_safe = await self check input $input_text
Expand All @@ -39,6 +38,4 @@ flow self check input $input_text -> $input_safe

flow main
activate llm continuation
activate greeting

wait indefinitely
activate greeting
12 changes: 5 additions & 7 deletions examples/v2_x/tutorial/hello_world_3/rails.co
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import core
import llm
import utils

flow user express greeting

flow user expressed greeting
user said "hi" or user said "hello"

flow bot expressed greeting
flow bot express greeting
bot say "Hello world!"

flow greeting
user express greeting
bot expressed greeting
user expressed greeting
bot express greeting

flow main
activate llm continuation
activate greeting

wait indefinitely
8 changes: 3 additions & 5 deletions examples/v2_x/tutorial/interaction_loop/main.co
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import avatars

flow main
activate polling llm request response 1.0
activate generating user intent for unhandled user utterance
activate tracking bot talking state

while True
when unhandled user intent
Expand All @@ -17,10 +15,10 @@ flow main
bot inform "That was fun. Goodbye"

flow user expressed greeting
user said "Hi"
or user said "Hello"
user said "hi"
or user said "hello"

flow user expressed goodbye
user said "Goodbye"
user said "goodbye"
or user said "I am done"
or user said "I have to go"
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ flow user expressed greeting
or user gestured "Greeting gesture"

flow user expressed verbal greeting
user said "Hi"
or user said "Hello"
user said "hi"
or user said "hello"

flow bot express greeting
bot express verbal greeting
Expand Down
22 changes: 0 additions & 22 deletions nemoguardrails/actions/llm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,28 +233,6 @@ def get_colang_history(
if action_group:
new_history.append(events_to_dialog_history(action_group))

# We make sure that there is not empty line between `user action` and `user intent`.
# TODO: check this does not break existing history.
i = 0
while i < len(new_history) - 2:
if (
new_history[i].startswith("user action")
and new_history[i + 1].strip() == ""
and new_history[i + 2].startswith("user intent")
):
del new_history[i + 1]

# Swap bot action and intent as well if found
if (
new_history[i].startswith("bot action")
and new_history[i + 1].strip() == ""
and new_history[i + 2].startswith("bot intent")
):
del new_history[i + 1]
new_history[i], new_history[i + 1] = new_history[i + 1], new_history[i]

i += 1

history = "\n".join(new_history).rstrip("\n")

return history
Expand Down
6 changes: 5 additions & 1 deletion nemoguardrails/colang/v2_x/library/avatars.co
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ flow handling bot talking interruption $mode="inform"
# ----------------------------------

@loop("llm_response_polling")
flow polling llm request response $interval
flow polling llm request response $interval=1.0
match StartGenerateUserIntentAction() as $event_ref
or StartGenerateFlowContinuationAction() as $event_ref
or StartGenerateFlowFromNameAction() as $event_ref
Expand All @@ -448,7 +448,9 @@ flow polling llm request response $interval

flow generating user intent for unhandled user utterance
"""This is the fallback flow that takes care of unhandled user utterances and will generate a user intent."""
activate tracking bot talking state
global $bot_talking_state

match UnhandledEvent(event="UtteranceUserActionFinished", loop_ids={$self.loop_id}) as $event
if $bot_talking_state == False
$transcript = $event.final_transcript
Expand All @@ -465,10 +467,12 @@ flow generating user intent for unhandled user utterance
send FinishFlow(flow_id=$intent)

flow derive user intent from user action $user_action $max_example_flows -> $intent
activate polling llm request response
$intent = await GenerateUserIntentAction(user_action=$user_action, max_example_flows=$max_example_flows)
return $intent

flow generate interaction continuation -> $flow_name
activate polling llm request response
# Generate continuation based current interaction history
$flow_info = await GenerateFlowContinuationAction(temperature=0.1)

Expand Down
6 changes: 0 additions & 6 deletions nemoguardrails/colang/v2_x/library/core.co
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,13 @@ flow _bot_say $text

# PUBLIC

@meta(user_action='user said "{$transcript}"')
flow user said $text -> $transcript
_user_said $text as $user_said
$transcript = $user_said.event.final_transcript

@meta(user_action=True)
flow user said something -> $transcript
_user_said as $user_said
send UserActionLog(flow_id="user said", parameter=$user_said.event.final_transcript, intent_flow_id="user said something")
$transcript = $user_said.event.final_transcript

return $transcript

@meta(bot_action=True)
flow bot say $text
await _bot_say $text
49 changes: 39 additions & 10 deletions nemoguardrails/colang/v2_x/library/llm.co
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,47 @@
import utils


@loop(id="auto_log")
@loop(id="action_log")
flow log user action
"""Record user actions to the interaction log."""
match FlowFinished(flow_id=regex("^user said")) as $event
$info = flows_info($event.flow.uid)
$count = 1
while $count < len($info.flow_hierarchy)
$intent_flow_uid = $info.flow_hierarchy[$count]
$intent_flow_name = find_all("\((user (?!said).*)\)", $intent_flow_uid)
if $intent_flow_name
send UserActionLog(flow_id=$event.flow_id, parameter=$event.flow.transcript, intent_flow_id=$intent_flow_name[0])
break
$count = $count + 1

@loop(id="intent_log")
flow log user intent
"""Record user intents to the interaction log."""
match FlowFinished(flow_id=regex("^user ")) as $event
if $event.flow_id not in ["user said"]
send UserIntentLog(flow_id=$event.flow_id, parameter=None)


@loop(id="auto_log")
match FlowFinished(flow_id=regex("^user (?!said)")) as $event
send UserIntentLog(flow_id=$event.flow_id, parameter=None)


@loop(id="action_log")
flow log bot action
"""Record bot actions to the interaction log."""
match FlowFinished(flow_id=regex("^bot say")) as $event
$info = flows_info($event.flow.uid)
$count = 1
while $count < len($info.flow_hierarchy)
$intent_flow_uid = $info.flow_hierarchy[$count]
$intent_flow_name = find_all("\((bot (?!say).*)\)", $intent_flow_uid)
if $intent_flow_name
send BotActionLog(flow_id=$event.flow_id, parameter=$event.text, intent_flow_id=$intent_flow_name[0])
break
$count = $count + 1


@loop(id="intent_log")
flow log bot intent
"""Record bot intents to the interaction log."""
match FlowFinished(flow_id=regex("^bot ")) as $event
if $event.flow_id not in ["bot say"]
send BotIntentLog(flow_id=$event.flow_id, parameter=None)
match FlowFinished(flow_id=regex("^bot (?!say)")) as $event
send BotIntentLog(flow_id=$event.flow_id, parameter=None)


flow unhandled user utterance -> $event
Expand Down Expand Up @@ -75,7 +102,9 @@ flow continue on undefined flow


flow llm continuation
activate log user action
activate log user intent
activate log bot action
activate log bot intent

activate continue on undefined user utterance
Expand Down
2 changes: 1 addition & 1 deletion nemoguardrails/colang/v2_x/library/utils.co
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ flow wait indefinitely
match NeverComingEvent()

@loop("NEW")
flow wait $time_s $timer_id="wait_timer_{{uid()}}"
flow wait $time_s $timer_id = "wait_timer_{uid()}"
"""Wait the specified number of seconds before continuing."""
await TimerBotAction(timer_name=$timer_id, duration=$time_s)

Expand Down
10 changes: 5 additions & 5 deletions nemoguardrails/colang/v2_x/runtime/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,14 @@ def eval_expression(expr: str, context: dict) -> Any:
# TODO: replace this with something even more restrictive.
functions: Dict[str, Callable] = {
"len": len,
"flow": system_functions.flow,
"action": system_functions.action,
"flow": system_functions.flow, # TODO: Consider this to remove
"action": system_functions.action, # TODO: Consider this to remove
"regex": _create_regex,
"search": _regex_search,
"find_all": _regex_findall,
"uid": new_uid,
"str": _to_str,
"simple_str": _simple_str,
"pretty_str": _pretty_str,
"escape": _escape_string,
"is_int": _is_int,
"is_float": _is_float,
Expand Down Expand Up @@ -188,7 +188,7 @@ def _to_str(data: Any) -> str:
return str(data)


def _simple_str(data: Any) -> str:
def _pretty_str(data: Any) -> str:
if isinstance(data, (dict, list, set)):
string = json.dumps(data, indent=4)
return SimplifyFormatter().format(string)
Expand Down Expand Up @@ -271,7 +271,7 @@ def _flows_info(state: State, flow_instance_uid: Optional[str] = None) -> dict:
def _flow_state_related_to_source(state: State, flow_state: FlowState):
flow_config = state.flow_configs[flow_state.flow_id]
flow_head_source_lines: Set[int] = set()
for head in flow_state.heads.values():
for head in flow_state.active_heads.values():
element = flow_config.elements[head.position]
if isinstance(element, Element) and element._source is not None:
flow_head_source_lines.add(element._source.line)
Expand Down
Loading
Loading