From 40ecc8e7e75fc184cd77e283f8368222a288df1e Mon Sep 17 00:00:00 2001 From: Charles Packer Date: Wed, 15 Nov 2023 15:51:08 -0800 Subject: [PATCH] Update functions.md (#461) --- docs/functions.md | 107 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 33 deletions(-) diff --git a/docs/functions.md b/docs/functions.md index 56358a86..adb30b94 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -30,53 +30,79 @@ There are three steps to adding more MemGPT functions: 2. (Optional) Create a new system prompt that instructs MemGPT how to use these functions 3. Create a new preset that imports these functions (and optionally uses the new system prompt) -### Step 1: Writing the functions +### Example: giving MemGPT the ability to use the Jira API !!! warning "Function requirements" The functions you write MUST have proper docstrings and type hints - this is because MemGPT will use these docstrings and types to automatically create a JSON schema that is used in the LLM prompt. Use the docstrings and types annotations from the [example functions](https://github.com/cpacker/MemGPT/blob/main/memgpt/functions/function_sets/base.py) for guidance. -As an example, if you wanted to give MemGPT the ability to make HTTP requests, you would write the function in Python (you would save this python file inside `~/.memgpt/functions/your_new_functions.py`): -```python -import json -import requests +_Example taken from [this pull request](https://github.com/cpacker/MemGPT/pull/282) by @cevatkerim_ -def http_request(self, method: str, url: str, payload_json: Optional[str] = None): +As an example, if you wanted to give MemGPT the ability to make calls to Jira Cloud, you would write the function in Python (you would save this python file inside `~/.memgpt/functions/jira_cloud.py`): +```python +import os + +from jira import JIRA +from jira.exceptions import JIRAError + + +def get_jira(self, issue_key: str) -> dict: """ - Generates an HTTP request and returns the response. + Makes a request to user's JIRA instance with the jira issue id that is provided and returns the issue details Args: - method (str): The HTTP method (e.g., 'GET', 'POST'). - url (str): The URL for the request. - payload_json (Optional[str]): A JSON string representing the request payload. + issue_key (str): the issue key (MAIN-1 for example). Returns: - dict: The response from the HTTP request. + dict: The response from the JIRA request. """ + if self.jira is None: + server = os.getenv("JIRA_SERVER") + username = os.getenv("JIRA_USER") + password = os.getenv("JIRA_KEY") + self.jira = JIRA({"server": server}, basic_auth=(username, password)) try: - headers = {"Content-Type": "application/json"} + issue = self.jira.issue(issue_key) + return { + "issue": { + "key": issue.key, + "summary": issue.fields.summary, + "description": issue.fields.description, + "created": issue.fields.created, + "assignee": issue.fields.creator.displayName, + "status": issue.fields.status.name, + "status_category": issue.fields.status.statusCategory.name, + } + } + except JIRAError as e: + print(f"Error: {e.text}") + return {"error": str(e.text)} - # For GET requests, ignore the payload - if method.upper() == "GET": - print(f"[HTTP] launching GET request to {url}") - response = requests.get(url, headers=headers) - else: - # Validate and convert the payload for other types of requests - if payload_json: - payload = json.loads(payload_json) - else: - payload = {} - print(f"[HTTP] launching {method} request to {url}, payload=\n{json.dumps(payload, indent=2)}") - response = requests.request(method, url, json=payload, headers=headers) - return {"status_code": response.status_code, "headers": dict(response.headers), "body": response.text} - except Exception as e: - return {"error": str(e)} +def run_jql(self, jql: str) -> dict: + """ + Makes a request to user's JIRA instance with the jql that is provided and returns the issues + + Args: + jql (str): the JQL. + + Returns: + dict: The response from the JIRA request. + """ + if self.jira is None: + server = os.getenv("JIRA_SERVER") + username = os.getenv("JIRA_USER") + password = os.getenv("JIRA_KEY") + self.jira = JIRA({"server": server}, basic_auth=(username, password)) + try: + issues = self.jira.search_issues(jql) + return {"issues": [issue.key for issue in issues]} + except JIRAError as e: + print(f"Error: {e.text}") + return {"error": str(e.text)} ``` -### Step 3: Create a new preset file - -Now we need to create a new preset file, let's create one called `~/.memgpt/presets/memgpt_http.yaml`: +Now we need to create a new preset file, let's create one called `~/.memgpt/presets/memgpt_jira.yaml`: ```yaml # if we had created a new system prompt, we would replace "memgpt_chat" with the new prompt filename (no .txt) system_prompt: "memgpt_chat" @@ -89,8 +115,23 @@ functions: - "conversation_search_date" - "archival_memory_insert" - "archival_memory_search" - # internet access - - "http_request" + # Jira functions that we made inside of `~/.memgpt/functions/jira_cloud.py` + - "get_jira" + - "run_jql" ``` -Now when we run `memgpt configure`, we should see the option to use `memgpt_http` as a preset. \ No newline at end of file +Now when we run `memgpt configure`, we should see the option to use `memgpt_jira` as a preset: +```sh +memgpt configure +``` +```text +... +? Select default preset: (Use arrow keys) + memgpt_extras + memgpt_docs + memgpt_chat + ยป memgpt_jira +``` + +Now, if we create a new MemGPT agent (with `memgpt run`) using this `memgpt_jira` preset, it will have the ability to call Jira cloud: +![image](https://github.com/cpacker/MemGPT/assets/1452094/618a3ec3-8d0c-46e9-8a2f-2dbfc3ec57ac)