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/agent checking #104

Merged
merged 86 commits into from
Aug 28, 2023
Merged

Feature/agent checking #104

merged 86 commits into from
Aug 28, 2023

Conversation

SeanScripts
Copy link
Collaborator

Creates AgentCheckerUtil class, with functions for finding reachable/unreachable pages and intents. Some other checking functions could be added in the future. Also adds a function to TestCases to get a dataframe of test case results for an agent, rerunning tests without results, or optionally rerunning all test cases. I had put this in the agent checking class, but decided it made more sense to include it in TestCases directly, since we have similar functions to get dataframes in the other core classes.

@SeanScripts SeanScripts self-assigned this Dec 29, 2022
@kmaphoenix kmaphoenix marked this pull request as draft January 4, 2023 18:09
@kmaphoenix kmaphoenix requested a review from MRyderOC January 4, 2023 18:09
@kmaphoenix
Copy link
Member

@MRyderOC please review PR and make optimization suggestions, particularly around the following:

  • Method length (Should aim for ~40 lines per style guide)
  • Nested statements (can these be condensed? Refactored?)
  • Arg Inputs (can these be condensed?)

Copy link
Collaborator

@MRyderOC MRyderOC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some general points:

  • Most of the functions don't have proper documentation. Please follow Google Python Style Guide: Comments and Docstrings and make the changes accordingly.
  • To condense the input parameters, use either id or name for page and flow and be consistent with your choice. e.g. only use name (flow_name, page_name). If you want the user to have the ability to pass either name or id, define an internal helper method to identify which one is passed as an argument and return the one we're using in our code. e.g.
def helper_identify_flow_name_or_id(self, flow_name_or_id):
    # identify whether "flow_name_or_id" is a "flow_name" or a "flow_id"
    # Assuming that we use "flow_name" as an argument for methods like 'find_reachable_pages'
    if flow_name_or_id is like flow_name:
        return flow_name_or_id
    else:
        return self.flow_map[flow_name_or_id]
  • Most of the if statements could be more brief. I addressed some of them as "Brief if statement" to explain how we can achieve the same result with less code. I noticed that most of them use the hasattr built-in function.
  • Note that hasattr(obj, name) returns True if obj has the name attribute even though the value of the obj.name is None and for all the proto objects that we're working with the result of hasattr will be True.

  • For verbose=True change the print statements to logging.info and provide more readable information for the user.

src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
src/dfcx_scrapi/tools/agent_checker_util.py Outdated Show resolved Hide resolved
Comment on lines 556 to 571
flow_id OR flow_name: The ID or name of the flow
from_page: (Optional) The page to start from. If left blank, it will
start on the Start Page
intent_route_limit: (Optional) Default None
include_groups: (Optional) If true, intents from transition route
groups will be included, but only if they are actually referenced
on some page
include_start_page_routes: (Optional) Default true
limit_intent_to_initial: (Optional) Default False. If true, only
take intent routes on the initial page, rather than on any page
in the traversal.
is_initial: (Optional) Default True
include_meta: (Optional) Default False. If true, includes special
transition targets like End Session, End Flow, etc.
verbose: (Optional) If true, print debug information about
route traversal
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Could you please provide more information on intent_route_limit and is_initial?
  2. It seems include_start_page_routes only affects the flow's Start Page (Line 519). That means if we pass some random page other than the Start page to from_page and pass include_start_page_routes it will return all reachable pages from both from_page and Start Page.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I added some documentation about intent_route_limit. is_initial should have been internal here. I realized that I broke the functionality earlier by trying to put is_initial into the params dict, but I think I managed to fix it.

  2. Yes, that's the intended behavior. If include_start_page_routes is true, then start page intent routes will be treated as if they are in scope on every page, which is the way they actually work in the agent. This isn't very useful if you're starting from a page other than the start page with no limit on the number of intent routes taken. But with intent_route_limit = 1 for example, you can answer the question: "Starting from from_page, which pages can be reached in one conversation turn? (assuming all conditional routes are possible)". Choosing whether or not to allow start page routes to be in scope is pretty useful here.

@MRyderOC
Copy link
Collaborator

@kmaphoenix Would you please take a quick look at the comments? I'll appreciate your input.

return "Default Start Flow"

# Note that flow id includes agent, normally...
def _convert_page(self, page_id, flow_id, pages_map):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SeanScripts one way to optimize this section would be to create dictionary of your page_id mappings.

Then you can call .get on the dictionary directly and return INVALID if nothing matches.
This should significantly cut down on the number of if/else checks you need to do.

page_dict = {
  'END_SESSION': 'End Session',
  'END_FLOW': 'End Flow',
  etc.
}

display_name = page_dict.get(page_id, 'INVALID')

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this dictionary and returned the mapping through it if the page ID was one of these special cases. However, we still need to look up the page name from the main dictionary of page names if it's not one of these special cases. I simplified the part after this a little bit by using .get.

Also, I know the latest version of Scrapi added the special cases to the list of pages, but I'm not sure what the format is, compared to what is returned in the test cases. In particular, whether or not the "pages" like END_SESSION include the flow ID. I might need to check that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like with the 1.6 update to get_pages_map, this check for the special pages isn't needed at all. Thanks! This function has been simplified.

passed = []

for response in test_case_results:
# Collect untested cases to be retested
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SeanScripts If you have a commented section in a method where you are describing what that section does, you can just make that entire section a new method.

This will clean up your main method and provide better debug tracking later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this section to a new function and had it return a single-row dataframe for each test case response, which avoided initializing all the empty lists above. I kept the check for test cases that needed to be retested since it was just one condition.

@SeanScripts SeanScripts force-pushed the feature/agent_checking branch from 39ba9b3 to 612c1f9 Compare July 10, 2023 18:22
@SeanScripts
Copy link
Collaborator Author

@kmaphoenix I wrote some tests, though I wasn't able to run them using pytest in my environment. However, running the content of the tests with a demo agent, they're still working as expected.

@kmaphoenix kmaphoenix marked this pull request as ready for review August 25, 2023 22:26
Copy link
Member

@kmaphoenix kmaphoenix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linted and tested locally.

@kmaphoenix kmaphoenix merged commit 77187bd into main Aug 28, 2023
@kmaphoenix kmaphoenix deleted the feature/agent_checking branch August 28, 2023 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants