For the complete documentation index, see llms.txt. This page is also available as Markdown.

Behavior Rules

Overview

Behavior Rules are the decision-making engine in EDDI's Lifecycle Pipeline. They are IF-THEN rules that evaluate conversation state and trigger actions based on conditions. This is where you define when to call an LLM, when to invoke an API, and how your agent responds to user inputs.

Role in the Lifecycle

In EDDI's processing pipeline, Behavior Rules sit between input parsing and action execution:

User Input → Parser → Behavior Rules → API/LLM Calls → Output Generation

Behavior Rules examine the conversation memory (including parsed input, context data, and conversation history) and decide:

  • Which actions to trigger

  • Whether to call an LLM or skip it

  • Whether to make external API calls

  • What output to generate

Key Concepts

  • Rules are IF-THEN logic: If all conditions match, execute the specified actions

  • Rules are grouped: Multiple rules can be organized into groups for better structure

  • Sequential execution: Rules within a group execute in order until one succeeds

  • First match wins: Once a rule in a group succeeds, remaining rules in that group are skipped

  • Actions trigger other lifecycle tasks: Actions like httpcall(weather-api) or send_to_llm activate other parts of the pipeline

Behavior Rules Structure

Behavior Rules are very flexible in structure to cover most use cases that you will come across. Behavior Rules are clustered in Groups. Behavior Rules are executed sequentially within each Group. As soon as one Behavior Rule succeeds, all remaining Behavior Rules in this Group will be skipped.

Groups

Type of Conditions

Each Behavior Rule has a list of conditions, that, depending on the condition , might have a list of sub-conditions.

If all conditions are true, then the Behavior Rule is successful and it will trigger predefined actions.

List of available conditions:

General Structure

conditions are always children of either a Behavior Rule or another condition. It will always follows that same structure.

Description of condition structure

Input Matcher

The inputmatcher is used to match user inputs. Not directly the real input of the user, but the meaning of it, represented by expressions that are resolved from by the parser.

Description

Element
Value
Description

type

inputmatcher

configs

expressions

comma separated list of

expressions such as:

expression(value),expression2(value2),

yetAnotherExpressions(anotherValue(withASubValue))

occurrence

currentStep - used in case if the user said it in this conversationStep

lastStep - used in case if the user said it in the previous conversationStep

anyStep - used in case if the user said it in any step if this whole conversation

never - used in case if the user has never said that, including the current step

If the user would type "hello", and the parser resolves this as expressions "greeting(hello)" [assuming it has been defined in one of the dictionaries], then a condition could look as following in order to match this user input meaning:

This inputmatcher condition will match any expression of type greeting, may that be "greeting(hello)", "greeting(hi)" or anything else. Of course, if you would want to match greeting(hello) explicitly, you would put "greeting(hello)" as value for the "expressions" field.

Context Matcher

The contextmatcher is used to match context data that has been handed over to EDDI alongside the user input. This is great to check certain conditions that come from another system, such as the day time or to check the existence of user data.

Description

Element
Value
Description

type

contextmatcher

configs

contextKey

The key for this context (defined when handing over context to EDDI)

contextType

expressions

object

string

expressions (if contextType=expressions)

A list of comma separated expressions

objectKeyPath (if contextType=object)

objectValue

Allows match via Jsonpath, such as "profile.username" (see: https://github.com/rest-assured/rest-assured/wiki/Usage)

Exp: contextKey: userInfo , contextValue: {"profile":{"username":"John"}} The value to be match with the extracted JsonPath value

string

string matching (equals)

Examples

Limitations

  • The runtime context you hand over to EDDI may declare "type": "array", but contextmatcher only understands expressions, object and string. An array context can never match any contextmatcher — the condition always fails and the engine logs a warning naming the context key. Send the data as an object (and match with objectKeyPath) if you need to match into it.

  • The configured contextType must equal the runtime type of the context. A contextmatcher configured for string never matches an expressions context, and vice versa; the mismatch is logged at DEBUG level.

Connector

The connector is there to all logical OR conditions within rules. By default all conditions are AND conditions, but in some cases it might be suitable to connect conditions with a logical OR.

Description

Element
Value

type

connector

values

operator (either AND or OR)

Examples

Two edge cases are worth knowing (they mirror the negation rules below):

  • A connector must declare at least one nested condition. An empty connector is rejected at configuration validation time — an AND over zero conditions would succeed unconditionally and make the surrounding rule fire on every turn.

  • If a child reports NOT_EXECUTED (e.g. a sizematcher where every bound is -1), the AND branch treats it as a failure, exactly like a condition placed directly on the rule. A misconfigured condition therefore decides a rule the same way whether or not it is wrapped in a connector.

Negation

Inverts the overall outcome of the children conditions

In some cases it is more relevant if a condition is false than if it is true, this is where the negation condition comes into play. The logical result of all children together (AND connected), will be inverted.

This is exactly what the engine does: every child is evaluated in order, the first child that fails makes the negation succeed (the AND is already false), and the negation only fails when every child succeeded. Multi-child negations therefore behave as documented — earlier EDDI versions only looked at the first child, which made a negation with more than one child effectively always true.

Two edge cases are worth knowing:

  • A negation must declare at least one nested condition. An empty negation is rejected at configuration validation time.

  • If a child reports ERROR or NOT_EXECUTED (e.g. a sizematcher where every bound is -1), there is nothing meaningful to invert — that state is propagated unchanged instead of being flipped.

Example:

Occurrence

Defines the occurrence/frequency of an action in a Behavior Rule.

behaviorRuleName and at least one of minTimesOccurred / maxTimesOccurred are required — both are validated when the ruleset is loaded. Without a rule name there is nothing to count, and without a bound the condition matches as soon as any behavior rule has ever succeeded, which is almost never what was intended.

Dependency

Check if another Behavior Rule has met it's condition or not in the same conversationStep. Sometimes you need to know if a rule has succeeded , dependency will take that rule that hasn't been executed yet in a sandbox environment as a reference for an other behavior rule.

Action Matcher

As inputMatcher doesn't look at expressions but it looks for actions instead, imagine a Behavior Rule has been triggered and you want to check if that action has been triggered before.

Dynamic Value Matcher

This will allow you to compile a condition based on any http request/properties or any sort of variables available in EDDI's context.

Size Matcher

This condition type checks the size of arrays or collections in the conversation memory.

The example above matches whenever the API call stored between 1 and 10 result elements. Collections, maps and arrays report their element count — earlier EDDI versions ran the resolved value through Integer.parseInt, so a real collection silently degraded to size 0 and a rule like this one could never match.

Config
Type
Description

valuePath

string

Path to the array/collection to check

min

int

Minimum size required (-1 to skip check)

max

int

Maximum size allowed (-1 to skip check)

equal

int

Exact size required (-1 to skip check)

How the size is determined — the value the valuePath resolves to decides the rule:

Resolved value
Size used

null / path not found

0

Collection, Map, or array

Its element count

Number

The number itself (the value is the size)

Numeric string

The parsed number (kept for backwards compatibility)

Any other value

The length of its textual representation

If min, max and equal are all -1, the condition reports NOT_EXECUTED — it neither succeeds nor fails, and a wrapping negation propagates that state instead of inverting it.

The Behavior Rule API Endpoints

The API Endpoints below will allow you to manage the Behavior Rules in your EDDI instance.

The {id} is a path parameters that indicate which behavior rule you want to alter.

API Methods

HTTP Method
API Endpoint
Request Body
Response

DELETE

/behaviorstore/behaviorsets/{id}

N/A

N/A

GET

/behaviorstore/behaviorsets/{id}

N/A

BehaviorSet model

PUT

/behaviorstore/behaviorsets/{id}

BehaviorSet model

N/A

GET

/behaviorstore/behaviorsets/descriptors

N/A

BehaviorSet model

POST

/behaviorstore/behaviorsets

BehaviorSet model

N/A

GET

/behaviorstore/behaviorsets/{id}/currentversion

N/A

BehaviorSet model

POST

/behaviorstore/behaviorsets/{id}/currentversion

BehaviorSet model

N/A

Example

We will demonstrate here the creation of a BehaviorSet

Request URL

POST http://localhost:7070/behaviorstore/behaviorsets

Request Body

Response Body

no content

Response Code

201

The Location response header contains the URI of the newly created resource:

Last updated

Was this helpful?