メインコンテンツまでスキップ

Expression の組み込み関数

Asgard の Expression には、対話履歴の扱い、データ変換、エンコードのための関数が 8 つ用意されています。

関数の一覧​

対話履歴​

history​

指定した索引の範囲で対話履歴を返します。

構文:

history(start, end)

引数:

  • start (number): 開始位置。0 から始まり、負の値は末尾からの数え方です
  • end (number): 終了位置。その位置を含みます。負の値は末尾からの数え方です

戻り値:

  • string: 対話履歴のプレーンテキスト。1 行が 1 件の対話にあたります

例:

// 索引 0、1、2 の 3 件
history(0, 2)

// 末尾から 3 件
history(-3, -1)

// すべて
history(0, -1)

戻り値の形式:

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

historySize​

チャネルの対話履歴の件数を返します。

構文:

historySize()

戻り値:

  • number: 対話の件数

例:

// 数値を返します。たとえば 5
historySize()

データ処理​

urlEncode​

文字列を URL エンコードします。

構文:

urlEncode(val)

引数:

  • val (string): エンコードする文字列

戻り値:

  • string: エンコードした結果

例:

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

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

// 直前のメッセージを URL エンコードする
urlEncode(prevMessage)

vecToStr​

ベクトルの配列を文字列に変換します。

構文:

vecToStr(vector, prefix, suffix, delimiter)

引数:

  • vector (array<number>): ベクトルの配列
  • prefix (string): 先頭の文字
  • suffix (string): 末尾の文字
  • delimiter (string): 区切り文字

戻り値:

  • string: 変換した文字列

例:

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

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

xpathExtract​

XPath で XML 文書から値を取り出します。

構文:

xpathExtract(xml, path)

引数:

  • xml (string): XML 文書
  • path (string): XPath のクエリ

戻り値:

  • string: 一致したすべての要素の内容を、改行で区切って返します

例:

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

// すべての結果の見出しを取得する
xpathExtract(responseXml, '//result/title')

日付と時刻​

isoNow​

指定したタイムゾーンの現在の日時を RFC3339 形式の文字列で返します。

構文:

isoNow(timezone)

引数:

  • timezone (string): IANA のタイムゾーン名

戻り値:

  • string: RFC3339 形式の現在の日時

例:

// "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​

指定したタイムゾーンの現在の日付を RFC3339 形式の文字列で返します。

構文:

isoToday(timezone)

引数:

  • timezone (string): IANA のタイムゾーン名

戻り値:

  • string: RFC3339 形式の現在の日付

例:

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

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

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

応用例​

対話の分析と要約​

// 対話の傾向を見る
(() => {
const totalMessages = historySize();
if (totalMessages === 0) return '対話の記録がありません';

// 分析のために直近の対話を取得する
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 `直近 ${recentCount} 件のうち、ユーザー ${userMessages} 件、ボット ${botMessages} 件`;
})()

API との連携​

// 照会用の URL を組み立てる
(() => {
const keyword = prevMessage || '';
const encodedQuery = urlEncode(keyword);
const timestamp = isoNow('UTC');

// クエリ文字列を組み立てる
const params = [`q=${encodedQuery}`, `timestamp=${timestamp}`, `channel=${customChannelId || 'default'}`].join('&');

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

XML の解析​

// 複雑な XML の応答を扱う
(() => {
if (!xmlResponse) return 'XML データがありません';

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

if (!titles) return '検索結果がありません';

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

let result = '検索結果:\n';
titleList.forEach((title, index) => {
const price = priceList[index] || '価格不明';
result += `${index + 1}. ${title} - ${price}\n`;
});

return result;
} catch (e) {
return 'XML の解析エラー';
}
})()

ベクトルの扱い​

// 複数の形式に整える
(() => {
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 `整形の結果:
JSON: ${formats.json}
CSV: ${formats.csv}
SQL: ${formats.sql}`;
})()

時刻付きのログ​

// タイムスタンプ付きのログ行を作る
(() => {
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}] ログ: チャネル ${logEntry.channel}、${logEntry.messages} 件のメッセージ${hasError ? '、エラーあり' : ''}`;
})()

性能について​

呼び出した値を持ち回す​

// ✅ 再利用する値は変数に置き、同じ関数を何度も呼ばない
(() => {
const messageCount = historySize(); // 一度だけ呼ぶ
const timezone = 'Asia/Taipei';
const currentTime = isoNow(timezone); // 一度だけ呼ぶ

if (messageCount === 0) {
return `[${currentTime}] 新しい対話の開始`;
}

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

return `[${currentTime}] 対話の記録: ${messageCount} 件\n${recentHistory}`;
})()

条件付きで呼ぶ​

// ✅ 不要な呼び出しを避ける
(() => {
// まず基本の条件を確認する
if (!prevMessage) return '処理するメッセージがありません';

// エンコードが必要なときだけ呼ぶ
const needsEncoding = /[^\w\s]/.test(prevMessage);
const processedMessage = needsEncoding ? urlEncode(prevMessage) : prevMessage;

return `処理結果: ${processedMessage}`;
})()

これらの関数により、Expression の中で対話の論理と形式変換に必要なデータ処理を行えます。