Skip to main content

Expression built-in functions

Asgard's Expression system provides eight functions for handling conversation history, data conversion and encoding inside dynamic content.

The functions​

Conversation history​

history​

Returns the conversation history over an index range.

Syntax:

history(start, end)

Parameters:

  • start (number): where to start, from 0, with negative values counting from the end
  • end (number): where to stop, inclusive, with negative values counting from the end

Returns:

  • string: the history as plain text, one message per line

Examples:

// the three messages at indexes 0, 1 and 2
history(0, 2)

// the last three messages
history(-3, -1)

// everything
history(0, -1)

The returned format:

bot: Hi, how can I help you?
user: Hello, I need assistance with my order.
bot: Okay, please provide your order number.

historySize​

Returns how many messages the channel's history holds.

Syntax:

historySize()

Returns:

  • number: the message count

Example:

// returns a number, for example 5
historySize()

Data handling​

urlEncode​

URL-encodes a string.

Syntax:

urlEncode(val)

Parameters:

  • val (string): the string to encode

Returns:

  • string: the encoded result

Examples:

// "hello%20world"
urlEncode('hello world')

// "%E6%90%9C%E5%B0%8B%E9%97%9C%E9%8D%B5%E5%AD%97"
urlEncode('搜尋關鍵字')

// URL-encode the previous message
urlEncode(prevMessage)

vecToStr​

Converts a vector array into a string.

Syntax:

vecToStr(vector, prefix, suffix, delimiter)

Parameters:

  • vector (array<number>): the vector array
  • prefix (string): the opening character
  • suffix (string): the closing character
  • delimiter (string): the separator

Returns:

  • string: the converted string

Examples:

// "{1,2,3}"
vecToStr([1, 2, 3], '{', '}', ',')

// "[0.1|0.5|0.8]"
vecToStr([0.1, 0.5, 0.8], '[', ']', '|')

xpathExtract​

Looks up a value in an XML document with XPath.

Syntax:

xpathExtract(xml, path)

Parameters:

  • xml (string): the XML document
  • path (string): the XPath query

Returns:

  • string: the inner text of every matching element, separated by newlines

Examples:

const xml = '<root><item>1</item><item>2</item></root>'
// "1\n2"
xpathExtract(xml, '/root/item')

// every result title
xpathExtract(responseXml, '//result/title')

Date and time​

isoNow​

Returns the current date and time in a given timezone, as an RFC3339 string.

Syntax:

isoNow(timezone)

Parameters:

  • timezone (string): an IANA timezone name

Returns:

  • string: the current date and time in RFC3339

Examples:

// "2025-05-27T01:08:44+08:00"
isoNow('Asia/Taipei')

// "2025-05-26T17:08:44Z"
isoNow('UTC')

// "2025-05-26T13:08:44-04:00"
isoNow('America/New_York')

isoToday​

Returns the current date in a given timezone, as an RFC3339 string.

Syntax:

isoToday(timezone)

Parameters:

  • timezone (string): an IANA timezone name

Returns:

  • string: the current date in RFC3339

Examples:

// "2025-05-27"
isoToday('Asia/Taipei')

// "2025-05-26"
isoToday('UTC')

// "2025-05-26"
isoToday('America/New_York')

Fuller examples​

Analysing and summarising a conversation​

// look at how the conversation is going
(() => {
const totalMessages = historySize();
if (totalMessages === 0) return 'no conversation yet';

// take the recent messages to analyse
const recentCount = Math.min(10, totalMessages);
const recentHistory = history(-recentCount, -1);

const lines = recentHistory.split('\n');
const userMessages = lines.filter(line => line.startsWith('user:')).length;
const botMessages = lines.filter(line => line.startsWith('bot:')).length;

return `Across the last ${recentCount} messages: ${userMessages} from the user, ${botMessages} from the bot`;
})()

Integrating with an API​

// build a query URL
(() => {
const keyword = prevMessage || '';
const encodedQuery = urlEncode(keyword);
const timestamp = isoNow('UTC');

// build the query string
const params = [`q=${encodedQuery}`, `timestamp=${timestamp}`, `channel=${customChannelId || 'default'}`].join('&');

return `https://api.example.com/search?${params}`;
})()

Parsing XML​

// handle a richer XML response
(() => {
if (!xmlResponse) return 'no XML data';

try {
const titles = xpathExtract(xmlResponse, '//result/title');
const prices = xpathExtract(xmlResponse, '//result/price');

if (!titles) return 'no results';

const titleList = titles.split('\n');
const priceList = prices ? prices.split('\n') : [];

let result = 'Results:\n';
titleList.forEach((title, index) => {
const price = priceList[index] || 'price unknown';
result += `${index + 1}. ${title} - ${price}\n`;
});

return result;
} catch (e) {
return 'XML parse error';
}
})()

Handling vectors​

// format a vector for several consumers
(() => {
const userVector = [0.1, 0.5, 0.8, 0.2];
const systemVector = [0.2, 0.4, 0.7, 0.3];

const formats = {
json: vecToStr(userVector, '[', ']', ','),
csv: vecToStr(userVector, '', '', ','),
sql: vecToStr(userVector, '(', ')', ','),
};

return `Formatted:
JSON: ${formats.json}
CSV: ${formats.csv}
SQL: ${formats.sql}`;
})()

Timestamped logging​

// build a log line with a timestamp
(() => {
const timezone = 'Asia/Taipei';
const now = isoNow(timezone);
const today = isoToday(timezone);

const messageCount = historySize();
const hasError = prevError ? true : false;

const logEntry = {
date: today,
timestamp: now,
messages: messageCount,
hasError: hasError,
channel: customChannelId || 'unknown',
};

return `[${now}] log: channel ${logEntry.channel}, ${logEntry.messages} messages${hasError ? ', with an error' : ''}`;
})()

Performance​

Cache what you call​

// ✅ cache the values you reuse rather than calling again
(() => {
const messageCount = historySize(); // called once
const timezone = 'Asia/Taipei';
const currentTime = isoNow(timezone); // called once

if (messageCount === 0) {
return `[${currentTime}] a new conversation`;
}

const recentHistory = messageCount > 5 ? history(-5, -1) : history(0, -1);

return `[${currentTime}] ${messageCount} messages\n${recentHistory}`;
})()

Call conditionally​

// ✅ avoid calls you do not need
(() => {
// check the basics first
if (!prevMessage) return 'nothing to process';

// only encode when encoding is needed
const needsEncoding = /[^\w\s]/.test(prevMessage);
const processedMessage = needsEncoding ? urlEncode(prevMessage) : prevMessage;

return `Result: ${processedMessage}`;
})()

These functions cover the data handling an Expression needs for conversation logic and format conversion.