Skip to main content

Deferred Annotations

The sections on this page provide information about the various aspects of Deferred Annotations:

Concept

Deferred Annotations allow for the creation of on-demand annotations and provide a way to control potentially expensive actions, such as calls to Gen AI Models or databases, within a solution. Deferred Annotations ensure these expensive actions are executed only when they are needed and only the minimum number of times.

This is implemented natively in the engine so that:

  • The solution developer uses the annotations in the same way as any other annotation, meaning usage is seamless for the developer.
  • The engine then ensures that the annotation script is executed only when the annotation is needed, meaning execution is optimized to minimize impact on costs, latency, etc.

By calling expensive or time-consuming actions on demand during the matching process, Deferred Annotations provide solution developers with a tool for optimizing solutions at runtime. They can be used to control:

  • Latency - a slow process can be deferred and only run once, and only if it is actually needed.
  • Cost - an expensive process will be called only when needed and maximum once per transaction.
  • Log Size/Clarity - many Deferred Annotations can be created but they will only be logged to the session log when actually used in testing.

Gen AI Annotators also make use of Deferred Annotations to create their annotations “behind the scenes”. By combining Deferred Annotations (either directly or via Gen AI Annotators) and Secrets, potentially expensive calls (such as Gen AI) can be encapsulated securely to not leak sensitive data. Also, they can be used seamlessly within the solution to ensure that the developer has the information needed to build a fully hybrid Gen AI solution, which automatically optimizes its own cost.

Deferred Annotation Script

A Deferred Annotation document consist of a list of Annotations and a script responsible for creating the listed annotation(s) using the engine method _.createInputAnnotation.

When one of the declared annotations is tested for the first time, the script of the Deferred Annotation will be requested and executed. An annotation is considered "tested” when a TLML Syntax containing the annotation is considered for matching, e.g. if a trigger or transition is tested and it contains a TLML match containing the annotation. If it (or any other annotation declared by the same Deferred Annotation) is already deferred at this stage, then the script is not executed again. If none of the declared annotations are tested against an input, then the script will not be executed for that transaction.

note

Please note that the script of a Deferred Annotation also would be requested and executed if calling the Engine method _.getInputAnnotations().getAll() in scripting.

This allows you to configure to use Annotations as needed within the solution, while Teneo ensures that they are only processed if and when they are needed.

UI

Deferred Annotations Overview

You can access Deferred Annotations from the backstage view of your Solution from the Globals section and the Annotations tab.

deferred annotations overview

Deferred Annotations Window

When you open a Deferred Annotation, the following window opens:

deferred annotations window

In the Deferred Annotations window, the following information is available:

  • Top ribbon
  • List of Deferred Annotations
  • Execution script
  • Used By
ACCESS USED BY FLOWS

To open a Flow that uses a Deferred Annotation: Ctrl + Click. To edit a Flow that uses a Deferred Annotation: Ctrl + Alt.

Top ribbon:

SectionButtonDescriptionRelated pages
Deferred AnnotationsCloseCloses the Deferred Annotations window.
SaveSaves the current Deferred Annotation.
EditUndoUndoes the recent action.
RedoRedoes the recent action.
Stable versionSetSets stable version.Versioning
UnsetUnsets stable version.Versioning
BranchingIncludeIncludes Deferred Annotation in branching.Localization
ExcludeExcludes Deferred Annotation from branching.Localization
ScriptGenerateCreates a draft for a Deferred Annotation script to be adapted.
TODO

A TODO label is shown for a Deferred Annotation without a script, indicating that the implementation of the script still is pending. To get started, a draft of the script can be created with the Generate button.

Deferred Annotations Properties

The Deferred Annotations Properties window opens when you add a new Deferred Annotation:

deferred annotations properties

In the Properties window, the following information is available:

  • Name and Description: give the Deferred Annotation a name and a description
  • Save: save Deferred Annotation
  • History: observe versions of Deferred Annotation
  • Close: close Deferred Annotation
  • Top arrow: go back to the Deferred Annotations Window

Practical Examples

Check for Credit card number

Let's add a Deferred Annotation that finds and annotates a credit card number when it appears in the user input:

  1. Add a new Deferred Annotation and give it a name like Creditcard numbers.

  2. Add an annotation named CREDITCARD_NUMBER.

  3. Add to the Deferred Annotation the following script:

    //Find a credit card number in the input using a regex
    def generalCreditCardRegex = /\b(?:\d[ -]*?){13,16}\b/
    // Remove any blank spaces from the number for the variable value
    def normalizeNumber = number -> number.replace(' ', '')

    def matchToWordIndexes = (match, sentence) -> sentence.words.findIndexValues {
    it.beginIndex >= match.start()
    && it.endIndex <= match.end()
    }.collect { it as Integer } as HashSet<Integer>

    _.sentences.eachWithIndex { sentence, sentenceIndex ->
    def regexMatches = sentence.text =~ generalCreditCardRegex
    regexMatches.results().each { match ->
    _.getInputAnnotations().add(
    _.createInputAnnotation(
    'CREDITCARD_NUMBER',
    sentenceIndex,
    matchToWordIndexes(match, sentence),
    ["cardNumber": normalizeNumber(match.group())]
    )
    )
    }
    }
  4. Now, create a flow where you want to match if a user input contains a credit card number. Add to its Tigger a TLML syntax match with the syntax: %$CREDITCARD_NUMBER. If you want to save the value from the annotation variable, you can add a flow variable called cardNumber to the flow and add a propagation script to fetch the variable value from the annotation: %$CREDITCARD_NUMBER^{cardNumber=lob.cardNumber}.

When testing with an input in in Tryout that contains a numeric sequence that corresponds to a credit card number, the flow should be triggered, the variable should be populated with the sequence and you should see the annotation in the Annotations section under Input in Advanced Tryout. If the input does not contain the number sequence, you can see that the annotation is not created.