Chat API
This API is experimental and there may be breaking changes as it evolves.
Overview
The Glean Chat API provides a programmatic interface to interact with the Glean chat system. It allows developers to send and receive messages and handle conversation streams.
The Glean Chat API utilizes a streaming POST endpoint at https://<your-domain>-be.glean.com/rest/api/v1/chat
for continuous, real-time conversational interactions. Remember to replace <your-domain-be>
with your specific domain.
Setup
First, a Glean admin at https://app.glean.com/admin/setup/gleanassistant must set a key with access to GPT-4 as well as who has access to the Glean Assistant.
Authentication
Glean’s Chat API uses the standard HTTP Authorization header to transmit the bearer token, similar to Glean’s Client REST API authentication methods.
‘CHAT’
scoped bearer tokens are required to interact with Glean’s Chat API and can be generated from the admin console. More details about token permissions, scopes and generation can be found here.
Please note that all samples in the document assume the usage of a user-permissioned token. For a global-permissioned token, you would need to add an additional ‘X-Scio-Actas’ HTTP header to make the request on behalf of another user in your company. You can learn about making your first request here.
Personalisation & Privacy
Glean Search and Glean Chat ensure personalized search results based on your document access permissions. Be aware, if a user-permissioned token is used, the results might reflect your private information. Similarly, with a global token, the response may include private data of the user specified in the X-Scio-Actas HTTP header. This feature is designed to enhance data relevance, but it's important to be mindful of the privacy implications. Handle your tokens with care to maintain your personal information's confidentiality.
Schema & Payload
Up-to-date details about API schemas are available at https://developers.glean.com/client/operation/chat/. Please refer to the curl requests and python scripts below for sample usage.
Sample Code and Diagrams
Example Conversational Flow Diagram
The following diagram illustrates a multi-message conversation flow between an end user, a custom client, and the Glean server.
Sample cURL request
Using a user-permissioned token (non-streaming response)
$ curl 'https://<your-domain>-be.glean.com/rest/api/v1/chat' \
-H 'content-type: text/plain;charset=UTF-8' \
-H 'Authorization: Bearer <TOKEN>' \
--data-raw '{
"stream": false,
"messages": [
{
"author": "USER",
"fragments": [
{
"text": "What are the holidays this year?"
}
]
}
]
}'
# Note: jq can be used for easier visualisation of the json response
Using a global-permissioned token (non-streaming response)
$ curl 'https://<your-domain>-be.glean.com/rest/api/v1/chat' \
-H 'Authorization: Bearer <TOKEN>' \
-H 'X-Scio-Actas: john.doe@yourcompany.com' \
--data-raw '{
"stream": false,
"messages": [
{
"author": "USER",
"fragments": [
{
"text": "What are the holidays this year?"
}
]
}
]
}' \
--compressed
# Note: jq can be used for easier visualisation of the json response
Sample python scripts to interact with the API
Variant 1: Single user message (can choose between streaming vs non-streaming)
Note: The following example streams the output as it becomes available, whenever possible. To turn off streaming outputs, please set the stream
field in the request body to False
import requests
import json
def process_message_fragment(message):
message_type = message['messageType']
fragments = message.get('fragments', [])
citations = message.get('citations', [])
message_fragment_str = ''
if message_type == 'CONTENT':
if fragments:
for fragment in fragments:
text = fragment.get('text', '')
print(text, end='', flush=True)
if citations:
print('\nSources:')
for idx, citation in enumerate(citations):
sourceDocument = citation.get('sourceDocument', {})
if sourceDocument:
source = citation['sourceDocument']
print(f'Source {idx + 1}: Document title - {source["title"]}, url: {source["url"]}')
sourcePerson = citation.get('sourcePerson', {})
if sourcePerson:
source = citation['sourcePerson']
print(f'Source {idx + 1}: Person name - {source["name"]}')
def process_response_message_stream(response):
for line in response.iter_lines():
if line:
line_json = json.loads(line)
messages = line_json.get('messages', [])
for message in messages:
process_message_fragment(message)
def main():
url = 'https://<your-domain>-be.glean.com/rest/api/v1/chat'
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer <TOKEN>'
}
data = {
'stream': True, # Set to False to toggle off streaming mode
'messages': [{
'author': 'USER',
'fragments': [{'text': 'What are the holidays this year?'}]
}],
}
try:
with requests.post(url, headers=headers, json=data, stream=True) as response:
if response.status_code == 200:
process_response_message_stream(response)
else:
print(f'Status code: {response.status_code}, error: {response.text}')
exit(1)
except requests.exceptions.RequestException as e:
print(f'Request Exception: {str(e)}')
exit(1)
if __name__ == '__main__':
main()
Variant 2: Multiple message conversations (can choose between streaming vs non-streaming)
Note: The following example streams the output as it becomes available, whenever possible. To turn off streaming outputs, please set the stream
field in the request body to False
import requests
import json
from typing import List, Dict
def process_message_fragment(message):
message_fragment_str = ''
message_fragment_citations = []
message_type = message['messageType']
fragments = message.get('fragments', [])
citations = message.get('citations', [])
message_fragment_str = ''
if message_type == 'CONTENT':
if fragments:
for fragment in fragments:
text = fragment.get('text', '')
print(text, end='', flush=True)
message_fragment_str += text
if citations:
print('\nSources:')
message_fragment_citations += citations
for idx, citation in enumerate(citations):
sourceDocument = citation.get('sourceDocument', {})
if sourceDocument:
source = citation['sourceDocument']
print(f'Source {idx + 1}: Document title - {source["title"]}, url: {source["url"]}')
sourcePerson = citation.get('sourcePerson', {})
if sourcePerson:
source = citation['sourcePerson']
print(f'Source {idx + 1}: Person name - {source["name"]}')
return message_fragment_str, message_fragment_citations
def make_content_message(author: str = 'USER', text: str = None, citations: List[Dict] = None):
# Create a content message JSON object
message_json = {
'author': author,
'messageType': 'CONTENT'
}
if text:
message_json['fragments'] = [{'text': text}]
if citations:
message_json['citations'] = citations
return message_json
def process_response_message_stream(response):
response_message_text = ''
response_message_citations = []
chat_session_tracking_token = None
for line in response.iter_lines():
if line:
line_json = json.loads(line)
messages = line_json.get('messages', [])
chat_session_tracking_token = line_json.get('chatSessionTrackingToken', None)
for message_fragment in messages:
message_fragment_text, message_fragment_citations = process_message_fragment(message_fragment)
response_message_text += message_fragment_text
response_message_citations += message_fragment_citations
return make_content_message(author='GLEAN_AI', text=response_message_text, citations=response_message_citations), chat_session_tracking_token
def send_conversation_message(url, headers, payload):
next_payload = payload
try:
with requests.post(url, headers=headers, json=payload, stream=True) as response:
if response.status_code == 200:
response_message, chat_session_tracking_token = process_response_message_stream(response)
# Add the response message to the next payload, most recent message first
next_payload['messages'].insert(0, response_message)
next_payload['chatSessionTrackingToken'] = chat_session_tracking_token
else:
print(f'Status code: {response.status_code}, error: {response.text}')
exit(1)
except requests.exceptions.RequestException as e:
print(f'Request Exception: {str(e)}')
exit(1)
return next_payload
def main():
url = 'https://<your-domain>-be.glean.com/rest/api/v1/chat'
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer <TOKEN>'
}
# Initialize the payload
payload = {
'stream': True, # Set to False to toggle off streaming mode
'messages': []
}
first_user_message = make_content_message(text='What are the holidays this year?')
second_user_message = make_content_message(text='What about this month?')
user_messages_list = [first_user_message, second_user_message]
for user_message in user_messages_list:
print(f'User message: {user_message["fragments"][0]["text"]}', flush=True)
print('Response: ', flush=True)
payload['messages'].insert(0, user_message) # Add the user message to the payload, most recent message first
payload = send_conversation_message(url, headers, payload) # Send conversation message and get next payload
if __name__ == '__main__':
main()