Skip to content

Apps

An app is code that runs on Maitento. Use one when you need logic around your agents: start an interaction, look at its answer, branch, loop, start several more in parallel, write files, run a capsule. Apps are written in Cogniscript, a small C-like language.

See it in tutorial 16, Apps, which writes the app below, and tutorial 17, which runs it every morning with an automation. Tutorial 23’s nightly digest is an app that calls a tool, saves the day’s tickets to a file system and runs a capsule that reports on them.

apps/taglines/taglines.mtc
// The taglines app: it asks for three campaign angles, then writes a tagline for each angle, all at once.
// An app starts at main. main's parameters are the app's inputs: this one has one, product.
string main(string product) {
// Stop early, with a clear message, when the input is missing.
if (product == "") {
throw("Tell me which product to write taglines for.");
}
PrintLine("Brainstorming angles for " + product);
// Start the brainstorm interaction and wait for it. The last three arguments are for memory,
// model overrides and a response schema; this app uses none of them.
jsonObject brainstormInputs = JsonObjectCreate();
brainstormInputs = JsonObjectSetString(brainstormInputs, "product", product);
guid brainstormId = InteractionStart("brainstorm", brainstormInputs, "[]", "[]", "");
jsonObject brainstorm = InteractionAwait(brainstormId);
if (JsonObjectGet(brainstorm, "status") != "Finished") {
throw("The brainstorm failed: " + JsonObjectGet(brainstorm, "failureDetails"));
}
// The brainstorm's answer is JSON that matches json/ideas.json.
jsonObject result = StringToJsonObject(JsonObjectGet(brainstorm, "output"));
jsonArray ideas = JsonObjectGet(result, "ideas");
// Start one tagline run per idea. They all run at the same time.
jsonArray runIds = JsonArrayCreate();
int ideaCount = JsonArrayCount(ideas);
for (int i = 0; i < ideaCount; i++) {
jsonObject inputs = JsonObjectCreate();
inputs = JsonObjectSetString(inputs, "product", product);
inputs = JsonObjectSetString(inputs, "idea", JsonArrayGetAtIndex(ideas, i));
guid runId = InteractionStart("tagline", inputs, "[]", "[]", "");
runIds = JsonArrayAdd(runIds, runId);
}
// Wait for every tagline run, then collect the answers.
jsonArray runs = InteractionAwaitAll(runIds);
jsonArray taglines = JsonArrayCreate();
int runCount = JsonArrayCount(runs);
for (int j = 0; j < runCount; j++) {
jsonObject run = JsonArrayGetAtIndex(runs, j);
if (JsonObjectGet(run, "status") == "Finished") {
string tagline = JsonObjectGet(run, "output");
PrintLine("- " + tagline);
taglines = JsonArrayAdd(taglines, tagline);
}
}
// A named output is what your code reads back from the finished run. return gives the run's return value.
AppStateSetOutputJsonArray("taglines", taglines);
return(JsonArrayCount(taglines) + " taglines");
}
  • Each app is a folder under apps/, named after the app: apps/taglines/.
  • It holds one or more .mtc files with the code, and optionally one .mtr file with settings such as duration.max.
  • An app starts at main. main’s parameters are the app’s inputs, so main(string product) makes an app with one input called product.
  • A system call takes every argument, even the ones you don’t need: InteractionStart’s last three are there even when they’re empty. The deploy fails (“Argument count mismatch”) when one is missing.
Field on the finished runComes from
returnValuereturn(...) in main
outputsAppStateSetOutputString(name, value), AppStateSetOutputJsonArray(...) and friends
consoleOutputsPrintLine(...) and TraceLine(...)
failureDetailsan uncaught throw("...") (its message), or an error the app didn’t catch (InteractionStart failed: …, naming the system call)
const run = await mt.apps.run("taglines", { inputs: { product: "a reusable bamboo coffee cup" } });
console.log(run.outputs);

run() waits for the run. If it ends Error or Killed, run() throws (ProcessFailedError in TypeScript and Python, MaitentoProcessFailedException in C#) with the run’s failureDetails. To get the failed run back instead, pass throwOnFailure: false (throw_on_failure=False in Python, ThrowOnFailure = false in C#‘s RunOptions). A start without one of the app’s inputs is refused with api:apps:input-missing. See it in tutorial 16’s break-it step.

string main(string name) {
string greeting = "Hello " + name; // variables must be given a value
int count = 3;
for (int i = 0; i < count; i++) {
PrintLine(greeting);
}
if (count > 2) {
return("many"); // return, exit and throw need brackets
}
return("few");
}
  • Types: string, int, decimal, bool, guid, date, jsonObject and jsonArray. Every value is held as text underneath, so treat types as documentation.
  • Arithmetic is decimal: 7 / 2 is 3.5. + adds two numbers, and joins anything else.
  • Comparisons are exact: == compares text exactly, including case.
  • JSON helpers return a new value: write o = JsonObjectSetString(o, "key", "value");.
  • Errors: try { } catch { } catches them, and GetLastError() says what went wrong.
  • Backslashes need doubling in strings: "\\d".
AreaCalls
InteractionsInteractionStart, InteractionAwait, InteractionAwaitAll, InteractionAwaitAny
AppsAppStart, AppProcessAwait, AppStateSetOutput…
FilesVfsReadText, VfsWriteText, VfsFind, FileSearch
SandboxesCapsuleStart, CapsuleExec, CapsuleCommandAwait, CapsuleTerminate: see tutorial 21
ToolsExtOpInvoke
JSONJsonObjectCreate, JsonObjectGet, JsonObjectSetString, JsonArrayCreate, JsonArrayAdd, JsonArrayCount, JsonArrayGetAtIndex
TextStringToLower, StringContains, StringToJsonObject, RegexIsMatch
  • Child runs use your model keys. Interactions an app starts run on your tenant’s model keys, like any other run.
  • Every input is required when you start the app, and arrives as text.
  • Tools that need approval don’t run from apps. Approvals happen in interactions.