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 flow context sharing #418

Merged
merged 7 commits into from
Mar 25, 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
34 changes: 32 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
},
{
"name": "Debug story (current directory)",
"name": "Debug story very verbose (current directory)",
"type": "debugpy",
"request": "launch",
"console": "integratedTerminal",
Expand All @@ -29,7 +29,25 @@
}
},
{
"name": "Run story verbose (current directory)",
"name": "Debug story verbose (current directory)",
"type": "debugpy",
"request": "launch",
"console": "integratedTerminal",
"module": "nemoguardrails",
"args": [
"chat",
"--config=${fileDirname}",
"--verbose",
"--verbose-llm-calls",
"--debug-level=INFO"
],
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"
}
},
{
"name": "Debug story (current directory)",
"type": "debugpy",
"request": "launch",
"console": "integratedTerminal",
Expand All @@ -40,6 +58,18 @@
"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"
}
},
{
"name": "Run story verbose (current directory)",
"type": "debugpy",
"request": "launch",
"console": "integratedTerminal",
"module": "nemoguardrails",
"args": ["chat", "--config=${fileDirname}", "--verbose-llm-calls"],
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"
}
},
{
"name": "Run story (current directory)",
"type": "debugpy",
Expand Down
7 changes: 2 additions & 5 deletions nemoguardrails/actions/v2_x/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@
)
from nemoguardrails.colang.v2_x.lang.colang_ast import Flow
from nemoguardrails.colang.v2_x.lang.utils import new_uuid
from nemoguardrails.colang.v2_x.runtime.flows import (
ActionEvent,
InternalEvent,
LlmResponseError,
)
from nemoguardrails.colang.v2_x.runtime.errors import LlmResponseError
from nemoguardrails.colang.v2_x.runtime.flows import ActionEvent, InternalEvent
from nemoguardrails.colang.v2_x.runtime.statemachine import (
Event,
InternalEvents,
Expand Down
31 changes: 22 additions & 9 deletions nemoguardrails/colang/v2_x/lang/expansion.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@
When,
While,
)
from nemoguardrails.colang.v2_x.runtime.flows import (
ColangSyntaxError,
FlowConfig,
InternalEvents,
)
from nemoguardrails.colang.v2_x.runtime.errors import ColangSyntaxError
from nemoguardrails.colang.v2_x.runtime.flows import FlowConfig, InternalEvents
from nemoguardrails.colang.v2_x.runtime.utils import new_var_uid


Expand Down Expand Up @@ -169,11 +166,19 @@ def _expand_start_element(
# Single element
if element.spec.spec_type == SpecType.FLOW and element.spec.members is None:
# It's a flow
# send StartFlow(flow_id="FLOW_NAME")
# $_instance_<uid> = (<flow_id>)<uid>
instance_uid_variable_name = f"_instance_uid_{new_var_uid()}"
new_elements.append(
Assignment(
key=instance_uid_variable_name,
expression=f"'({element.spec.name}){{uid()}}'",
)
)
# send StartFlow(flow_id=<flow_id>, flow_instance_uid=$_instance_<uid>)
element.spec.arguments.update(
{
"flow_id": f"'{element.spec.name}'",
"flow_instance_uid": f"'{new_var_uid()}'",
"flow_instance_uid": f"'{{${instance_uid_variable_name}}}'",
}
)
new_elements.append(
Expand Down Expand Up @@ -582,11 +587,19 @@ def _expand_activate_element(
element_copy = copy.deepcopy(element)
# TODO: Remove assert once SpecOp type is refactored
assert isinstance(element_copy.spec, Spec)
# $_instance_<uid> = (<flow_id>)<uid>
instance_uid_variable_name = f"_instance_uid_{new_var_uid()}"
new_elements.append(
Assignment(
key=instance_uid_variable_name,
expression=f"'({element.spec.name}){{uid()}}'",
)
)
element_copy.spec.arguments.update(
{
"flow_id": f"'{element.spec.name}'",
"flow_instance_uid": f"'{new_var_uid()}'",
"activated": True,
"flow_instance_uid": f"'{{${instance_uid_variable_name}}}'",
"activated": "True",
}
)
new_elements.append(
Expand Down
17 changes: 10 additions & 7 deletions nemoguardrails/colang/v2_x/library/avatars.co
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
# - Internal events: new_flow_start_uid -> new_flow_instance_uid
# - Cleanup and improvements of certain log and print statements
#-------
# 0.2.1 (3/20/2024)
# - Introduce $self variable to access flow attributes like loop_id
#-------
################################################################

# -----------------------------------
Expand Down Expand Up @@ -59,7 +62,7 @@ flow user said something -> $transcript
$transcript = $event.final_transcript

flow user said something unexpected -> $transcript
match UnhandledEvent(event="UtteranceUserActionFinished", loop_ids={$loop_id}) as $event
match UnhandledEvent(event="UtteranceUserActionFinished", loop_ids={$self.loop_id}) as $event
send UserActionLog(flow_id="user said", parameter=$event.final_transcript, intent_flow_id=None)
$transcript = $event.final_transcript

Expand All @@ -79,7 +82,7 @@ flow user has selected choice $choice_id
match VisualChoiceSceneAction.ChoiceUpdated(current_choice=[$choice_id]) as $event

flow unhandled user intent -> $intent
match UnhandledEvent(event="FinishFlow", flow_id=regex("^user "), loop_ids={$loop_id}) as $event
match UnhandledEvent(event="FinishFlow", flow_id=regex("^user "), loop_ids={$self.loop_id}) as $event
$intent = $event.flow_id

@loop("user_was_silent")
Expand Down Expand Up @@ -399,7 +402,7 @@ flow repeating timer $timer_id $interval_s
# await TimerBotAction(timer_name=$timer_id, duration=$interval_s)

flow await_flow_by_name $flow_name
$new_flow_instance_uid = "{uid()}"
$new_flow_instance_uid = "($flow_name){uid()}"
send StartFlow(flow_id=$flow_name, flow_instance_uid=$new_flow_instance_uid)
match FlowStarted(flow_id=$flow_name, flow_instance_uid=$new_flow_instance_uid) as $event_ref
match $event_ref.flow.Finished()
Expand Down Expand Up @@ -436,7 +439,7 @@ 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."""
global $bot_talking_state
match UnhandledEvent(event="UtteranceUserActionFinished", loop_ids={$loop_id}) as $event
match UnhandledEvent(event="UtteranceUserActionFinished", loop_ids={$self.loop_id}) as $event
if $bot_talking_state == False
$transcript = $event.final_transcript
log "generating user intent for unhandled user utterance: {$transcript}"
Expand Down Expand Up @@ -497,7 +500,7 @@ flow handling start of undefined flow
if search('^user ',$event.flow_id)

# We have an undefined user intent, so we just fake it to be started by this fallback flow
send FlowStarted(flow_id=$event.flow_id, flow_instance_uid=$event.arguments.flow_instance_uid)
send FlowStarted(flow_id=$event.flow_id, flow_instance_uid=$event.flow_instance_uid)
# Once this fallback flow receives the user intent it will finish and therefore also trigger the original matcher
match FlowFinished(flow_id=$event.flow_id)

Expand All @@ -508,7 +511,7 @@ flow handling start of undefined flow
$flow_source = await GenerateFlowFromNameAction(name=$event.flow_id)

await AddFlowsAction(config=$flow_source)
$new_flow_instance_uid = "{uid()}"
$new_flow_instance_uid = "($event.flow_id){uid()}"
send StartFlow(flow_id=$event.flow_id, flow_instance_uid=$new_flow_instance_uid)
match FlowStarted(flow_id=$event.flow_id, flow_instance_uid=$new_flow_instance_uid) as $event_ref
match $event_ref.flow.Finished()
Expand All @@ -520,7 +523,7 @@ flow execute llm instruction $instructions

await AddFlowsAction(config=$flow_info.body)

$new_flow_instance_uid = "{uid()}"
$new_flow_instance_uid = "($flow_info.name){uid()}"
send StartFlow(flow_id=$flow_info.name, flow_instance_uid=$new_flow_instance_uid)
match FlowStarted(flow_id=$flow_info.name, flow_instance_uid=$new_flow_instance_uid) as $event_ref
match $event_ref.flow.Finished()
Expand Down
10 changes: 5 additions & 5 deletions nemoguardrails/colang/v2_x/library/core.co
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
flow user said $text -> $transcript
# meta: user action
match UtteranceUserAction.Finished(final_transcript=$text) as $event
$transcript = $event.arguments.final_transcript
$transcript = $event.final_transcript

flow user said something -> $transcript
match UtteranceUserAction.Finished() as $event
send UserActionLog(flow_id="user said", parameter=$event.arguments.final_transcript, intent_flow_id="user said something")
$transcript = $event.arguments.final_transcript
send UserActionLog(flow_id="user said", parameter=$event.final_transcript, intent_flow_id="user said something")
$transcript = $event.final_transcript

flow unhandled user intent -> $intent
match UnhandledEvent(event="FinishFlow", flow_id=regex("^user "), loop_ids={$loop_id}) as $event
$intent = $event.arguments.flow_id
match UnhandledEvent(event="FinishFlow", flow_id=regex("^user "), loop_ids={$self.loop_id}) as $event
$intent = $event.flow_id

flow _bot_say $text
"""It's an internal helper for higher semantic level flows"""
Expand Down
21 changes: 21 additions & 0 deletions nemoguardrails/colang/v2_x/runtime/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Colang error types."""


class ColangParsingError(Exception):
"""Raised when there is invalid Colang syntax detected."""


class ColangSyntaxError(Exception):
"""Raised when there is invalid Colang syntax detected."""


class ColangValueError(Exception):
"""Raised when there is an invalid value detected in a Colang expression."""


class ColangRuntimeError(Exception):
"""Raised when there is a Colang related runtime exception."""


class LlmResponseError(Exception):
"""Raised when there is an issue with the lmm response."""
10 changes: 8 additions & 2 deletions nemoguardrails/colang/v2_x/runtime/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@

from nemoguardrails.colang.v2_x.lang.colang_ast import Element
from nemoguardrails.colang.v2_x.runtime import system_functions
from nemoguardrails.colang.v2_x.runtime.flows import ColangValueError, FlowState, State
from nemoguardrails.colang.v2_x.runtime.errors import ColangValueError
from nemoguardrails.colang.v2_x.runtime.flows import FlowState, State
from nemoguardrails.colang.v2_x.runtime.utils import AttributeDict
from nemoguardrails.eval.cli.simplify_formatter import SimplifyFormatter
from nemoguardrails.utils import new_uid
Expand Down Expand Up @@ -117,7 +118,12 @@ def eval_expression(expr: str, context: dict) -> Any:
if f"var_{var_name}" in expr_locals:
continue

val = context.get(var_name, None)
# Check if it is a global variable
global_var_name = f"_global_{var_name}"
if global_var_name in context:
val = context.get(global_var_name, None)
else:
val = context.get(var_name, None)

# We transform dicts to AttributeDict so we can access their keys as attributes
# e.g. write things like $speaker.name
Expand Down
Loading
Loading