Skip to main content

Built-in variables

Asgard's Expression and Template systems provide built-in variables, so a workflow can read the conversation, file details and channel state as it runs.

The variables​

Conversation​

prevMessage​

  • Type: string
  • What it is: the previous user message
  • Using it:
// Expression
prevMessage || 'no message'
{{! Template }}
{{#if prevMessage}}
You said: {{prevMessage}}
{{/if}}

prevBlobs​

  • Type: array<Blob>
  • What it is: the files attached to the previous message
  • Using it:
// Expression
prevBlobs && prevBlobs.length > 0 ? `Received ${prevBlobs.length} files` : 'no files'
{{! Template }}
{{#if prevBlobs}}
Files:
{{#each prevBlobs}}
• {{fileName}} ({{size}} bytes)
{{/each}}
{{/if}}

prevPayload​

  • Type: object
  • What it is: the payload carried by the previous message
  • Using it:
// Expression
prevPayload && prevPayload.userAction
{{! Template }}
{{#if prevPayload}}
Payload: {{{toJson prevPayload}}}
{{/if}}

prevError​

  • Type: string
  • What it is: the most recent processor error
  • Using it:
// Expression
prevError ? `An error occurred: ${prevError}` : 'processed normally'
{{! Template }}
{{#if prevError}}
Error: {{prevError}}
{{else}}
Processed successfully
{{/if}}

Channel​

customChannelId​

  • Type: string
  • What it is: the custom channel id
  • Using it:
// Expression
`Channel: ${customChannelId}`
{{! Template }}
Current channel: {{customChannelId}}

customMessageId​

  • Type: string
  • What it is: the previous message's custom id, an empty string when the client did not supply one
  • Using it:
// Expression
customMessageId || 'no custom id'
{{! Template }}
{{#if customMessageId}}
Message id: {{customMessageId}}
{{/if}}

The Blob object​

interface Blob {
blobId: number; // the blob's id
fileType: FileType; // the file's type
fileName?: string; // the original filename, optional
size: number; // size in bytes
mime: string; // MIME type
}

type FileType = 'BINARY' | 'IMAGE' | 'VIDEO' | 'AUDIO' | 'DOCUMENT';

Reading variables​

Reading them safely​

Expression mode

// check a variable exists
prevMessage && prevMessage.length > 0 ? prevMessage : 'no message'

// use a logical operator
prevMessage || 'a default message'

// index into an array safely
prevBlobs && prevBlobs[0] && prevBlobs[0].fileName

// check an object property
prevPayload && 'property' in prevPayload ? prevPayload.property : 'a default'

Template mode

{{#if prevMessage}}
There is a message: {{prevMessage}}
{{else}}
No message
{{/if}}

{{#each prevBlobs}}
File
{{@index}}:
{{fileName}}
{{/each}}

Worked examples​

Checking the conversation's state​

// Expression: a full state check
(() => {
let status = [];

if (prevMessage) {
status.push(`Message: ${prevMessage.substring(0, 50)}...`);
}

if (prevBlobs && prevBlobs.length > 0) {
status.push(`Files: ${prevBlobs.length}`);
}

if (prevError) {
status.push(`Error: ${prevError}`);
}

return status.length > 0 ? status.join(' | ') : 'no state';
})()
{{! Template: a status report }}
• Conversation state

{{#if prevMessage}}
• Last message: {{prevMessage}}
{{else}}
• No message yet
{{/if}}

{{#if prevBlobs}}
• Files:
{{#each prevBlobs}}
• {{fileName}} ({{fileType}}, {{size}} bytes)
{{/each}}
{{else}}
• No attachments
{{/if}}

{{#if prevError}}
• Error: {{prevError}}
{{else}}
• Running normally
{{/if}}

• Channel: {{customChannelId}}

Handling files​

// Expression: counting files by type
(() => {
if (!prevBlobs || prevBlobs.length === 0) {
return 'no files';
}

const stats = {};
prevBlobs.forEach(blob => {
stats[blob.fileType] = (stats[blob.fileType] || 0) + 1;
});

return Object.entries(stats)
.map(([type, count]) => `${type}: ${count}`)
.join(', ');
})()
{{! Template: file details }}
{{#if prevBlobs}}
• Files:
{{#each prevBlobs}}
{{@index}}.
{{fileName}}
• Type: {{fileType}}
• Size: {{size}} bytes
• MIME: {{mime}}
• Id: {{blobId}}
{{/each}}
{{/if}}

Common questions​

Q: How do I check whether a variable exists?

// Expression
typeof prevMessage !== 'undefined' && prevMessage !== null

// checks undefined and null at once
prevMessage != null
{{! Template }}
{{#if prevMessage}}
The variable exists
{{/if}}

Q: How do I handle an empty array?

// Expression
prevBlobs && Array.isArray(prevBlobs) && prevBlobs.length > 0
{{! Template }}
{{#if prevBlobs}}
{{#if prevBlobs.length}}
There are files
{{/if}}
{{/if}}

Q: How do I read a file property safely?

// Expression
prevBlobs && prevBlobs[0] && prevBlobs[0].fileName
{{! Template }}
{{#if prevBlobs}}
{{#each prevBlobs}}
{{#if fileName}}
Filename: {{fileName}}
{{/if}}
{{/each}}
{{/if}}

Q: How do I work with the payload?

// Expression: reading a payload property safely
prevPayload && typeof prevPayload === 'object' && 'action' in prevPayload ? prevPayload.action : 'no action'
{{! Template: showing the payload }}
{{#if prevPayload}}
Payload: {{{toJson prevPayload}}}
{{/if}}

Using these variables properly is what makes a conversation feel informed and personal.