Skip to content

One-shot interaction files

A one-shot interaction: one agent, one task, one answer.

What one-shot interactions are for, and how to use them: Interactions.

interactions/one-shot/, or any sub-folder of it. The file name without .mtr is the one-shot 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.

A file must set agent and task. Everything else is optional.

Required. Block.

The seat: the name the agent goes by here, and which agent fills it.

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 = "Hello, how are you?"

Optional. List of blocks.

Tools available to every agent in the interaction, as well as the tools each agent has itself.

Optional. List of blocks.

The inputs a run is started with, which the task uses as %%name%%.

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.

Optional. List of blocks.

Run inputs that choose the secret a tool sends with its calls.

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("recipe")

Optional. One of the values below. Default: "AppendToDefault".

How prompts.system combines with the instructions Maitento gives every agent.

ValueMeaning
AppendToDefaultThey are added after Maitento’s instructions.
OverwriteAllThey replace everything: the agent’s prompt, Maitento’s instructions and the list of tools.
OverwriteNonCriticalThey replace Maitento’s general guidance, keeping the agent’s prompt, safety rules and tools.
prompts.system.mode = "OverwriteAll"

Optional. List of text.

Extra system instructions for every agent in the interaction.

prompts.system = [ "Write in British English." ]

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:02:00"

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:04:00"

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.

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.

A seat in an interaction: the name a participant goes by, and the agent that fills it. { name = "Greeter" agent = @ref("greeter") }.

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 = "Greeter"

Required. Reference to an agent.

The agent that fills the seat.

agent = @ref("greeter")

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")

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.

Optional. true or false.

Gives or takes away the built-in web search tool for this participant, overriding its agent.

webAccess.search = true

Optional. true or false.

Gives or takes away the built-in web fetch tools for this participant, overriding its agent.

webAccess.fetch = true

Optional. List of blocks.

Tools for this participant only, as well as the interaction’s and its agent’s own.

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 agent › functions.openApi.

Required. Reference to a tool.

The tool.

ref = @ref("search-handbook")

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"

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"

Optional. Text.

The name the model calls the tool by here. The tool’s own name when not set.

name = "search-handbook"

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"

Optional. Block.

A credential to send with every call made here, instead of the tool’s own.

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."

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 = true

An input a run is started with, used in the task as %%name%%: { name = "topic" description = "What the haiku is about" required = true }.

Required. Text.

The input’s name: a run gives the input’s value under this name.

name = "topic"

Optional. One of the values below. Default: "String".

The type of value the input takes.

ValueMeaning
StringText.
IntegerA whole number.
DecimalA number that may have a fractional part.
Booleantrue or false.
type = "Integer"

Optional. Text.

What the input is for, shown to whoever starts a run.

description = "What the haiku is about"

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 = true

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" }.

Required. Reference to a tool.

The tool whose calls get the value.

function = @ref("current-weather")

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"

Required. Text.

The input’s name: a run gives the input’s value under this name.

name = "temperatureUnit"

Optional. Reference to an agent.

Only the participant filled by this agent gets the value. Every participant when not set.

agent = @ref("weather-bot")

Optional. Text.

The value used when a run does not give one.

default = "celsius"

Optional. One of the values below. Default: "Request".

What target names: a field of the request body, a query parameter or a path parameter.

ValueMeaning
RequestA field of the request body.
QueryA query-string parameter.
PathA path parameter.
type = "query"

Optional. Text.

What the input is for, shown to whoever starts a run.

description = "celsius or fahrenheit"

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 = false

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" }.

Required. Reference to a tool.

The tool whose calls send the secret.

function = @ref("get-order")

Required. Text.

The input’s name: a run gives the input’s value under this name.

name = "shopKey"

Optional. Reference to an agent.

Only the participant filled by this agent sends it. Every participant when not set.

agent = @ref("support-agent")

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")

Optional. Text. Default: "Authorization".

The HTTP header the secret’s value is sent in.

header = "X-Api-Key"

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"

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 = true

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.

Optional. One of the values below. Default: "Automatic".

What happens when the conversation no longer fits the model’s context window.

ValueMeaning
NoneNothing until the conversation reaches the model’s hard limit; then it is shortened just enough to be sent.
AutomaticThe 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.
AggressiveAccepted, and trims as Automatic does.
FailOnOverflowNo trimming: a conversation that no longer fits makes the run fail, instead of going on without part of it.
mode = "Automatic"

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.8

Optional. One of the values below. Default: "OnOverflow".

When the results of earlier tool calls are replaced, to save space.

ValueMeaning
NeverNever: tool results are kept as they came back.
OnOverflowWhen the conversation no longer fits the context window.
AfterCyclesOnce an agent has had a set number of turns: every result but the latest.
BothBoth: after a set number of turns, and whenever the conversation no longer fits.
toolResultTrimming.mode = "Never"

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 = 6

context › 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]"

Optional. One of the values below. Default: "Placeholder".

What a replaced tool result becomes.

ValueMeaning
PlaceholderThe same replacement text for every result.
DigestA 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"

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.

ValueMeaning
SameAgentThe agent summarises its own conversation. Usually the best summary, since the agent already understands it, but an agent with strict instructions may refuse.
StandaloneAgentA separate call, without the agent’s instructions, writes the summary, so one is always made. It loses the agent’s own understanding.
NoneNo summaries: the conversation is only trimmed.
compaction.type = "SameAgent"

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.75

Optional. Whole number. Default: 8000.

The most recent part of the conversation kept word for word when it is summarised, in tokens.

compaction.keepRecentTokens = 16000

Optional. Whole number. Default: 4000.

The length the summary aims for, in tokens.

compaction.targetTokens = 8000

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 = 12

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 = 64000

Optional. Whole number. Default: 40000.

The most a summary may be, in tokens. Used only with compaction.type set.

compaction.maxTokens = 80000

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.

Optional. true or false. Default: true.

Turns memory on. false keeps the settings but leaves memory off.

enabled = true

Optional. One of the values below. Default: "Process".

Whose memory a run uses, and so whether it lasts beyond one run.

ValueMeaning
ProcessA fresh loom for every run. One caller’s threads never reach another’s run.
InteractionOne loom per agent (or one for the interaction, when shared) that lasts across every run.
InputOne loom per value of the run input named by the scope input, such as one per user.
scope = "Input"

Optional. Text.

For scope = "Input": the run input whose value picks the memory, such as "userName".

scopeInput = "email"

Optional. true or false. Default: false.

All the interaction’s agents share one memory. Otherwise each agent has its own.

shared = true

Optional. One of the values below. Default: "Suggest".

How remembered threads come back into a conversation.

ValueMeaning
OffNothing is offered: the agent searches its memory only when it chooses to.
SuggestThe agent is told what may connect, and chooses whether to recall it.
SurfaceThe relevant threads are shown in the conversation straight away.
recall = "Suggest"

Optional. One of the values below. Default: "Suggest".

How new memories are made from a conversation.

ValueMeaning
ManualOnly the agent weaves, with its LoomWeave tool.
SuggestThe weaver reads each exchange and offers what may be worth keeping; the agent decides.
AutoThe weaver weaves weak threads directly; use strengthens them, and disuse lets them fade.
weave = "Manual"

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 = 3000

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 = [ "customer" ]

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 = true

Optional. Whole number. Default: 15.

Minutes without activity before night weaving starts.

quietMinutes = 5

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"

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"

Optional. true or false. Default: false.

The vetModel also checks what an agent’s own searches of its memory bring back.

vetRecall = true

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")

Optional. List of references to looms.

Named looms the agents may read but never change.

readFrom = [ @ref("family") ]

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.

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") ]

Optional. List of text.

The seats (by name) that may start them. Every seat whose agent allows it when not set.

participants = [ "Lead" ]

Optional. Whole number.

How many levels of sub-runs may be started below this one. 1 when not set; at most 4.

maxDepth = 2

Optional. Whole number.

How many sub-runs may run at once, across the whole tree. 5 when not set; at most 20.

maxConcurrent = 5

Optional. Whole number.

How many sub-runs may be started in all, across the whole tree. 20 when not set; at most 100.

maxTotal = 10

A participant’s built-in web tools: webAccess = { search = true fetch = false }. Leave either out to keep its agent’s own setting.

Optional. true or false.

Gives (true) or takes away (false) the web search tool.

search = true

Optional. true or false.

Gives (true) or takes away (false) the web fetch tools.

fetch = true

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 agent › functions.openApi › auth.

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"

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")

From the 23-support-desk example project:

interactions/one-shot/draft-reply.mtr
agent = {
name = "Desk"
agent = @ref("desk-agent")
}
task = @prompt("draft-reply-task")
inputs.prompts = [
{
name = "customer"
description = "The customer's name"
required = true
},
{
name = "email"
description = "The customer's email address: whose memory the agent wakes up with"
required = true
},
{
name = "message"
description = "What the customer wrote"
required = true
},
{
name = "category"
required = true
},
{
name = "urgency"
required = true
},
{
name = "orderId"
required = false
}
]
functions.openApi = [
{
name = "find-order"
ref = @ref("find-order")
},
{
name = "issue-refund"
ref = @ref("issue-refund")
},
{
name = "search-policies"
ref = @ref("search-policies")
}
]
// The knowledge base id comes in with each run and goes straight into the search (tutorial 13).
inputs.functions.binding = [
{
function = @ref("search-policies")
name = "policiesId"
target = "partitionId"
description = "The knowledge base that holds the shop's policies"
required = true
type = "request"
}
]
// One memory per customer, chosen by their email address (tutorial 20).
loom = {
enabled = true
scope = "Input"
scopeInput = "email"
subjectInputs = [ "customer" ]
recall = "Suggest"
weave = "Manual"
}
duration.warn = "00:03:00"
duration.max = "00:05:00"