Update functions.md (#461)
This commit is contained in:
@@ -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.
|
||||
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:
|
||||

|
||||
|
||||
Reference in New Issue
Block a user