Tool interfaces#

Function Tools#

Function Tools are python functions with authentication data supplied through keyword arguments.

Example: list_gmail function tool#

source: examples/openai/personal-email-summarizer#L254

@function_tool(
    auth_provider=AuthProvider.GOOGLE,
    scopes=["https://www.googleapis.com/auth/gmail.readonly"],
)
def list_gmail(q: str, GOOGLE_TOKEN: str, **kwargs):
    """
    List gmail with gmail query

    Args:
        q(str) : gmail query, see https://support.google.com/mail/answer/7190?hl=en
                 call get_gmail_query_definition to get the definition of gmail query

    """

    response = requests.get(
        url=f"https://gmail.googleapis.com/gmail/v1/users/me/messages",
        headers={
            "Authorization": f"Bearer {GOOGLE_TOKEN}",
        },
        params={
            "q": q,
        },
    )

    if response.status_code != 200:
        return f"failed to get mail list. error : {response.text}"

    return response.json()

Input and Output#

Input and output are passed as function arguments and return values.

Authentication data#

Authentication data is passed as keyword arguments. For the example above, the GOOGLE_TOKEN is passed as a keyword argument.

...
@function_tool()
def my_tool(args, **kwargs):
    token = kwargs["GOOGLE_TOKEN"]
...

For each auth provider, the key name is different. (See Supported Auth List for more details.)

Sandboxed Tools#

Example: create-issue github tool in hyperpocket#

Directory Structure#

/create-issue
  /create_issue
    /__init__.py
    /__main__.py
  /requirements.txt
  /pocket.json

Example Code#

Original source code can be found at tools/github/create-issue.

# tools/github/create-issue/create-issue/__main__.py
import json
import os
import sys

from github import Auth, Github
from github.GithubObject import NotSet
from pydantic import BaseModel, Field


class GithubCreateIssueRequest(BaseModel):
    owner: str = Field(..., description="The owner of the repository")
    repo: str = Field(..., description="The name of the repository")
    title: str = Field(..., description="The title of the issue")
    body: str | None = Field(None, description="The body of the issue")
    assignee: str | None = Field(None, description="The assignee of the issue")
    labels: list[str] | None = Field(None, description="The labels of the issue")


def create_issue(req: GithubCreateIssueRequest):
    token = os.environ.get("GITHUB_TOKEN")
    github = Github(auth=Auth.Token(token))

    body = req.body if req.body is not None else NotSet
    assignee = req.assignee if req.assignee is not None else NotSet
    labels = req.labels if req.labels is not None else NotSet

    res = github.get_repo(f"{req.owner}/{req.repo}").create_issue(
        title=req.title,
        body=body,
        assignee=assignee,
        labels=labels,
    )

    return res.raw_data


def main():
    req = json.load(sys.stdin.buffer)
    req_typed = GithubCreateIssueRequest.model_validate(req)
    response = create_issue(req_typed)

    print(json.dumps(response))


if __name__ == "__main__":
    main()
# tools/github/create-issue/create-issue/pocket.json
{
    "tool": {
        "name": "github_create_issue",
        "description": "Create a GitHub issue",
        "inputSchema": { 
            "properties": {
                "owner": {
                    "description": "The owner of the repository",
                    "title": "Owner",
                    "type": "string"
                },
                "repo": {
                    "description": "The name of the repository",
                    "title": "Repo",
                    "type": "string"
                },
                "title": {
                    "description": "The title of the issue",
                    "title": "Title",
                    "type": "string"
                },
                "body": {
                    "anyOf": [
                        {
                        "type": "string"
                        },
                        {
                        "type": "null"
                        }
                    ],
                    "default": null,
                    "description": "The body of the issue",
                    "title": "Body"
                },
                "assignee": {
                    "anyOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "null"
                        }
                    ],
                    "default": null,
                    "description": "The assignee of the issue",
                    "title": "Assignee"
                },
                "labels": {
                    "anyOf": [
                        {
                            "items": {
                                "type": "string"
                            },
                            "type": "array"
                        },
                        {
                            "type": "null"
                        }
                    ],
                    "default": null,
                    "description": "The labels of the issue",
                    "title": "Labels"
                }
            },
            "required": [
                "owner",
                "repo",
                "title"
            ],
            "title": "GithubCreateIssueRequest",
            "type": "object"
        }
    },
    "language": "python",
    "auth": {
        "auth_provider": "github",
        "scopes": ["repo"]
    },
    "entrypoint": {
        "build": "pip install -r requirements.txt",
        "run": "create_issue/__main__.py"
    }
}
Tips for Building .tool.inputSchema#

You can obtain tool.inputSchema with GithubCreateIssueRequest.model_json_schema(). Especially, if there are multiple BaseModels involved, you can get a flattened schema just as the following code.

from hyperpocket.util.flatten_json_schema import flatten_json_schema
json_schema = flatten_json_schema(GithubCreateIssueRequest.model_json_schema())

Input and Output#

Input is fed from stdin. You should print the output to stdout.

Using passed authentication token#

Authentication resulting token is provided through environment variable. In this case, GITHUB_TOKEN.

For each auth provider, the key name is different. (See Supported Auth List for more details.)