Using back_to_back_functions
The back_to_back_functions
property of a SWAIG function, when set to true
, tells the AI that
it is allowed to invoke another function directly after a function has finished executing. It is
false
by default.
Being able to explicitly tell the AI to invoke another function with the results of the current function is very useful in certain situations. It makes composing multiple SWAIG functions extremely simple. The AI is usually smart enough to decide what function to use, and whether to use it or not, based on the intermediate results it gets.
Usage
Whether you're using a SWAIG data map's expression or a webhook, the back_to_back_functions
feature
can be enabled inside the action
block of the function.
- YAML
- JSON
functions:
- function: getIntermediateValue
purpose: Get some information from server
data_map:
webhooks:
- url: example.com/intermediate
method: GET
output:
response: process the intermediate `${value}` using the `finalStep` function.
action:
- back_to_back_functions: true
{
"functions": [
{
"function": "getIntermediateValue",
"purpose": "Get some information from server",
"data_map": {
"webhooks": [
{
"url": "example.com/intermediate",
"method": "GET",
"output": {
"response": "process the intermediate `${value}` using the `finalStep` function.",
"action": [
{
"back_to_back_functions": true
}
]
}
}
]
}
}
]
}
With back_to_back_functions
set to true
, AI will automatically invoke the finalStep
function with required arguments.
Example
Consider the following pipeline, where you are querying for a piece of data from a certain server, decoding it, then decrypting it with a separate SWAIG function.
This pipeline can be realised with the following SWML:
- YAML
- JSON
version: 1.0.0
sections:
main:
- answer
- ai:
prompt:
text: Say "Hi".
1. Get the secret message using the `getSecretMessage` function.
2. Decode it using the `decode` function.
3. Decrypt it using the `decrypt` function. The key is 'blue'.
4. Say the decrypted message, then hang up.
params:
swaig_allow_swml: true
SWAIG:
functions:
- function: getSecretMessage
purpose: Get the secret message from the server
data_map:
webhooks:
- url: https://<NGROK UUID>.ngrok-free.app/secret_information
method: GET
output:
response:
The secret data was acquired. It is `${b64}`. Decode it using the
`decode` function.
action:
- back_to_back_functions: true
- function: decode
purpose: Decode the given message
argument:
type: object
properties:
encoded_message:
type: string
description: The encoded message to decode
data_map:
webhooks:
- url: https://<NGROK UUID>.ngrok-free.app/decode?enc=${args.encoded_message}
method: GET
output:
response: The decoded message is `${decoded_message}`. Use the `decrypt` function to decrypt it.
action:
- toggle_functions:
- active: true
function: decrypt
- back_to_back_functions: true
- function: decrypt
active: false
purpose: Decrypt the given message
argument:
type: object
properties:
encrypted_message:
type: string
description: The encrypted message to decrypt
key:
type: string
description: The key used for decoding
data_map:
webhooks:
- url: https://<NGROK UUID>.ngrok-free.app/decrypt?enc=${args.encrypted_message}&key=${args.key}
method: GET
output:
response: The decrypted message is ${original}
{
"version": "1.0.0",
"sections": {
"main": [
"answer",
{
"ai": {
"prompt": {
"text": "Say \"Hi\". 1. Get the secret message using the `getSecretMessage` function. 2. Decode it using the `decode` function. 3. Decrypt it using the `decrypt` function. The key is 'blue'. 4. Say the decrypted message, then hang up."
},
"params": {
"swaig_allow_swml": true
},
"SWAIG": {
"functions": [
{
"function": "getSecretMessage",
"purpose": "Get the secret message from the server",
"data_map": {
"webhooks": [
{
"url": "https://<NGROK UUID>.ngrok-free.app/secret_information",
"method": "GET",
"output": {
"response": "The secret data was acquired. It is `${b64}`. Decode it using the `decode` function.",
"action": [
{
"back_to_back_functions": true
}
]
}
}
]
}
},
{
"function": "decode",
"purpose": "Decode the given message",
"argument": {
"type": "object",
"properties": {
"encoded_message": {
"type": "string",
"description": "The encoded message to decode"
}
}
},
"data_map": {
"webhooks": [
{
"url": "https://<NGROK UUID>.ngrok-free.app/decode?enc=${args.encoded_message}",
"method": "GET",
"output": {
"response": "The decoded message is `${decoded_message}`. Use the `decrypt` function to decrypt it.",
"action": [
{
"toggle_functions": [
{
"active": true,
"function": "decrypt"
}
]
},
{
"back_to_back_functions": true
}
]
}
}
]
}
},
{
"function": "decrypt",
"active": false,
"purpose": "Decrypt the given message",
"argument": {
"type": "object",
"properties": {
"encrypted_message": {
"type": "string",
"description": "The encrypted message to decrypt"
},
"key": {
"type": "string",
"description": "The key used for decoding"
}
}
},
"data_map": {
"webhooks": [
{
"url": "https://<NGROK UUID>.ngrok-free.app/decrypt?enc=${args.encrypted_message}&key=${args.key}",
"method": "GET",
"output": {
"response": "The decrypted message is ${original}"
}
}
]
}
}
]
}
}
}
]
}
}
There are a few things to note in the example above:
-
Only the functions
getSecretMessage
anddecode
have theback_to_back_functions
flag set totrue
. We only intend those two functions to call the next function in the pipeline. Thedecrypt
function is the end of the chain. -
We use the
toggle_functions
mechanism to keep thedecrypt
function disabled unless thedecode
function has been called. This is to make sure that the AI doesn't ever jump straight from fetching the secret data to attempting to decrypt it without decoding it.
A minimal server for this SWML script can be written as follows:
const express = require("express");
const app = express();
const crypto = require("crypto");
app.use(express.json());
// Function to decrypt text with AES using a key
function decrypt(encryptedText, key) {
const decipher = crypto.createDecipher("aes-256-cbc", key);
let decrypted = decipher.update(encryptedText, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
}
app.get("/secret_information", (req, res) => {
res.json({
b64: "MDIwMTUyMWNjZWRiMmJmY2JmNDllOTFkMTI5NzQyMzYwYTA5YWU1NmZhNDFiYTljZGUzNDU5NTBiNzQ1YjExYQ==",
});
});
app.get("/decode", (req, res) => {
const { enc } = req.query;
const decoded_message = Buffer.from(enc, "base64").toString("utf-8");
res.json({ decoded_message });
});
app.get("/decrypt", (req, res) => {
const { key, enc } = req.query;
const original = decrypt(enc, key);
res.json({ original });
});
const port = 6000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
This server (running on localhost
) can be made accessible to the wider web (and thus this SWML script) using forwarding tools like ngrok
.
You can follow our Testing webhooks with ngrok guide to learn how.
Conclusion
You can use the back_to_back_functions
mechanism to create very complex interactions all managed by an intelligent agent.
If you're looking for more examples, the set_meta_data
tutorial also
demonstrates the use of back_to_back_functions
.