The AI Chat Service provides a JSON-RPC 2.0 API for creating and managing AI-powered conversations with advanced function calling capabilities through the SWAIG (SignalWire AI Gateway) system.
Base URL: http://localhost:8080/
(configurable)
Protocol: JSON-RPC 2.0
Content-Type: application/json
Method: POST
All requests require authentication via two parameters:
- project_id
: Project identifier for multi-tenancy
- token
: Authentication token for the project
Creates a new conversation or reinitializes an existing one.
Parameter | Type | Required | Description |
---|---|---|---|
project_id |
string | ✅ | Project identifier |
token |
string | ✅ | Authentication token |
id |
string | ✅ | Unique conversation identifier |
config_url |
string | ✅ | URL to fetch YAML configuration |
reinit |
boolean | ❌ | Force reinitialize existing conversation (default: false) |
conversation_timeout |
integer | ❌ | Timeout in seconds (default: 3600) |
user_message |
string | ❌ | Initial user message to send |
user_meta_data |
object | ❌ | Additional metadata to store |
{
"jsonrpc": "2.0",
"method": "create_conversation",
"params": {
"project_id": "my-project",
"token": "auth-token-123",
"id": "conversation-uuid-123",
"config_url": "https://example.com/config.yaml",
"reinit": false,
"conversation_timeout": 7200,
"user_message": "Hello, I need help with my account",
"user_meta_data": {
"user_id": "user123",
"session_id": "sess456"
}
},
"id": "req-1"
}
New Conversation Created:
{
"jsonrpc": "2.0",
"result": {
"status": "created",
"id": "conversation-uuid-123",
"initial_message": "Hello! I'm here to help you with your account. What can I assist you with today?"
},
"id": "req-1"
}
Existing Conversation (reinit=false):
{
"jsonrpc": "2.0",
"result": {
"status": "exists",
"id": "conversation-uuid-123",
"initial_message": null
},
"id": "req-1"
}
Reinitialized Conversation:
{
"jsonrpc": "2.0",
"result": {
"status": "reinitialized",
"id": "conversation-uuid-123",
"initial_message": "Welcome back! How can I help you today?"
},
"id": "req-1"
}
Sends a message to an existing conversation and receives an AI response.
Parameter | Type | Required | Description |
---|---|---|---|
project_id |
string | ✅ | Project identifier |
token |
string | ✅ | Authentication token |
id |
string | ✅ | Conversation identifier |
message |
string | ✅ | Message content to send |
role |
string | ❌ | Message role: "user" or "system" (default: "user") |
config_url |
string | ❌ | Config URL (creates conversation if not exists) |
conversation_timeout |
integer | ❌ | Timeout in seconds |
reinit |
boolean | ❌ | Reinitialize if using config_url |
user_meta_data |
object | ❌ | Additional metadata |
{
"jsonrpc": "2.0",
"method": "chat",
"params": {
"project_id": "my-project",
"token": "auth-token-123",
"id": "conversation-uuid-123",
"message": "What's the weather like in Orlando?",
"role": "user"
},
"id": "req-2"
}
{
"jsonrpc": "2.0",
"result": {
"response": "Let me check the current weather in Orlando for you. The weather is currently partly cloudy with a temperature of 91.9°F degrees."
},
"id": "req-2"
}
If you include config_url
in a chat request for a non-existent conversation, it will be created automatically:
{
"jsonrpc": "2.0",
"method": "chat",
"params": {
"project_id": "my-project",
"token": "auth-token-123",
"id": "new-conversation-123",
"message": "Hello there!",
"config_url": "https://example.com/config.yaml"
},
"id": "req-3"
}
Permanently deletes a conversation and all its data.
Parameter | Type | Required | Description |
---|---|---|---|
project_id |
string | ✅ | Project identifier |
token |
string | ✅ | Authentication token |
id |
string | ✅ | Conversation identifier to delete |
{
"jsonrpc": "2.0",
"method": "delete",
"params": {
"project_id": "my-project",
"token": "auth-token-123",
"id": "conversation-uuid-123"
},
"id": "req-4"
}
{
"jsonrpc": "2.0",
"result": {
"status": "deleted",
"id": "conversation-uuid-123"
},
"id": "req-4"
}
Marks a conversation as ended and moves it to the processed conversations table for analytics.
Parameter | Type | Required | Description |
---|---|---|---|
project_id |
string | ✅ | Project identifier |
token |
string | ✅ | Authentication token |
id |
string | ✅ | Conversation identifier to end |
{
"jsonrpc": "2.0",
"method": "end_conversation",
"params": {
"project_id": "my-project",
"token": "auth-token-123",
"id": "conversation-uuid-123"
},
"id": "req-5"
}
Successfully Ended:
{
"jsonrpc": "2.0",
"result": {
"status": "ended",
"id": "conversation-uuid-123"
},
"id": "req-5"
}
Conversation Not Found:
{
"jsonrpc": "2.0",
"result": {
"status": "not_found",
"id": "conversation-uuid-123"
},
"id": "req-5"
}
The API uses standard JSON-RPC 2.0 error codes plus custom application-specific codes.
Code | Message | Description |
---|---|---|
-32700 | Parse error | Invalid JSON received |
-32600 | Invalid Request | Invalid JSON-RPC request |
-32601 | Method not found | Unknown method |
-32602 | Invalid params | Invalid method parameters |
-32603 | Internal error | Internal server error |
Code | Message | Description |
---|---|---|
-32001 | Conversation not found | Conversation doesn't exist |
-32002 | Config fetch error | Failed to fetch configuration |
-32003 | OpenAI API error | AI service error |
-32004 | Database error | Database operation failed |
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Missing required key: project_id",
"details": "Additional error information (optional)"
},
"id": "req-1"
}
Missing Required Parameter:
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Missing required key: project_id"
},
"id": "req-1"
}
Invalid Method:
{
"jsonrpc": "2.0",
"error": {
"code": -32601,
"message": "Unknown method: invalid_method"
},
"id": "req-1"
}
Database Error:
{
"jsonrpc": "2.0",
"error": {
"code": -32004,
"message": "Database operation failed"
},
"id": "req-1"
}
The config_url
parameter should point to a YAML file containing the conversation configuration:
# Example configuration
SWAIG:
defaults:
web_hook_url: "https://api.example.com/webhook"
functions:
- function: "get_weather"
description: "Get current weather for a location"
parameters:
type: "object"
properties:
location:
type: "string"
description: "City name or location"
data_map:
webhooks:
- url: "https://api.weather.com/v1/current?location=${args.location}"
method: "GET"
headers:
"X-API-Key": "your-api-key"
output:
response: "The weather in ${location.name} is ${current.condition} with ${current.temp_f}°F"
prompt:
text: "You are a helpful weather assistant."
temperature: 0.7
params:
conversation_timeout: 3600
sliding_window: 50
The AI can call external functions through the SWAIG (SignalWire AI Gateway) system:
${variable}
or %{variable}
- Basic variable substitution${object.property}
- Nested object access${array[0]}
- Array element access${enc:variable}
- URL encoding${b64enc:variable}
- Base64 encoding${json:variable}
- JSON encoding# 1. Create conversation
curl -X POST http://localhost:8080/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "create_conversation",
"params": {
"project_id": "demo-project",
"token": "demo-token",
"id": "demo-conversation-1",
"config_url": "https://example.com/chatbot-config.yaml"
},
"id": "1"
}'
# 2. Send messages
curl -X POST http://localhost:8080/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "chat",
"params": {
"project_id": "demo-project",
"token": "demo-token",
"id": "demo-conversation-1",
"message": "What'\''s the weather in Miami?"
},
"id": "2"
}'
# 3. End conversation
curl -X POST http://localhost:8080/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "end_conversation",
"params": {
"project_id": "demo-project",
"token": "demo-token",
"id": "demo-conversation-1"
},
"id": "3"
}'
import aiohttp
import asyncio
import json
async def chat_example():
async with aiohttp.ClientSession() as session:
# Create conversation
create_request = {
"jsonrpc": "2.0",
"method": "create_conversation",
"params": {
"project_id": "my-project",
"token": "my-token",
"id": "python-chat-1",
"config_url": "https://example.com/config.yaml"
},
"id": "1"
}
async with session.post('http://localhost:8080/', json=create_request) as resp:
result = await resp.json()
print("Created:", result)
# Send message
chat_request = {
"jsonrpc": "2.0",
"method": "chat",
"params": {
"project_id": "my-project",
"token": "my-token",
"id": "python-chat-1",
"message": "Hello, how are you?"
},
"id": "2"
}
async with session.post('http://localhost:8080/', json=chat_request) as resp:
result = await resp.json()
print("AI Response:", result['result']['response'])
# Run the example
asyncio.run(chat_example())
const axios = require('axios');
async function chatExample() {
const baseURL = 'http://localhost:8080/';
// Create conversation
const createResponse = await axios.post(baseURL, {
jsonrpc: "2.0",
method: "create_conversation",
params: {
project_id: "js-project",
token: "js-token",
id: "js-conversation-1",
config_url: "https://example.com/config.yaml"
},
id: "1"
});
console.log("Created:", createResponse.data);
// Send message
const chatResponse = await axios.post(baseURL, {
jsonrpc: "2.0",
method: "chat",
params: {
project_id: "js-project",
token: "js-token",
id: "js-conversation-1",
message: "Tell me a joke"
},
id: "2"
});
console.log("AI Response:", chatResponse.data.result.response);
}
chatExample().catch(console.error);
Enable verbose logging with environment variable:
VERBOSE_LOGGING=true
The service provides connection pool monitoring and performance metrics.
All errors include detailed logging with request IDs for tracing.
Use the included cli_test.py
for interactive testing:
# Interactive chat
python cli_test.py \
--project-id "test-project" \
--token "test-token" \
--convo-id "test-conversation" \
--config-url "https://example.com/config.yaml" \
--verbose
# Direct message
python cli_test.py \
--project-id "test-project" \
--token "test-token" \
--convo-id "test-conversation" \
--chat-first "Hello there!" \
--config-url "https://example.com/config.yaml"
# Delete conversation
python cli_test.py \
--project-id "test-project" \
--token "test-token" \
--convo-id "test-conversation" \
--delete
docker-compose logs web