Immutable definition of an AI agent, parsed from an XML file. An AgentDef supplies the system prompt (instructions), the events and timers it responds to, the functions it may call, and the workflows it can run; AgentService loads these from bundled app resources and per-tenant overrides, and AgentManager instantiates them as Agent instances that act on behalf of a user. An AgentDef is scoped to a list of user groups, and users may be permitted to override specific properties (such as a timer's schedule) rather than the whole definition. All mutation happens through withXXX methods that return a new copy, since the parsed definition itself never changes. Written as the agent element, the root of an agent XML file.
Group: AI Agents
Properties
| Property | Returns | Description |
|---|---|---|
| allowedOverrides | List<String> | Which properties of this definition a user is allowed to override, and how. Each entry is of the form property=mode1,mode2 where property is the name of a property on AgentDef and each mode is one of add, edit or remove. |
| allowPlanning | boolean | Whether this agent may spend a call deciding an approach before it acts. Off unless authored, because planning is a real cost paid on every turn and most agents answer questions rather than carry out multi-step work, for which the round trip buys nothing. Turning it on does not mean every turn is planned: the plan call's first job is to say whether the task needs one, so a definition that allows planning still skips it for the trivial questions it is mostly asked. |
| assetTypeName | String | The asset type name used to find the list of Assets the agent draws on as knowledge. |
| attributes | Map<String,Serializable> | Arbitrary name/value pairs attached to this definition. |
| availableSubAgents | List<String> | The specialists this agent may delegate to, identified by AgentDef name. This is an explicit allow list for the same reason functions is one, a level up: which specialists this agent may use, rather than implicitly every specialist the tenant happens to have. Empty or null for a specialist agent, which delegates to nobody. |
| description | String | What this agent is for, in one line, written for a different agent's planning to read when deciding whether to delegate here. Distinct from the title (a display name) and the instructions (the system prompt used when running as this agent) - this is the compressed substitute for knowing the specialist's tools, letting a root agent route correctly without holding the whole tool catalogue in context. |
| events | List<AgentDefEventHandler> | The event handlers this agent responds to. An account may add its own, replace one the app declares by name, or disable one, without taking a copy of the definition - see AgentManager.saveAccountEventHandlers. |
| functions | List<String> | Names of the functions this agent is permitted to call. |
| groups | List<String> | Names of the user groups whose members may use this agent. A user only needs to belong to one of them. |
| instructions | String | The system prompt for this agent. May be templated with kcode, which is evaluated before the prompt is sent. |
| journeys | List<String> | Names of the journeys this agent is allowed to start in order to carry out a workflow. |
| model | String | An exact model name this agent must run on, overriding {@link #getModelTier()}. <p> An escape hatch, not the normal case: it is right when an agent has been tuned against one model's specific behaviour, or when reproducing a problem on a named model. Left set, it also means the agent silently keeps running an old model after better ones arrive, which is the failure tiers exist to prevent - so prefer a tier unless there is a reason not to. |
| modelTier | String | What kind of model this agent needs, as a {@code LlmModelTier} name - {@code fast}, {@code balanced} or {@code deep}. <p> This is the field to set. It says what the agent's work is like, which does not change, rather than which model does it best today, which does: a tier is re-resolved on every run, so an agent picks up a better model when one is enabled without its definition being touched. Naming a model outright - see {@link #getModel()} - pins the agent to it and opts out of that. |
| name | String | Portable identifier for this definition, taken from the name of the XML file it was parsed from, including the .xml suffix. |
| overrideGeneration | Integer | Which generation of the definition model this stored override was saved against, or null if it predates generations. <p> The problem this exists for: until definitions came from apps, a copy was written into every tenant on first use. Those copies override what the app supplies, and a stored copy wins outright - so a tenant that never customised anything was nonetheless pinned forever to whatever the definition looked like on the day it was first used. When the definition then changes shape - as it did when the root agent stopped holding domain tools and started delegating - those tenants silently keep the old shape, and get an agent that no longer works the way it is designed to. <p> So an override has to say which world it was written for. One saved against an older generation is <b>superseded</b>: it is kept, and still visible, but it no longer overrides the app. Saving it again adopts it into the current generation, which is what an administrator who does want their version does. |
| skills | List<AgentSkillDef> | The skills this agent may read, ie short reference documents it pulls into context only when the task calls for one. <p> Distinct from {@link #getAssetTypeName() knowledge assets}, which are loaded whole into every turn. A skill is the opposite trade: only its name, purpose and keywords are standing context, and the body is fetched by the agent when it decides it is relevant. That makes a skill the right home for material that is long, that only some tasks need, and that would otherwise crowd out the conversation - a query cookbook, a house style, the steps of an occasional procedure. <p> They live on the definition rather than being uploaded per tenant because definitions come from apps and have no per-tenant instantiation: a skill has to travel with the agent that knows how to use it. |
| timers | List<AgentDefTimer> | The timers this agent responds to, each firing its own instructions on a recurring schedule. |
| title | String | Display title for this agent, shown to users choosing or configuring an agent. |
| workflows | List<AgentWorkflowDef> | The workflows this agent is able to execute, each a named series of steps. |
Methods
withTitle(String newTitle) · withInstructions(String newInstructions) · withTimers(List<AgentDefTimer> timerList) · withEvents(List<AgentDefEventHandler> eventList) · withFunctions(List<String> functionList) · withAttributes(Map<String,Serializable> attributeMap) · getDescription() · withDescription(String newDescription) · getAvailableSubAgents() · withAvailableSubAgents(List<String> newAvailableSubAgents) · isAllowPlanning() · withAllowPlanning(Boolean newAllowPlanning) · withGroups(List<String> groupList) · withTimer(String timerName, String timerInstructions, int multiples, String units, String time) · withEvent(String eventName, String eventInstructions, String scope, Integer bufferSecs, Integer bufferSize) · getName() · getTitle() · getAssetTypeName() · getInstructions() · getTimers() · getEvents() · getWorkflows() · getFunctions() · getSkills() · withSkills(List<AgentSkillDef> skillList) · withSkill(String skillName, String skillTitle, String skillDescription, String keywords, String content) · withSkill(String skillName, String skillTitle, String skillDescription, String keywords, String content, Boolean alwaysRead) · getAttributes() · getJourneys() · getGroups() · getAllowedOverrides() · timer(String timerName) · event(String eventDefName)
withTitle(String newTitle)
Returns: AgentDef
Returns a copy of this definition with the given display title.
| Parameter | Description |
|---|---|
newTitle | the display title |
withInstructions(String newInstructions)
Returns: AgentDef
Returns a copy of this definition with the given instructions, ie system prompt.
| Parameter | Description |
|---|---|
newInstructions | the instructions text, which may be templated with kcode |
withTimers(List<AgentDefTimer> timerList)
Returns: AgentDef
Returns a copy of this definition with the given list of timers, replacing any existing timers.
| Parameter | Description |
|---|---|
timerList | the timers to set; copied, so later changes to the caller's list do not leak in |
withEvents(List<AgentDefEventHandler> eventList)
Returns: AgentDef
Returns a copy of this definition with the given list of event handlers, replacing any existing handlers.
| Parameter | Description |
|---|---|
eventList | the event handlers to set; copied, so later changes to the caller's list do not leak in |
withFunctions(List<String> functionList)
Returns: AgentDef
Returns a copy of this definition with the given list of allowed function names, replacing any existing functions.
| Parameter | Description |
|---|---|
functionList | names of the functions this agent may call; copied, so later changes to the caller's list do not leak in |
withAttributes(Map<String,Serializable> attributeMap)
Returns: AgentDef
Returns a copy of this definition with the given arbitrary name/value pairs, following the same immutable-wither pattern used throughout this class.
| Parameter | Description |
|---|---|
attributeMap | the attributes to set; copied, so later changes to the caller's map do not leak in |
getDescription()
Returns: String
What this agent is for, in one line, written for a different agent's planning to read when deciding whether to delegate here. Distinct from the title (a display name) and the instructions (the system prompt used when running as this agent) - this is the compressed substitute for knowing the specialist's tools, letting a root agent route correctly without holding the whole tool catalogue in context.
withDescription(String newDescription)
Returns: AgentDef
Returns a copy of this definition with the given routing description.
| Parameter | Description |
|---|---|
newDescription | the routing description |
getAvailableSubAgents()
Returns: List<String>
The specialists this agent may delegate to, identified by AgentDef name. This is an explicit allow list for the same reason functions is one, a level up: which specialists this agent may use, rather than implicitly every specialist the tenant happens to have. Empty or null for a specialist agent, which delegates to nobody.
withAvailableSubAgents(List<String> newAvailableSubAgents)
Returns: AgentDef
Returns a copy of this definition with the given list of delegate specialists.
| Parameter | Description |
|---|---|
newAvailableSubAgents | specialist AgentDef names this agent may delegate to |
isAllowPlanning()
Returns: boolean
Whether this agent may spend a call deciding an approach before it acts. Off unless authored, because planning is a real cost paid on every turn and most agents answer questions rather than carry out multi-step work, for which the round trip buys nothing. Turning it on does not mean every turn is planned: the plan call's first job is to say whether the task needs one, so a definition that allows planning still skips it for the trivial questions it is mostly asked.
withAllowPlanning(Boolean newAllowPlanning)
Returns: AgentDef
Returns a copy of this definition with the given planning permission.
| Parameter | Description |
|---|---|
newAllowPlanning | whether planning is permitted; null is the same as false |
withGroups(List<String> groupList)
Returns: AgentDef
Returns a copy of this definition restricted to the given user groups.
| Parameter | Description |
|---|---|
groupList | names of the groups whose members may use this agent |
withTimer(String timerName, String timerInstructions, int multiples, String units, String time)
Returns: AgentDef
Returns a copy of this definition with an additional timer appended to its existing timers.
| Parameter | Description |
|---|---|
timerName | portable identifier for the new timer |
timerInstructions | instructions to run when the timer fires |
multiples | how many units between firings, eg 3 for "every 3 days" |
units | the time unit the timer runs on, one of the values returned by getTimerUnits |
time | if set, the time of day the timeout is adjusted to |
withEvent(String eventName, String eventInstructions, String scope, Integer bufferSecs, Integer bufferSize)
Returns: AgentDef
Returns a copy of this definition with an additional event handler appended to its existing handlers.
| Parameter | Description |
|---|---|
eventName | the funnel event name to listen for |
eventInstructions | instructions to run when the event fires |
scope | null to match the event regardless of profile, or a scope constant such as SCOPE_CUST_PROFILE to match only events for the lead's own profile |
bufferSecs | if set, buffer matching events for up to this many seconds before firing with the recorded events |
bufferSize | if set, buffer up to this many matching events before firing |
getName()
Returns: String
Portable identifier for this definition, taken from the name of the XML file it was parsed from, including the .xml suffix.
getTitle()
Returns: String
Display title for this agent, shown to users choosing or configuring an agent.
getAssetTypeName()
Returns: String
The asset type name used to find the list of Assets the agent draws on as knowledge.
getInstructions()
Returns: String
The system prompt for this agent. May be templated with kcode, which is evaluated before the prompt is sent.
getTimers()
Returns: List<AgentDefTimer>
The timers this agent responds to, each firing its own instructions on a recurring schedule.
getEvents()
Returns: List<AgentDefEventHandler>
The event handlers this agent responds to. An account may add its own, replace one the app declares by name, or disable one, without taking a copy of the definition - see AgentManager.saveAccountEventHandlers.
getWorkflows()
Returns: List<AgentWorkflowDef>
The workflows this agent is able to execute, each a named series of steps.
getFunctions()
Returns: List<String>
Names of the functions this agent is permitted to call.
getSkills()
Returns: List<AgentSkillDef>
The skills this agent may read, ie short reference documents it pulls into context only when the task calls for one. <p> Distinct from {@link #getAssetTypeName() knowledge assets}, which are loaded whole into every turn. A skill is the opposite trade: only its name, purpose and keywords are standing context, and the body is fetched by the agent when it decides it is relevant. That makes a skill the right home for material that is long, that only some tasks need, and that would otherwise crowd out the conversation - a query cookbook, a house style, the steps of an occasional procedure. <p> They live on the definition rather than being uploaded per tenant because definitions come from apps and have no per-tenant instantiation: a skill has to travel with the agent that knows how to use it.
withSkills(List<AgentSkillDef> skillList)
Returns: AgentDef
Returns a copy of this definition with the given skills, replacing any existing ones.
| Parameter | Description |
|---|---|
skillList | the skills to set; copied, so later changes to the caller's list do not leak in |
withSkill(String skillName, String skillTitle, String skillDescription, String keywords, String content)
Returns: AgentDef
Returns a copy of this definition with one more skill appended to its existing ones.
| Parameter | Description |
|---|---|
skillName | the identifier the agent names when it reads this skill, eg {@code chart-playbook} |
skillTitle | a display title |
skillDescription | one line saying what the skill covers, shown to the agent in its instructions |
keywords | comma separated words and phrases that should make the agent reach for this skill |
content | the skill itself, as markdown. Second level headings become the sections a partial read can ask for |
withSkill(String skillName, String skillTitle, String skillDescription, String keywords, String content, Boolean alwaysRead)
Returns: AgentDef
Returns a copy of this definition with one more skill appended, saying whether it is standing context.
| Parameter | Description |
|---|---|
skillName | the identifier the agent names when it reads this skill |
skillTitle | a display title |
skillDescription | one line saying what the skill covers |
keywords | comma separated words and phrases that should make the agent reach for this skill |
content | the skill itself, as markdown |
alwaysRead | true to put the whole body in front of the agent every turn rather than indexing it - see {@link AgentSkillDef#isAlwaysRead()} |
getAttributes()
Returns: Map<String,Serializable>
Arbitrary name/value pairs attached to this definition.
getJourneys()
Returns: List<String>
Names of the journeys this agent is allowed to start in order to carry out a workflow.
getGroups()
Returns: List<String>
Names of the user groups whose members may use this agent. A user only needs to belong to one of them.
getAllowedOverrides()
Returns: List<String>
Which properties of this definition a user is allowed to override, and how. Each entry is of the form property=mode1,mode2 where property is the name of a property on AgentDef and each mode is one of add, edit or remove.
timer(String timerName)
Returns: AgentDefTimer
Finds the timer with the given name among this definition's timers.
| Parameter | Description |
|---|---|
timerName | the timer's name to look up |
event(String eventDefName)
Returns: AgentDefEventHandler
Finds the event handler with the given name among this definition's event handlers.
| Parameter | Description |
|---|---|
eventDefName | the event handler's name to look up |