Round-robin interaction files
A round-robin interaction: agents, and optionally a person, take turns in one shared conversation. Each agent can answer, pass, ask another a question, or propose a final answer that the others vote on.
What round-robin interactions are for, and how to use them: Teams of agents.
Where the file goes
Section titled “Where the file goes”interactions/round-robin/, or any sub-folder of it. The file name without .mtr is the round-robin interaction’s name. Other files refer to it as @ref("<name>").
A resource’s name is its file name without .mtr (an app’s is its folder’s name). Use letters, digits, _, - and . (but not ..), at most 128 characters. Two files of the same kind may not have the same name, even in different sub-folders or with different capitals.
Properties
Section titled “Properties”A file must set agents and task. Everything else is optional.
agents
Section titled “agents”Required. List of blocks.
The seats at the table, in the order they take turns.
Required. Text.
What the agents are asked to do. The run’s inputs are filled in where it says %%name%%, and {{#if name}}...{{/if}} keeps text only when an input has a value ({{#unless name}} for the opposite). Use @prompt("name") for anything longer than a sentence.
task = "Chat with the person. Answer what they ask."features
Section titled “features”Optional. Block.
Which moves the agents may make. All are allowed when not set.
Optional. Block.
A person takes part in the conversation. No one when not set.
Optional. Block.
When the conversation ends on its own.
functions.openApi
Section titled “functions.openApi”Optional. List of blocks.
Tools available to every agent in the interaction, as well as the tools each agent has itself.
inputs.prompts
Section titled “inputs.prompts”Optional. List of blocks.
The inputs a run is started with, which the task uses as %%name%%.
inputs.functions.binding
Section titled “inputs.functions.binding”Optional. List of blocks.
Run inputs whose values go straight into a tool call, such as a customer id: the model never sees or chooses them.
inputs.functions.auth
Section titled “inputs.functions.auth”Optional. List of blocks.
Run inputs that choose the secret a tool sends with its calls.
schema.solution
Section titled “schema.solution”Optional. JSON text.
The JSON Schema the answer must match, usually @json("name"). The run’s output is then JSON of that shape.
schema.solution = @json("answer")prompts.system.mode
Section titled “prompts.system.mode”Optional. One of the values below. Default: "AppendToDefault".
How prompts.system combines with the instructions Maitento gives every agent.
| Value | Meaning |
|---|---|
AppendToDefault | They are added after Maitento’s instructions. |
OverwriteAll | They replace everything: the agent’s prompt, Maitento’s instructions and the list of tools. |
OverwriteNonCritical | They replace Maitento’s general guidance, keeping the agent’s prompt, safety rules and tools. |
prompts.system.mode = "OverwriteAll"prompts.system
Section titled “prompts.system”Optional. List of text.
Extra system instructions for every agent in the interaction.
prompts.system = [ "Write in British English." ]duration.warn
Section titled “duration.warn”Optional. Duration, "hh:mm:ss".
When the agents are told that time is running short, as "hh:mm:ss" from the start of the run.
duration.warn = "00:05:00"duration.max
Section titled “duration.max”Optional. Duration, "hh:mm:ss".
The longest a run may take, as "hh:mm:ss". The run stops with an error when it is reached. Time spent waiting for a person does not count. No limit when not set.
duration.max = "00:05:00"context
Section titled “context”Optional. Block.
How the conversation is kept within the model’s context window, and how many rounds of tool calls an agent may make in one turn. The defaults suit almost every interaction.
Optional. Block.
Long-term memory for the interaction’s agents. No memory when not set.
credentialStack
Section titled “credentialStack”Optional. Text.
The credential stack this interaction’s runs use, by name, when their start doesn’t name one: its credentials serve every model call, and Maitento’s own keys never do. Leave it out to use the namespace’s default stack, then your tenant’s.
credentialStack = "..."Optional. Block.
Other interactions the agents may start as sub-runs, and how many. None when not set.
Each item of agents
Section titled “Each item of agents”A seat in an interaction: the name a participant goes by, and the agent that fills it. { name = "Greeter" agent = @ref("greeter") }.
agents › name
Section titled “agents › name”Required. Text.
The name the participant goes by in this interaction. The other participants, and the transcript, use it, so give each seat its own.
name = "Assistant"agents › agent
Section titled “agents › agent”Required. Reference to an agent.
The agent that fills the seat.
agent = @ref("assistant")agents › loom
Section titled “agents › loom”Optional. Reference to a loom.
A named loom the participant always remembers with, instead of the one the interaction’s loom settings would give it. A loom chosen when the run starts still takes precedence.
loom = @ref("family")agents › webAccess
Section titled “agents › webAccess”Optional. Block.
The participant’s built-in web tools, overriding what its agent allows: webAccess = { search = true fetch = false }. Leave either out to keep the agent’s own setting. Where this block and webAccess.search / webAccess.fetch are both given, the block wins.
agents › webAccess.search
Section titled “agents › webAccess.search”Optional. true or false.
Gives or takes away the built-in web search tool for this participant, overriding its agent.
webAccess.search = trueagents › webAccess.fetch
Section titled “agents › webAccess.fetch”Optional. true or false.
Gives or takes away the built-in web fetch tools for this participant, overriding its agent.
webAccess.fetch = trueagents › functions.openApi
Section titled “agents › functions.openApi”Optional. List of blocks.
Tools for this participant only, as well as the interaction’s and its agent’s own.
The features block
Section titled “The features block”features = { ... }: which moves the agents at the table may make.
features › noAction
Section titled “features › noAction”Optional. true or false. Default: true.
An agent may pass its turn without saying anything.
noAction = falsefeatures › voting
Section titled “features › voting”Optional. true or false. Default: true.
Agents vote on a proposed answer.
voting = falsefeatures › directQuestions
Section titled “features › directQuestions”Optional. true or false. Default: true.
An agent may ask another a question directly.
directQuestions = falsefeatures › solutionProposal
Section titled “features › solutionProposal”Optional. true or false. Default: true.
An agent may propose a final answer. With no one able to, a conversation with a person carries on until it is stopped.
solutionProposal = falseThe human block
Section titled “The human block”human = { first = true }: a person takes part in the conversation.
human › first
Section titled “human › first”Optional. true or false. Default: false.
The person speaks first. Otherwise the agents speak first and the person last.
first = truehuman › votes
Section titled “human › votes”Optional. true or false. Default: false.
Round-robin only: the person votes too, when an agent puts something to a vote. Needs features.voting.
votes = truehuman › solutions
Section titled “human › solutions”Optional. true or false. Default: false.
Round-robin only: a proposed final answer is put to the person too, to accept or reject. Needs features.solutionProposal.
solutions = falseThe rules block
Section titled “The rules block”rules = { ... }: when a round-robin conversation ends on its own.
rules › noActionLoops.max
Section titled “rules › noActionLoops.max”Optional. Whole number.
How many rounds in which every agent passes end the run. No limit when not set.
noActionLoops.max = 2Each item of functions.openApi
Section titled “Each item of functions.openApi”A tool made available in one place (to a whole interaction, to one participant, or to an app), with any values and credentials that apply there: { ref = @ref("search-handbook") }. What is set here overrides the tool’s own settings.
The same block is used for agents › functions.openApi.
functions.openApi › ref
Section titled “functions.openApi › ref”Required. Reference to a tool.
The tool.
ref = @ref("search-handbook")functions.openApi › bindings.path
Section titled “functions.openApi › bindings.path”Optional. Map of text, one line per entry: bindings.path:<key> = "value".
Fixed values for the connector’s path parameters, one line each: bindings.path:orderId = "A-1001".
bindings.path:orderId = "A-1001"functions.openApi › bindings.query
Section titled “functions.openApi › bindings.query”Optional. Map of text, one line per entry: bindings.query:<key> = "value".
Fixed values for the connector’s query parameters, one line each: bindings.query:units = "metric".
bindings.query:units = "metric"functions.openApi › name
Section titled “functions.openApi › name”Optional. Text.
The name the model calls the tool by here. The tool’s own name when not set.
name = "search-handbook"functions.openApi › bindings.request
Section titled “functions.openApi › bindings.request”Optional. Map of text, one line per entry: bindings.request:<key> = "value".
Fixed values for fields of the request body, which the model never sees or chooses, one line each: bindings.request:field = "value". Separate the names of a nested field with / (bindings.request:customer/id). A value is read as the type the request schema gives the field.
bindings.request:customer/id = "C-42"functions.openApi › auth
Section titled “functions.openApi › auth”Optional. Block.
A credential to send with every call made here, instead of the tool’s own.
functions.openApi › guidance
Section titled “functions.openApi › guidance”Optional. Text.
When and how to use the tool here, instead of the tool’s own guidance. The model reads it.
guidance = "Use it when the customer asks about an order."functions.openApi › terminal
Section titled “functions.openApi › terminal”Optional. true or false. Default: false.
A successful call ends the agent’s turn: the result is recorded, and the model is not asked to continue. Use it for a “finish” tool that is meant to be the last thing an agent does in a turn.
terminal = trueEach item of inputs.prompts
Section titled “Each item of inputs.prompts”An input a run is started with, used in the task as %%name%%: { name = "topic" description = "What the haiku is about" required = true }.
inputs.prompts › name
Section titled “inputs.prompts › name”Required. Text.
The input’s name: a run gives the input’s value under this name.
name = "userName"inputs.prompts › type
Section titled “inputs.prompts › type”Optional. One of the values below. Default: "String".
The type of value the input takes.
| Value | Meaning |
|---|---|
String | Text. |
Integer | A whole number. |
Decimal | A number that may have a fractional part. |
Boolean | true or false. |
type = "Integer"inputs.prompts › description
Section titled “inputs.prompts › description”Optional. Text.
What the input is for, shown to whoever starts a run.
description = "What the haiku is about"inputs.prompts › required
Section titled “inputs.prompts › required”Optional. true or false. Default: true.
Whether a run must give the input. A run without a required input is refused, unless the input has a default, which the run then uses.
required = trueEach item of inputs.functions.binding
Section titled “Each item of inputs.functions.binding”A run input whose value is written straight into a tool’s calls, so the model never sees or chooses it: { function = @ref("search-handbook") name = "partitionId" target = "partitionId" type = "request" }.
inputs.functions.binding › function
Section titled “inputs.functions.binding › function”Required. Reference to a tool.
The tool whose calls get the value.
function = @ref("current-weather")inputs.functions.binding › target
Section titled “inputs.functions.binding › target”Required. Text.
Where the value goes: the name of the request body field (separate the names of a nested field with /), or of the path or query parameter, as type says.
target = "temperature_unit"inputs.functions.binding › name
Section titled “inputs.functions.binding › name”Required. Text.
The input’s name: a run gives the input’s value under this name.
name = "temperatureUnit"inputs.functions.binding › agent
Section titled “inputs.functions.binding › agent”Optional. Reference to an agent.
Only the participant filled by this agent gets the value. Every participant when not set.
agent = @ref("weather-bot")inputs.functions.binding › default
Section titled “inputs.functions.binding › default”Optional. Text.
The value used when a run does not give one.
default = "celsius"inputs.functions.binding › type
Section titled “inputs.functions.binding › type”Optional. One of the values below. Default: "Request".
What target names: a field of the request body, a query parameter or a path parameter.
| Value | Meaning |
|---|---|
Request | A field of the request body. |
Query | A query-string parameter. |
Path | A path parameter. |
type = "query"inputs.functions.binding › description
Section titled “inputs.functions.binding › description”Optional. Text.
What the input is for, shown to whoever starts a run.
description = "celsius or fahrenheit"inputs.functions.binding › required
Section titled “inputs.functions.binding › required”Optional. true or false. Default: true.
Whether a run must give the input. A run without a required input is refused, unless the input has a default, which the run then uses.
required = falseEach item of inputs.functions.auth
Section titled “Each item of inputs.functions.auth”A run input that chooses the secret a tool sends with its calls: a run gives the id of the secret, such as one per customer. { function = @ref("get-order") name = "customerKey" header = "X-Api-Key" }.
inputs.functions.auth › function
Section titled “inputs.functions.auth › function”Required. Reference to a tool.
The tool whose calls send the secret.
function = @ref("get-order")inputs.functions.auth › name
Section titled “inputs.functions.auth › name”Required. Text.
The input’s name: a run gives the input’s value under this name.
name = "shopKey"inputs.functions.auth › agent
Section titled “inputs.functions.auth › agent”Optional. Reference to an agent.
Only the participant filled by this agent sends it. Every participant when not set.
agent = @ref("support-agent")inputs.functions.auth › secret
Section titled “inputs.functions.auth › secret”Optional. Reference to a secret.
The secret sent when a run does not choose one.
Secrets are not part of a project: create them in the portal, with the SDK or with mt secret-create before you deploy.
secret = @ref("orders-api-key")inputs.functions.auth › header
Section titled “inputs.functions.auth › header”Optional. Text. Default: "Authorization".
The HTTP header the secret’s value is sent in.
header = "X-Api-Key"inputs.functions.auth › description
Section titled “inputs.functions.auth › description”Optional. Text.
What the input is for, shown to whoever starts a run.
description = "The id of the secret that holds the shop's API key"inputs.functions.auth › required
Section titled “inputs.functions.auth › required”Optional. true or false. Default: true.
Whether a run must give the input. A run without a required input is refused, unless the input has a default, which the run then uses.
required = trueThe context block
Section titled “The context block”context = { ... }: how an interaction keeps its conversation within the model’s context window, and how many rounds of tool calls an agent may make in one turn. The defaults suit almost every interaction.
context › mode
Section titled “context › mode”Optional. One of the values below. Default: "Automatic".
What happens when the conversation no longer fits the model’s context window.
| Value | Meaning |
|---|---|
None | Nothing until the conversation reaches the model’s hard limit; then it is shortened just enough to be sent. |
Automatic | The conversation is shortened once it passes the target share of the window: large tool results first, then the oldest turns in the middle, with a notice that it was trimmed. |
Aggressive | Accepted, and trims as Automatic does. |
FailOnOverflow | No trimming: a conversation that no longer fits makes the run fail, instead of going on without part of it. |
mode = "Automatic"context › targetUtilization
Section titled “context › targetUtilization”Optional. Number. Default: 0.9.
How full the context window may get, as a fraction from 0 to 1, before the conversation is shortened.
targetUtilization = 0.8context › toolResultTrimming.mode
Section titled “context › toolResultTrimming.mode”Optional. One of the values below. Default: "OnOverflow".
When the results of earlier tool calls are replaced, to save space.
| Value | Meaning |
|---|---|
Never | Never: tool results are kept as they came back. |
OnOverflow | When the conversation no longer fits the context window. |
AfterCycles | Once an agent has had a set number of turns: every result but the latest. |
Both | Both: after a set number of turns, and whenever the conversation no longer fits. |
toolResultTrimming.mode = "Never"context › toolResultTrimming.maxCycles
Section titled “context › toolResultTrimming.maxCycles”Optional. Whole number. Default: 3.
For toolResultTrimming.mode = "AfterCycles" or "Both": once an agent has had this many turns, every tool result but the latest is replaced.
toolResultTrimming.maxCycles = 6context › toolResultTrimming.replacement
Section titled “context › toolResultTrimming.replacement”Optional. Text. Default: "[Tool result trimmed to reduce context size]".
The text a replaced tool result becomes, with toolResultTrimming.style = "Placeholder".
toolResultTrimming.replacement = "[Tool result trimmed to reduce context size]"context › toolResultTrimming.style
Section titled “context › toolResultTrimming.style”Optional. One of the values below. Default: "Placeholder".
What a replaced tool result becomes.
| Value | Meaning |
|---|---|
Placeholder | The same replacement text for every result. |
Digest | A digest of what was there: which tool was called, with what, how large the result was, and how it began. Made without a model call, so it costs nothing. |
toolResultTrimming.style = "Digest"context › compaction.type
Section titled “context › compaction.type”Optional. One of the values below. Default: "None".
Whether, and how, older parts of a long conversation are summarised to make room. Suits long, many-turn conversations such as chats.
| Value | Meaning |
|---|---|
SameAgent | The agent summarises its own conversation. Usually the best summary, since the agent already understands it, but an agent with strict instructions may refuse. |
StandaloneAgent | A separate call, without the agent’s instructions, writes the summary, so one is always made. It loses the agent’s own understanding. |
None | No summaries: the conversation is only trimmed. |
compaction.type = "SameAgent"context › compaction.atUtilization
Section titled “context › compaction.atUtilization”Optional. Number. Default: 0.85.
How full the context window gets, as a fraction from 0 to 1, before the conversation is summarised.
compaction.atUtilization = 0.75context › compaction.keepRecentTokens
Section titled “context › compaction.keepRecentTokens”Optional. Whole number. Default: 8000.
The most recent part of the conversation kept word for word when it is summarised, in tokens.
compaction.keepRecentTokens = 16000context › compaction.targetTokens
Section titled “context › compaction.targetTokens”Optional. Whole number. Default: 4000.
The length the summary aims for, in tokens.
compaction.targetTokens = 8000context › maxToolCallLoops
Section titled “context › maxToolCallLoops”Optional. Whole number. Default: 10.
The most rounds of tool calls an agent may make in one turn. After that its tools are withheld and it must answer. 0 means no limit.
maxToolCallLoops = 12context › responseMaxTokens
Section titled “context › responseMaxTokens”Optional. Whole number. Default: 32000.
The most the model may write in one reply, in tokens, including any reasoning. 0 allows the model’s maximum. A value above the model’s maximum is lowered to it; a reply that reaches the limit is kept as far as it got.
responseMaxTokens = 64000context › compaction.maxTokens
Section titled “context › compaction.maxTokens”Optional. Whole number. Default: 40000.
The most a summary may be, in tokens. Used only with compaction.type set.
compaction.maxTokens = 80000The loom block
Section titled “The loom block”loom = { ... } on an interaction: long-term memory for its agents. A bare loom = { enabled = true } gives each agent a fresh memory for every run, with suggested recall and suggested weaving.
loom › enabled
Section titled “loom › enabled”Optional. true or false. Default: true.
Turns memory on. false keeps the settings but leaves memory off.
enabled = trueloom › scope
Section titled “loom › scope”Optional. One of the values below. Default: "Process".
Whose memory a run uses, and so whether it lasts beyond one run.
| Value | Meaning |
|---|---|
Process | A fresh loom for every run. One caller’s threads never reach another’s run. |
Interaction | One loom per agent (or one for the interaction, when shared) that lasts across every run. |
Input | One loom per value of the run input named by the scope input, such as one per user. |
scope = "Input"loom › scopeInput
Section titled “loom › scopeInput”Optional. Text.
For scope = "Input": the run input whose value picks the memory, such as "userName".
scopeInput = "userName"loom › shared
Section titled “loom › shared”Optional. true or false. Default: false.
All the interaction’s agents share one memory. Otherwise each agent has its own.
shared = trueloom › recall
Section titled “loom › recall”Optional. One of the values below. Default: "Suggest".
How remembered threads come back into a conversation.
| Value | Meaning |
|---|---|
Off | Nothing is offered: the agent searches its memory only when it chooses to. |
Suggest | The agent is told what may connect, and chooses whether to recall it. |
Surface | The relevant threads are shown in the conversation straight away. |
recall = "Suggest"loom › weave
Section titled “loom › weave”Optional. One of the values below. Default: "Suggest".
How new memories are made from a conversation.
| Value | Meaning |
|---|---|
Manual | Only the agent weaves, with its LoomWeave tool. |
Suggest | The weaver reads each exchange and offers what may be worth keeping; the agent decides. |
Auto | The weaver weaves weak threads directly; use strengthens them, and disuse lets them fade. |
weave = "Auto"loom › tapestryTokens
Section titled “loom › tapestryTokens”Optional. Whole number. Default: 1500.
How long the “what you know” summary an agent is given when a conversation starts may be, in tokens.
tapestryTokens = 3000loom › subjectInputs
Section titled “loom › subjectInputs”Optional. List of text.
Run inputs that name who the agents are working with, such as "userName", so memories are about the right person.
subjectInputs = [ "userName" ]loom › nightWeaving
Section titled “loom › nightWeaving”Optional. true or false. Default: true.
Tidy up the memories this interaction creates once a conversation goes quiet: summarise it, merge duplicates, note contradictions and write a short portrait of each person.
nightWeaving = trueloom › quietMinutes
Section titled “loom › quietMinutes”Optional. Whole number. Default: 15.
Minutes without activity before night weaving starts.
quietMinutes = 5loom › weaverModel
Section titled “loom › weaverModel”Optional. Text.
The catalogue model that reads conversations to make memories and to night-weave, such as "anthropic.haiku-4.5". The agent’s own model when not set.
weaverModel = "deepseek.deepseek-v4-flash"loom › vetModel
Section titled “loom › vetModel”Optional. Text.
A lightweight catalogue model, such as "anthropic.haiku-4.5", that checks what memory offers an agent in the middle of a conversation and drops what does not belong. Off when not set.
vetModel = "deepseek.deepseek-v4-flash"loom › vetRecall
Section titled “loom › vetRecall”Optional. true or false. Default: false.
The vetModel also checks what an agent’s own searches of its memory bring back.
vetRecall = trueloom › seedFrom
Section titled “loom › seedFrom”Optional. Reference to a loom.
A named loom every memory this interaction creates starts from: a new person’s memory starts knowing what the shared loom knows.
seedFrom = @ref("family")loom › readFrom
Section titled “loom › readFrom”Optional. List of references to looms.
Named looms the agents may read but never change.
readFrom = [ @ref("family") ]The swarm block
Section titled “The swarm block”swarm = { interactions = [ @ref("country-facts") ] maxConcurrent = 5 }: other interactions this one’s agents may start as sub-runs, wait for and combine. An agent also needs allowSwarm = true.
swarm › interactions
Section titled “swarm › interactions”Required. List of references to interactions.
The interactions that may be started. Nothing else can be. They may be declared in the same project, this one included.
interactions = [ @ref("country-facts") ]swarm › participants
Section titled “swarm › participants”Optional. List of text.
The seats (by name) that may start them. Every seat whose agent allows it when not set.
participants = [ "Lead" ]swarm › maxDepth
Section titled “swarm › maxDepth”Optional. Whole number.
How many levels of sub-runs may be started below this one. 1 when not set; at most 4.
maxDepth = 2swarm › maxConcurrent
Section titled “swarm › maxConcurrent”Optional. Whole number.
How many sub-runs may run at once, across the whole tree. 5 when not set; at most 20.
maxConcurrent = 5swarm › maxTotal
Section titled “swarm › maxTotal”Optional. Whole number.
How many sub-runs may be started in all, across the whole tree. 20 when not set; at most 100.
maxTotal = 10The agents › webAccess block
Section titled “The agents › webAccess block”A participant’s built-in web tools: webAccess = { search = true fetch = false }. Leave either out to keep its agent’s own setting.
webAccess › search
Section titled “webAccess › search”Optional. true or false.
Gives (true) or takes away (false) the web search tool.
search = truewebAccess › fetch
Section titled “webAccess › fetch”Optional. true or false.
Gives (true) or takes away (false) the web fetch tools.
fetch = trueThe functions.openApi › auth block
Section titled “The functions.openApi › auth block”A credential sent with every call of a tool: auth = { header = "X-Api-Key" secret = @ref("orders-api-key") }. The tool’s connector needs auth = "Header".
The same block is used for agents › functions.openApi › auth.
auth › header
Section titled “auth › header”Required. Text.
The HTTP header the secret’s value is sent in. For Authorization, a value without a space is sent as Bearer <value>.
header = "X-Api-Key"auth › secret
Section titled “auth › secret”Required. Reference to a secret.
The secret whose value is sent. Create the secret before you deploy.
Secrets are not part of a project: create them in the portal, with the SDK or with mt secret-create before you deploy.
secret = @ref("orders-api-key")A complete example
Section titled “A complete example”From the 20-memory example project:
// A one-to-one conversation with Wren, a companion who remembers.//// Each person gets their own loom (scope = "Input" on userName), so Wren wakes up knowing whoever// it is talking to, and never mixes one person's threads into another's conversation.
agents = [ { name = "Wren" agent = @ref("wren") }]
task = @prompt("wren-chat")
inputs.prompts = [ { name = "userName" required = true }]
features = { voting = false noAction = false directQuestions = false solutionProposal = false}
human = { first = true solutions = false}
loom = { enabled = true // One loom per value of the userName input: one memory per person. scope = "Input" scopeInput = "userName" // Memories are about the person named by userName. subjectInputs = [ "userName" ] // A weaver reads every exchange and keeps what is worth keeping. Wren can also weave and recall itself. weave = "Auto" recall = "Suggest" // Five quiet minutes after a conversation, night weaving tidies the memory up. nightWeaving = true quietMinutes = 5}