Skip to main content

REFERENCE

Developer Reference

Authentication, APIs, SDKs, Flow Agent processors and parameter resolution, in full.

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.

  1. 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}}
  2. 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';
  3. 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}}
  4. 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}}
  5. 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.

Ready to get started?

Want to see how Asgard fits your team? Talk to us.

Contact us