def create_message_list(selected_plugin: List[str], all_plugins: List[AgentDescriptor], verbose_mode=False) -> Action: text = 'Available Skills:\n' for plugin in all_plugins: if plugin.pkg_name in selected_plugin: text += Colorize() \ .emoji(Colorize.EMOJI_CHECK) \ .complete() \ .append(f" {get_printable_name(plugin)}\n") \ .to_console() if verbose_mode: text += Colorize() \ .complete() \ .append(f"{plugin.description}\n") \ .to_console() else: text += \ Colorize() \ .emoji(Colorize.EMOJI_BOX) \ .append(f' {get_printable_name(plugin)}\n') \ .to_console() if verbose_mode: text += Colorize() \ .append(f"{plugin.description}\n") \ .to_console() return Action( suggested_command=':', description=text, execute=True )
def ask_user_prompt(command_to_execute: Action) -> Optional[str]: if command_to_execute.is_same_command(): return command_to_execute.origin_command if command_to_execute.execute: return command_to_execute.suggested_command print(Colorize().emoji( Colorize.EMOJI_ROBOT).info().append(" Suggests: ").info().append( f"{command_to_execute.suggested_command} ").append( "(y/n/e)").to_console()) while True: command_input = input() if is_yes_command(command_input): return command_to_execute.suggested_command if is_not_command(command_input): return command_to_execute.origin_command if is_explain_command(command_input): print(Colorize().warning().append( f"Description: {command_to_execute.description}").to_console()) print(Colorize().info().append( 'choose yes[y] or no[n] or explain[e]').to_console())
def create_message_server_runing() -> str: colorize = Colorize() if check_if_process_running(): colorize \ .complete() \ .append(f"The server is running") else: colorize \ .warning() \ .append(f"The server is not running") return colorize.to_console()
def ask_to_user(text): print(Colorize().info().append(f"{text} ").append("(y/n)").to_console()) while True: command_input = input() if command_input in ('y', 'yes'): return True if command_input in ('n', 'no'): return False print(Colorize().info().append('choose yes[y] or no[n]').to_console())
def expected_description(all_plugins, selected) -> str: text = 'Available Skills:\n' for plugin in all_plugins: if plugin.pkg_name in selected: text += Colorize().emoji(Colorize.EMOJI_CHECK).complete() \ .append(f" {get_printable_name(plugin)}\n") \ .to_console() else: text += Colorize().emoji(Colorize.EMOJI_BOX) \ .append(f' {get_printable_name(plugin)}\n') \ .to_console() return text
def get_next_action(self, state: State) -> Action: # to be ultimately replaced by a suitable intent recognizer # refer to the nlc2cmd skill for an example of a NLC layer if state.command in self.intents: # deploy to kube deploys local Dockerfile to your ibmcloud # run Dockerfile brings up an application locally self.exe.set_goal(state.command) # this is the sequence of actions that achieves the user's goal plan = self.exe.get_plan() if plan: logger.info("####### log plan inside ibmcloud ########") logger.info(plan) action_list = [] for action in plan: # translate from actions in the planner's domain to Action Class action_object = self.exe.execute_action(action) # some actions may have null executions (internal to the reasoning engine) if action_object: action_list.append(action_object) return action_list else: return Action(suggested_command=NOOP_COMMAND, execute=True, description=Colorize().info().append('Sorry could not find a plan to help! :-(').to_console(), confidence=1.0) # does not do anything else by default else: return Action(suggested_command=NOOP_COMMAND)
def get_next_action(self, state: State) -> Action: # user typed in, in natural language command = state.command try: ## Needs to be a post request since service/endpoint is configured for post endpoint_comeback = requests.post(tellina_endpoint, json={ 'command': command }).json() ## tellina endpoint must return a json with # tellina response, the cmd for the user NL utterance response = 'Try >> ' + endpoint_comeback['response'] # the confidence; the tellina endpoint currently returns 0.0 confidence = float(endpoint_comeback['confidence']) return Action( suggested_command=NOOP_COMMAND, execute=True, description=Colorize().info().append(response).to_console(), confidence=confidence) except Exception as ex: return [{"text": "Method failed with status " + str(ex)}, 0.0]
def get_next_action(self, state: State) -> Action: command = state.command data, confidence = self.service(command) response = data["text"] return Action( suggested_command=NOOP_COMMAND, execute=True, description=Colorize().info().append(response).to_console(), confidence=confidence)
def post_execute(self, state: State) -> Action: if state.command.startswith('ls') and state.result_code != '0': return Action(description=Colorize() .append(f"Are you sure that this command is correct?({state.result_code})\n") .warning() .append(f"Try man ls for more info ") .to_console(), confidence=1 ) return Action(suggested_command=state.command)
def create_error_install(name: str) -> Action: text = Colorize() \ .warning() \ .append(f"{name} is not a valid skill to add to the catalog. You need to write a folder or a valid url. \n") \ .append("Example: clai install ./my_new_agent") \ .to_console() return Action( suggested_command=':', description=text, execute=True )
def execute(self, state: State) -> Action: self.agent_datasource.reload() text = Colorize() \ .complete() \ .append("Plugins reloaded.\n") \ .to_console() return Action(suggested_command=":", execute=True, description=text, origin_command=state.command)
def create_error_select(selected_plugin: str) -> Action: text = Colorize() \ .warning() \ .append(f"{selected_plugin} is not a valid skill name. Write >> clai skills to check available skills.") \ .append("Example: >> clai activate nlc2cmd") \ .to_console() return Action( suggested_command=':', description=text, execute=True )
def create_orchestrator_list(selected_orchestrator: str, all_orchestrator: List[OrchestratorDescriptor], verbose_mode=False) -> Action: text = 'Available Orchestrators:\n' for orchestrator in all_orchestrator: if selected_orchestrator == orchestrator.name: text += Colorize() \ .emoji(Colorize.EMOJI_CHECK) \ .complete() \ .append(f" {orchestrator.name}\n") \ .to_console() if verbose_mode: text += Colorize() \ .complete() \ .append(f" {orchestrator.description}\n") \ .to_console() else: text += \ Colorize() \ .emoji(Colorize.EMOJI_BOX) \ .append(f' {orchestrator.name}\n') \ .to_console() if verbose_mode: text += Colorize() \ .append(f" {orchestrator.description}\n") \ .to_console() return Action( suggested_command=':', description=text, execute=True )
def process_command_from_user(command_id, user_name, command_to_check): command_to_execute = send_command(command_id=command_id, user_name=user_name, command_to_check=command_to_check) if command_to_execute.origin_command == STOP_COMMAND: print(Colorize().info().append("Clai has been stopped").to_console()) return NOOP_COMMAND, False if command_to_execute.description and command_to_execute.suggested_command == ":": print(command_to_execute.description) command_accepted_by_the_user = ask_user_prompt(command_to_execute) return command_accepted_by_the_user, command_to_execute.pending_actions
def process_command(command_id, user_name, command_to_check): pending_commands = False if command_to_check == COMMAND_START_SERVER: command_accepted_by_the_user = START_SERVER_COMMAND_TO_EXECUTE print(Colorize().info().append( "CLAI Starting. CLAI could take a while to start replying"). to_console()) elif command_to_check.strip() == COMMAND_BASE.strip(): command_accepted_by_the_user = NOOP_COMMAND print(create_message_server_runing()) print(create_message_help().description) else: command_accepted_by_the_user, pending_commands = \ process_command_from_user(command_id, user_name, command_to_check) override_last_command("\n" + command_accepted_by_the_user + "\n") if not pending_commands: sys.exit(1)
def post_execute(self, state: State) -> Action: if state.result_code == '0': return Action(suggested_command=state.command) cmd = str(state.command) stderr = str(state.stderr) try: # Get corrected command from `thefuck` bot settings.init() cmd = Command(cmd, stderr) cmd_corrected = get_corrected_commands(cmd) cmd_to_run = next(cmd_corrected).script except Exception: return Action(suggested_command=state.command, confidence=0.1) else: return Action(description=Colorize().info().append( "Maybe you want to try: {}".format(cmd_to_run)).to_console(), confidence=0.8)
def create_message_help() -> Action: text = Colorize().info() \ .append("CLAI usage:\n" "clai [help] [skills [-v]] [activate [skill_name]] [deactivate [skill_name]] " "[manual | automatic] [install [name | url]] \n\n" "help Print help and usage of clai.\n" "skills List available skills. Use -v For a verbose description of each skill.\n" "activate Activate the named skill.\n" "deactivate Deactivate the named skill.\n" "manual Disables automatic execution of commands without operator confirmation.\n" "auto Enables automatic execution of commands without operator confirmation.\n" "install Installs a new skill. The required argument may be a local file path\n" " to a skill plugin folder, or it may be a URL to install a skill plugin \n" " over a network connection.\n" ) \ .to_console() return Action( suggested_command=':', description=text, execute=True )
def print_error(text): print(Colorize().warning().append(text).to_console())
def get_command_tldr(cmd): if not TLDR_AVAILABLE: return '' cmd_tldr = tldr.get_page(cmd) if cmd_tldr is None: return '' description = Colorize() for i, line in enumerate(cmd_tldr): line = line.rstrip().decode('utf-8') if i == 0: description.append('-' * 50 + '\n') if len(line) < 1: # Empty line description.append('\n') elif line[0] == '#': line = line[1:] description.warning().append(line.strip() + '\n') elif line[0] == '>': # Description line line = ' ' + line[1:] description.normal().append(line.strip() + '\n') elif line[0] == '-': # Example line description.normal().append(line.strip() + '\n') elif line[0] == '`': # Example command line = ' ' + line[1:-1] description.info().append(line.strip() + '\n') description.normal().append('summary provided by tldr package\n') description.normal().append('-' * 50 + '\n') return description.to_console()
def __call__(self, *args, **kwargs): # Set user command command = args[0] confidence = 0.0 try: response = requests.post(_rasa_service, json={'text': command}).json() confidence = response["intent"]["confidence"] if confidence > self.state["threshold"]: self.state["current_intent"] = response["intent"]["name"] except Exception as ex: print("Method failed with status " + str(ex)) if self.state["current_intent"] == "commit": if not self.state["ready_flag"]: self.state["ready_flag"] = True temp_description = "Ready to {}. Press execute to continue.".format(self.state["current_intent"]) return [ Action( suggested_command="git status | tee {}".format(_path_to_log_file), execute=True, description=None, confidence=1.0 ), Action( suggested_command=NOOP_COMMAND, execute=True, description=Colorize().info().append(temp_description).to_console(), confidence=1.0 ) ] if command == "execute": now = datetime.now() commit_message = now.strftime("%d/%m/%Y %H:%M:%S") # this should really go into post-execute # stdout = open(_path_to_log_file).read().split("\n") commit_description = "" current_branch = None for line in stdout: if line.startswith("On branch"): current_branch = line.split()[-1] if line.strip().startswith("modified:"): commit_description += line.strip() + " + " if commit_description: self.state["commit_details"] = commit_description if current_branch: self.state["current_branch"] = current_branch commit_description = self.state["commit_details"] respond = Action( suggested_command='git commit -m "{}" -m "{}";'.format(commit_message, commit_description), execute=False, description=None, confidence=1.0 ) if self.state["has_done_add"]: return respond else: return [ Action( suggested_command='git add -A', execute=True, description="Adding untracked files...", confidence=1.0 ), respond] if self.state["current_intent"] == "push": return Action( suggested_command='git push', execute=False, description=None, confidence=confidence ) if self.state["current_intent"] == "merge": merge_url = "{}/pulls".format(_github_url) source = None target = "master" for entity in response["entities"]: if entity["entity"] == "source": source = entity["value"] if entity["entity"] == "target": target = entity["value"] if not source: source = self.state["current_branch"] payload = { "title" : "Dummy PR from gitbot", "body" : "Example from the `gitbot` screencast. This will not be merged.", "head" : source, "base" : target } ping_github = json.loads(self.gh_session.post(merge_url, json=payload).text) return Action( suggested_command=NOOP_COMMAND, execute=True, description="Success. Created PR {}".format(ping_github["number"]), confidence=confidence ) if self.state["current_intent"] == "comment": idx = 0 comment = None for entity in response["entities"]: if entity["entity"] == "id": idx = entity["value"] if entity["entity"] == "comment": comment = entity["value"] idx = command.split('<')[-1].split('>')[0] comment_url = "{}/issues/{}/comments".format(_github_url, idx) payload = { "body" : comment } ping_github = json.loads(self.gh_session.post(comment_url, json=payload).text) return Action( suggested_command=NOOP_COMMAND, execute=True, description="Success", confidence=confidence )
def get_next_action(self, state: State) -> Action: logger.info( "================== In HowDoI Bot:get_next_action ========================" ) logger.info( "State:\n\tCommand: {}\n\tError Code: {}\n\tStderr: {}".format( state.command, state.result_code, state.stderr)) logger.info( "============================================================================" ) # Invoke "howdoi" plugin only when a question is asked is_question = self.questionIdentifier.is_question(state.command) if not is_question: return Action(suggested_command=state.command, confidence=0.0) apis: OrderedDict = self.store.get_apis() helpWasFound = False for provider in apis: # We don't want to process the manpages provider... thats the provider # that we use to clarify results from other providers if provider == "manpages": logger.info(f"Skipping search provider 'manpages'") continue thisAPI: Provider = apis[provider] # Skip this provider if it isn't supported on the target OS if not thisAPI.can_run_on_this_os(): logger.info(f"Skipping search provider '{provider}'") logger.info( f"==> Excluded on platforms: {str(thisAPI.get_excludes())}" ) continue # Move to next provider in list logger.info(f"Processing search provider '{provider}'") if thisAPI.has_variants(): logger.info( f"==> Has search variants: {str(thisAPI.get_variants())}") variants: List = thisAPI.get_variants() else: logger.info(f"==> Has no search variants") variants: List = [None] # For each search variant supported by the current API, query # the data store to find the closest matching data. If there are # no search variants (ie: the singleton variant case), the variants # list will only contain a single, Nonetype value. for variant in variants: if variant is not None: logger.info(f"==> Searching variant '{variant}'") data = self.store.search(state.command, service=provider, size=1, searchType=variant) else: data = self.store.search(state.command, service=provider, size=1) if data: logger.info( f"==> Success!!! Found a result in the {thisAPI}") # Find closest match b/w relevant data and manpages for unix searchResult = thisAPI.extract_search_result(data) manpages = self.store.search(searchResult, service='manpages', size=5) if manpages: logger.info("==> Success!!! found relevant manpages.") command = manpages['commands'][-1] confidence = manpages['dists'][-1] logger.info("==> Command: {} \t Confidence:{}".format( command, confidence)) # Set return data suggested_command = "man {}".format(command) description=Colorize() \ .emoji(Colorize.EMOJI_ROBOT).append(f"I did little bit of Internet searching for you, ") \ .append(f"and found this in the {thisAPI}:\n") \ .info() \ .append(thisAPI.get_printable_output(data)) \ .warning() \ .append("Do you want to try: man {}".format(command)) \ .to_console() # Mark that help was indeed found helpWasFound = True # We've found help; no need to keep searching break # If we found help, then break out of the outer loop as well if helpWasFound: break if not helpWasFound: logger.info("Failure: Unable to be helpful") logger.info( "============================================================================" ) suggested_command = NOOP_COMMAND description=Colorize().emoji(Colorize.EMOJI_ROBOT) \ .append( f"Sorry. It looks like you have stumbled across a problem that even the Internet doesn't have answer to.\n") \ .info() \ .append(f"Have you tried turning it OFF and ON again. ;)") \ .to_console() confidence = 0.0 return Action(suggested_command=suggested_command, description=description, confidence=confidence)
def post_execute(self, state: State) -> Action: logger.info( "=========================== In Helpme Bot:post_execute ===================================" ) logger.info( "State:\n Command: {}\n Error Code: {}\n Stderr: {}".format( state.command, state.result_code, state.stderr)) logger.info( "============================================================================" ) if state.result_code != '0': # Query data store to find closest matching forum forum = self.store.search(state.stderr, service='stack_exchange', size=1) if forum: logger.info("Success!!! Found relevant forums.") # Find closes match b/w relevant forum and manpages for unix manpages = self.store.search(forum[0]['Answer'], service='manpages', size=5) if manpages: logger.info("Success!!! found relevant manpages.") command = manpages['commands'][-1] confidence = manpages['dists'][-1] # FIXME: Artificially boosted confidence confidence = 1.0 logger.info("Command: {} \t Confidence:{}".format( command, confidence)) return Action( suggested_command="man {}".format(command), description=Colorize( ).emoji(Colorize.EMOJI_ROBOT).append( f"I did little bit of internet searching for you.\n" ).info().append("Post: {}\n".format( forum[0]['Content'][:384] + " ...")).append("Answer: {}\n".format( forum[0]['Answer'][:256] + " ...")).append("Link: {}\n\n".format( forum[0]['Url'])).warning().append( "Do you want to try: man {}".format( command)).to_console(), confidence=confidence) else: logger.info("Failure: Manpage search") logger.info( "============================================================================" ) return Action( suggested_command=NOOP_COMMAND, description=Colorize( ).emoji(Colorize.EMOJI_ROBOT).append( f"Sorry. It looks like you have stumbled across a problem that even internet doesn't have answer to.\n" ).info().append( f"Have you tried turning it OFF and ON again. ;)"). to_console(), confidence=0.0) else: logger.info("Failure: Forum search") logger.info( "============================================================================" ) return Action( suggested_command=NOOP_COMMAND, description=Colorize().emoji(Colorize.EMOJI_ROBOT).append( f"Sorry. It looks like you have stumbled across a problem that even internet doesn't have answer to.\n" ).warning().append( f"Have you tried turning it OFF and ON again. ;)"). to_console(), confidence=0.0) return Action(suggested_command=state.command)
def print_complete(text): print(Colorize().complete().append(text).to_console())
def get_next_action(self, state: State) -> Action: logger.info( "================== In HowDoI Bot:get_next_action ========================" ) logger.info("User Command: {}".format(state.command)) # Query data store to find closest matching forum forum = self.store.search(state.command, service='stack_exchange', size=1) if forum: # Find closes match b/w relevant forum for unix logger.info("Success!!! Found relevant forums.") # Find closes match b/w relevant forum and manpages for unix manpages = self.store.search(forum[0]['Answer'], service='manpages', size=5) if manpages: logger.info("Success!!! found relevant manpages.") command = manpages['commands'][-1] confidence = manpages['dists'][-1] logger.info("Command: {} \t Confidence:{}".format( command, confidence)) return Action( suggested_command="man {}".format(command), description=Colorize().emoji(Colorize.EMOJI_ROBOT).append( f"I did little bit of internet searching for you.\n"). info().append("Post: {}\n".format( forum[0]['Content'][:384] + " ...")).append("Answer: {}\n".format( forum[0]['Answer'][:256] + " ...")).append( "Link: {}\n\n".format( forum[0]['Url'])).warning().append( "Do you want to try: man {}".format( command)).to_console(), confidence=confidence) else: logger.info("Failure: Manpage search") logger.info( "============================================================================" ) return Action( suggested_command=NOOP_COMMAND, description=Colorize().emoji(Colorize.EMOJI_ROBOT).append( f"Sorry. It looks like you have stumbled across a problem that even internet has not answer to.\n" ).info().append( f"Have you tried turning it OFF and ON again. ;)"). to_console(), confidence=0.0) else: logger.info("Failure: Forum search") logger.info( "============================================================================" ) return Action( suggested_command=NOOP_COMMAND, description=Colorize().emoji(Colorize.EMOJI_ROBOT).append( f"Sorry. It looks like you have stumbled across a problem that even internet has not answer to.\n" ).warning().append( f"Have you tried turning it OFF and ON again. ;)"). to_console(), confidence=0.0)
def post_execute(self, state: State) -> Action: logger.info("==================== In zMsgCode Bot:post_execute ============================") logger.info("State:\n\tCommand: {}\n\tError Code: {}\n\tStderr: {}".format(state.command, state.result_code, state.stderr)) logger.info("============================================================================") if state.result_code == '0': return Action(suggested_command=state.command) stderr = state.stderr.strip() # This bot should be triggered if the message on STDERR resembles an # IBM z Systems message ID. For example: # FSUM8977 cp: source "test.txt" and target "test.txt" are identical # # If if the contents of stderr don't include a Z message code, move along matches = re.compile(REGEX_ZMSG).match(stderr) if matches is None: logger.info(f"No Z message ID found in '{stderr}'") return Action(suggested_command=state.command) logger.info(f"Analyzing error message '{matches[0]}'") msgid:str = matches[2] # Isolate the message ID helpWasFound = False # If this message contains data which can be parsed by bpxmtext, then # try calling bpxmtext to get a string describing the error bpx_matches:List[str] = self.__search(matches[0], REGEX_BPX) if bpx_matches is not None: reason_code:str = bpx_matches[1] logger.info(f"==> Reason Code: {reason_code}") # Call bpmxtext to get info about that message result:CompletedProcess = subprocess.run(["bpxmtext", reason_code], stdout=subprocess.PIPE) if result.returncode == 0: messageText = result.stdout.decode('UTF8') # If bpmxtext's response is actually something useful, use it if self.__search(messageText, REGEX_BPX_BADANSWER) is None: suggested_command=state.command description=Colorize() \ .emoji(Colorize.EMOJI_ROBOT) \ .append(f"I asked bpxmtext about that message:\n") \ .info() \ .append(messageText) \ .warning() \ .to_console() helpWasFound = True # Mark that help was indeed found # If this message wasn't one we could send to bpxmtext, or if bpxmtext # didn't return a meaningful message, try searching the KnowledgeCenter if not helpWasFound: kc_api:Provider = self.store.get_apis()['ibm_kc'] if kc_api is not None and kc_api.can_run_on_this_os(): data = self.store.search(msgid, service='ibm_kc', size=1) if data: logger.info(f"==> Success!!! Found information for msgid {msgid}") suggested_command=state.command description=Colorize() \ .emoji(Colorize.EMOJI_ROBOT) \ .append( f"I looked up {msgid} in the IBM KnowledgeCenter for you:\n") \ .info() \ .append(kc_api.get_printable_output(data)) \ .warning() \ .to_console() helpWasFound = True # Mark that help was indeed found if not helpWasFound: logger.info("Failure: Unable to be helpful") logger.info("============================================================================") suggested_command=NOOP_COMMAND description=Colorize() \ .emoji(Colorize.EMOJI_ROBOT) \ .append( f"I couldn't find any help for message code '{msgid}'\n") \ .info() \ .to_console() return Action(suggested_command=suggested_command, description=description, confidence=1.0)