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

feat: add new documentation for Hub API #169

Merged
merged 30 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1adc831
initial commit of api documentation
martyndavies Mar 28, 2024
ab0423e
add endpoints overview
martyndavies Apr 2, 2024
9362ee1
add guide on managing sessions for users
martyndavies Apr 3, 2024
0b4250d
add example notebooks for OpenAI and MistralAI
martyndavies Apr 3, 2024
9e7bec8
update intro paragraph
martyndavies Apr 3, 2024
e658d0e
add MistralAI integration example
martyndavies Apr 3, 2024
8eafb50
add OpenAI integration example
martyndavies Apr 3, 2024
049583c
update sessions info
martyndavies Apr 3, 2024
39cb2cd
update nav
martyndavies Apr 3, 2024
0cef2c6
additional authentication example
martyndavies Apr 3, 2024
0b460e9
expanded overview
martyndavies Apr 3, 2024
1dc2272
update nav
martyndavies Apr 3, 2024
f900e7e
add images
martyndavies Apr 3, 2024
1a6fe0a
update nav
martyndavies Apr 3, 2024
4e53eee
add langchain example
martyndavies Apr 4, 2024
34699c5
add langchain example
martyndavies Apr 4, 2024
20daf95
update nav name for Hub
martyndavies Apr 4, 2024
72ea5be
update api intro
martyndavies Apr 5, 2024
639d3fe
add Anthropic Claude example
martyndavies Apr 5, 2024
b0b0b8d
add anthropic notebook
martyndavies Apr 5, 2024
c036135
update nav and add Anthropic
martyndavies Apr 5, 2024
0cf655b
update notebooks to remove user id
martyndavies Apr 5, 2024
ec647f9
update nav
martyndavies Apr 5, 2024
07be833
add a UI config guide
martyndavies Apr 5, 2024
e4daaa3
change the title
martyndavies Apr 5, 2024
1beb22a
update index
martyndavies Apr 5, 2024
d0594c2
update main index
martyndavies Apr 5, 2024
1abeec3
add new images for Hub API UI
martyndavies Apr 5, 2024
7383c99
change the name back
martyndavies Apr 5, 2024
4a60cab
update getting started wording
martyndavies Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/api/authentication.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Authentication

Every Superface account has an authentication token assigned to it. This token is used to authenticate API calls, but also to determine which set of tools and their associated functions should be returned for use by your agent.

## API token

You can find the API token in the [Hub API](https://pod.superface.ai/hub/api) section of your Superface account.

![The authentication token section of the Hub API in Superface](/img/api/hub-api-auth-token.png)

## Authentication setup

The Superface API uses `Bearer` authentication, and expects this as part of the headers that as passed with each request for every endpoint.

```
Authorization: Bearer <your_auth_token>
```

For example:

```curl
curl -H "Authorization: Bearer <your_auth_token>" https://pod.superface.ai/api/hub/fd
```
144 changes: 144 additions & 0 deletions docs/api/endpoints.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# API Endpoints

In order to use the tools that Superface offers in your own Agent you don't have to use lots of different endpoints. In fact, using Superface significantly cut down the amount of code you need to write to communicate with external APIs.

## /fd

`GET https://pod.superface.ai/api/hub/fd`

Returns a list of the functions currently available for use by users. The API token that is used to authenticate this endpoint will be used to determine which Superface account is used.

### Example

```curl
curl -H "Authorization: Bearer <auth_token>" https://pod.superface.ai/api/hub/fd
```

### Response

The response will be an array of function objects similar to this example for retrieving the current weather from Wttr.in.

```json
[
{
"type": "function",
"function": {
"name": "weather__current-weather__CurrentWeather",
"description": "Retrieve current weather information for a specified location.\n",
"parameters": {
"type": "object",
"required": ["city"],
"properties": {
"city": {
"type": "string",
"nullable": false,
"description": "Name of the city including state and country, e.g.: \"Prague, Czech Republic\" or \"New York City, NY, USA\"",
"title": "city"
},
"units": {
"enum": ["C", "F", "K"],
"description": "Units used to represent temperature - Fahrenheit, Celsius, Kelvin\nCelsius by default",
"title": "units"
}
},
"nullable": true
}
}
}
]
```

## /session

`POST https://pod.superface.ai/api/hub/session`

Users need to configure their own access credentials for the tools that you offer. In order to do this, we provide a temporary URL that you can use to prompt your users to set up their access.

This URL will expire 15 minutes after generation.

In order to ensure that users can configure, edit or remove access at any time. You need to assign them an ID and use it when calling `/session`. We recommend that your user IDs are formatted as follows: `your_agent_name|unique_user_id` and that you store this for your users so they can access their configuration in future.

### Example

```curl
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <auth_token>" \
-H "x-superface-user-id: <your_agent_name|unique_user_id>" \
https://pod.superface.ai/api/hub/session
```

### Response

```json
{
"status": "success",
"configuration_url": "https://pod.superface.ai/api/hub/session/psxis99ux9",
"assistant_hint": "Tell user to go to URL at 'configuration_url' to configure to open configuration. Always show the whole URL to the user. The 'configuration_url' expires in 15 minutes."
}
```

## /perform

`POST https://pod.superface.ai/api/hub/perform/<tool_and_function_name>`

Calls a specific function by the name defined in the function description. At a minimum this endpoint expects the body object to contain any parameters that are required by this tool and function. Those parameters are also listed in the function description.

The `x-superface-user-id` header is also required so Superface knows which user's configuration to use when performing the functions.

### Example

```curl
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <auth_token>" \
-H "x-superface-user-id: <your_agent_name|unique_user_id>" \
-d '{"city": "prague, cz"}' \
https://pod.superface.ai/api/hub/perform/<tool_and_function_name>
```

### Response

A successful response object will look something similar to the JSON shown below. An `assistant_hint` is provided to help your agent understand how to process this response.

```json
{
"status": "success",
"assistant_hint": "Format the result in 'result' field to the user. If the user asked for a specific format, respect it",
"result": {
"description": "What a sense of achievement!",
"end": {
"dateTime": "2024-04-03T16:54:47+02:00",
"timeZone": "Europe/Prague"
},
"kind": "calendar#event",
"organizer": {
"email": "[email protected]",
"self": true
},
"reminders": {
"useDefault": true
},
"sequence": 0,
"start": {
"dateTime": "2024-04-03T16:39:47+02:00",
"timeZone": "Europe/Prague"
},
"status": "confirmed",
"summary": "Feel successful with Superface"
}
}
```

If the user has not configured access to the tool they are trying to use, or the credentials they entered have now expired, the response body will be a prompt for the user that will include a new `action_url`.

```json
{
"status": "requires_action",
"assistant_hint": "Tell user to go to URL at 'action_url' to configure access to 'google-calendar'. Then try calling tool again. Always show the whole URL to the user. The 'action_url' expires in 15 minutes.",
"action_type": "configure_access",
"action_url": "https://pod.superface.ai/api/hub/session/9uzs6qz3t8"
}
```

Once this step has been completed, the `/perform` action can be run again to complete the task.
225 changes: 225 additions & 0 deletions docs/api/examples/anthropic.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# Anthropic

Anthropic are building a series of Large Language Models under the name Claude. In this example we show how to use their approach to [function calls and tools](https://docs.anthropic.com/claude/docs/tool-use) (currenly in Beta).

The tool function definitions and execution of the API calls for the selected tool(s) is handled by Superface using the [Hub API endpoints](../endpoints). The choice of which tool to use, and other decision making is handled by Claude.

You can download this example as a [runnable .ipynb notebook](/notebooks/superface_hub_api_anthropic_weather_example.ipynb).

## Prerequisites

The Anthropic Python SDK is required for this example.

```python
pip install anthropic
```

## Setup

Import the dependencies and configure the required constants. Some of these, such as those relating to the `SUPERFACE_USER_ID` are for example purposes. In a production environment you would handle this differenly, as outlined in the [Session Management guide](../sessions).

```python
import anthropic
import json
import requests as r
from IPython.display import display, Markdown

# Set a random number of your choice, but don't change it
# once you have run the notebook, otherwise you will create another user.
SUPERFACE_USER_ID_CONSTANT =

# Use the number to create a unique ID
SUPERFACE_USER_ID = "sfoaidemo|" + str(SUPERFACE_USER_ID_CONSTANT)

# Default URL for Superface
SUPERFACE_BASE_URL = "https://pod.superface.ai/api/hub"

# Set the Superface authentication token
SUPERFACE_API_TOKEN="<your-superface-api-token"

# Set the OpenAI API Key
ANTHROPIC_API_KEY="<your-anthropic-api-key"
```

## Anthropic Setup

To initialize the Anthropic SDK, pass in your API key.

```python
client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)
```

## Helper functions

There are a lot of repetitive tasks when dealing with LLMs so having some helper functions to cut down on code helps. First we define two helpers to use with Superface's Hub API.

```python
# Helper function to return the tool function descriptors
def get_superface_tools():
headers = {"Authorization": "Bearer "+ SUPERFACE_AUTH_TOKEN}
tools = r.get(SUPERFACE_BASE_URL + "/fd", headers=headers)
return tools.json()

# Helper function to perform the action for all the functions.
# This is the only API call required regardless of what the function is.
def perform_action(tool_name=None, tool_body=None):
headers = {"Authorization": "Bearer "+ SUPERFACE_AUTH_TOKEN, "x-superface-user-id": SUPERFACE_USER_ID}
perform = r.post(SUPERFACE_BASE_URL + "/perform/" + tool_name, headers=headers, json=tool_body)
return json.dumps(perform.json())
```

The first function, `get_superface_tools()`, retrieves the function descriptions for any tools that have been added in your Superface account. At the very least, you'll already have the Wttr.in tool that this example uses.

The second function, `perform_action()`, is responsible for executing the API request for the tool and specific function that Claude will choose. It also ensures that this request is authenticated as a specific user using the `x-superface-user-id` header.

### Transform function descriptions

The JSON schema for defining tools that Anthropic requires is _slightly_ different to that used by OpenAI, MistraAI and LangChain. To account for this, the helper function below reformats the JSON response from `get_superface_tools()`.

```python
def get_formatted_tools():
original_tools = get_superface_tools()
formatted_tools = []

for tool in original_tools:
formatted_tools.append(tool['function'])

for tool in formatted_tools:
tool['input_schema'] = tool.pop("parameters")

return formatted_tools
```

The final helper is to communicate with Claude. This is also where the model selection, initial system prompt, list of tools and message history are set up.

```python

def talk_to_claude(role=None, message=None):
messages.append({"role": role, "content": message})
response = client.beta.tools.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
system="Today is April 5, 2024",
tools=get_formatted_tools(),
messages=messages
)
return response
```

## Message history

This example needs a "memory" of all the interactions between the user, the API and Claude. An array is a good way to do this:

```python
messages = []
```

## Prompt

Next, set up the initial user prompt. Asking about the weather is the most simplistic example you can do but it's also the example that Anthropic use for their [function calling documentation](https://docs.anthropic.com/claude/docs/tool-use) so we've mirrored that here to help you compare.

```python
response = talk_to_claude("user", "What's the weather like in Prague?")
print(response)
```

## What is Claude thinking?

Claude likes to think. The first response to a user prompt will contain what Claude thinks the best approach is for obtaining the result. It can vary slightly depending on the amount of inputs a tool expects.

```text
<thinking>
To get the current weather forecast for Prague, I should use the weather__current-weather__CurrentWeather function. Let's check if I have the required parameters:

city: The user provided "Prague" as the city. To be more precise, I'll specify "Prague, Czech Republic".
units: This is an optional parameter. The user did not specify units, so I can omit this and the function will use the default of Celsius.

I have the required city parameter, so I can proceed with calling the function.
</thinking>
```

Additionally, as part of the response Claude will provide the name of the selected tool, and the required inputs so that a call to the Superface Hub API can be made.

## Perform function call

If Claude wants to use a tool (which is this case is true), add the last response to the message history, then extract the function name, and the inputs and use the `perform_action()` helper to pass them to the Hub API.

```python
if (response.content[1] and response.content[1].type == "tool_use"):
claude_response = response.content[1]
messages.append({
"role": "assistant",
"content": [
{
"type": "text",
"text": response.content[0].text
},
{
"type": claude_response.type,
"id": claude_response.id,
"name": claude_response.name,
"input": claude_response.input
}
]
})

function_name = claude_response.name
function_inputs = claude_response.input
tool_use_id = claude_response.id

superface_response = perform_action(function_name, function_inputs)

superface_response
```

The response from Superface in this instance will look similar to this:

```json
{
"status": "success",
"assistant_hint": "Format the result in 'result' field to the user. If the user asked for a specific format, respect it",
"result": {
"description": "Partly cloudy",
"feelsLike": 16,
"temperature": 16
}
}
```

## Final response

Now that the Hub API has executed the function and returned a result, this needs to be added to the message history and sent back to Claude to determine a final response.

```python
tool_response_content = [{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": superface_response

}]
claude_response = talk_to_claude("user", tool_response_content)
```

Claude will reply with the final response which can also be added to the message history:

```python
messages.append({"role": "assistant", "content": claude_response.content[0].text})
```

In notebook form, this can be displayed nicely to the user:

```python
display(Markdown(claude_response.content[0].text))
```

```text
Current weather in Prague, Czech Republic: Temperature: 16°C Feels like: 16°C Description: Partly cloudy
```

## Summary

This example builds on the function calling example that Anthropic use, however, with Superface's Hub API you can access many varied APIs, including your own custom tools.

The approach to implementing those would be similar, especialy when you consider that just a single function is required to execute any of the functions an LLM selects and Superface will handle it from there.

For more information on how to implement function calling with Anthropic Claude3, take a look at their [documentation}(https://docs.anthropic.com/claude/docs/tool-use).
Loading
Loading