Reference for the atomic Local AI script API — the server-side method that calls Local AI atomically (one-shot, stateless, no transcript, no tool dispatch). New code uses AI.Execute from the T.Toolkit.LocalAI namespace; the legacy TK.AIExecute alias is retained as an [Obsolete] forwarder for backward compatibility.
AI Integration → Local AI → AI.Execute API Reference
Canonical surface (10.1.5+): AI.Execute(query) / AI.ExecuteAsync(query), from the T.Toolkit.LocalAI namespace. Add T.Toolkit.LocalAI to the script's NamespaceDeclarations so the unqualified form resolves, or call T.Toolkit.LocalAI.AI.Execute(query) fully qualified.
Legacy alias: TK.AIExecute(query) / TK.AIExecuteAsync(query) still work — they are [Obsolete] (CS0618 compile-time warning), hidden from IntelliSense, and forward internally to AI.Execute. Pre-10.1.5 scripts compile and run unchanged. New code uses AI.Execute.
What it is
AI.Execute is a static method on the T.Toolkit.LocalAI.AI Toolkit class. A server-domain script calls it with a query string and gets back a SPEC reply envelope JSON. Every call is an independent one-shot LLM round-trip — no transcript, no caching, no tool dispatch, no hooks. The atomic counterpart to the operator-facing ChatRequest Display action.
Use it for: alarm probable-cause narration, message translation, text rephrase, classification, summarization, and any other "run this through an LLM and give me the answer" task that does not need follow-up turns.
Signatures
// In the T.Toolkit.LocalAI namespace. // Synchronous — returns the full reply envelope JSON. string AI.Execute(string query); // Async overload — for native async/await scripts. Task<string> AI.ExecuteAsync(string query); // Legacy flat-on-TK aliases — [Obsolete] (CS0618), hidden from IntelliSense. // Retained for backward compatibility; forward to AI.Execute internally. string TK.AIExecute(string query); Task<string> TK.AIExecuteAsync(string query);
Namespace setup. Add T.Toolkit.LocalAI to the script row's NamespaceDeclarations so unqualified AI.Execute resolves. Or call fully qualified as T.Toolkit.LocalAI.AI.Execute(query). Examples below assume T.Toolkit.LocalAI is declared.
Parameter | Type | Notes |
|---|---|---|
| string | Either a plain text question, or a structured query JSON with |
Returns | Notes |
|---|---|
string (JSON) | The reply envelope. Always well-formed JSON, parseable with |
Where it can be called from
AI.Execute is a Toolkit static — callable from any script context. But the resolution and execution happen in whichever process is running the calling code, and meaningful execution requires a server-domain ObjectServer. Practical surface:
Context | Works? | Notes |
|---|---|---|
Server.Class method | Yes | The canonical caller. Class methods invoked from Server-domain trigger contexts (alarm callbacks, dataset cycles, custom server logic) execute in TServer with full server-side state. |
Server-trigger Script.Task | Yes | Tasks running under |
Report generator (server-side report rendering) | Yes | ReportServer hosts a server-side ObjectServer; reports may call |
Alarm-event callback (server-domain) | Yes | Alarm callbacks fire under TServer. |
Display CodeBehind (WPF or HTML5 client) | No (returns error envelope) | Display CodeBehind runs at the client. The ambient ObjectServer is the client-side instance; secret resolution short-circuits, the LLM endpoint URL may not be reachable, and the call falls back to a normal HTTP-error envelope. Use the |
The platform does NOT add a runtime gate that blocks client-side callers — instead, the existing platform safety nets ensure no silent secret leak. A misrouted client-side call returns status="error" with an HTTP-error warning, never a successful POST with degraded credentials.
Query format
Two accepted shapes — the simple form and the structured form.
Simple form (plain text)
Pass any plain string. The platform wraps it as the user message of a single-turn LLM exchange:
string reply = AI.Execute("Translate to French: Pump 1 is offline.");
Structured form (JSON object)
Pass a JSON object with any combination of these top-level fields:
Field | Required? | Role |
|---|---|---|
| Required when using structured form | The user-role message — the actual question or instruction. |
| Optional | The system-role message — sets the LLM's persona, voice, output constraints. |
| Optional | Arbitrary structured data the LLM should consider when answering. Typically a JSON object holding tag values, sensor readings, or domain context. Serialized into the LLM prompt. |
| Optional | Reserved for caller-side annotation; the platform does not currently consume it. |
var query = new JObject
{
["system"] = "You are a SCADA alarm-message translator. Preserve tag names and " +
"numeric values verbatim. Keep replies operator-friendly.",
["user"] = "Translate to French: Pump 1 is offline.",
["context"] = new JObject { ["targetLanguage"] = "fr" }
};
string reply = AI.Execute(query.ToString());
Reply envelope
Every call returns the same JSON shape. Field reference and status semantics: Local AI Reply Envelope Schema.
Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'{
"text": "<the LLM answer text or '' on non-ok status>",
"status": "ok | error | disabled | truncated",
"toolTrace": [],
"latencyMs": 832,
"warnings": []
}Note: toolTrace is always an empty array ([]) for atomic calls — the atomic path has no tool surface. This differs from the ChatRequest action, which may dispatch tools and populate toolTrace with each one.
Exception model — never throws
AI.Execute never throws. The legacy TK.AIExecute alias inherits the never-throws contract through the forwarder. Every failure path — invalid context, model offline, network error, malformed query, gate disabled, internal exception — returns a well-formed reply envelope with status set to error or disabled and an explanatory entry in warnings[].
Failure modes:
Situation |
|
|
|---|---|---|
Invalid query JSON |
|
|
Structured query missing |
|
|
|
|
|
LLM endpoint URL empty or unresolvable |
|
|
Wall-clock budget (60s) exceeded |
|
|
HTTP non-2xx response |
|
|
Network failure (connection refused, DNS, etc.) |
|
|
Other unhandled exception |
|
|
In all cases the envelope is well-formed and parseable. Customer scripts can rely on JObject.Parse(reply) never throwing on a Local AI reply.
Master gates
The atomic path applies only ONE master gate:
SolutionCapabilities[LocalAI].Enabled = true— kill-switch must be ON. Off returnsstatus="disabled"immediately, withlatencyMs = 0.
Atomic does NOT consult ModelOptions — the bitmask gates the tool surface, and the atomic path has no tools. A solution with SolutionCapabilities[LocalAI].Enabled = true and SolutionSettings.ModelOptions = 0 (every bit off) can still call AI.Execute("summarize this") and receive a normal reply.
This asymmetry is deliberate: it lets a solution reserve the tool-equipped chat surface for selected operator panels (master tool bit OFF) while still using AI.Execute for pure-language tasks like translation and summarization.
Worked examples
Each example assumes the Server.Class lists T.Toolkit.LocalAI in NamespaceDeclarations so the unqualified AI.Execute calls resolve. If you prefer not to declare the namespace, swap each AI.Execute for T.Toolkit.LocalAI.AI.Execute.
Example 1 — Multi-tag root-cause hypothesis on an alarm
When a critical alarm fires, an operator typically scans several related tags to form a hypothesis about the actual cause. This Server.Class collects those tags automatically and asks the LLM to correlate them into a probable-cause statement.
public void DiagnosePumpHighTemp()
{
var snapshot = new JObject
{
["alarm"] = "Pump1.HighTempAlarm",
["bearingTempC"] = (double)@Tag.Pump1.BearingTemp,
["motorCurrentA"] = (double)@Tag.Pump1.MotorCurrent,
["dischargePressBar"] = (double)@Tag.Pump1.DischargePress,
["suctionPressBar"] = (double)@Tag.Pump1.SuctionPress,
["flowRate_m3h"] = (double)@Tag.Pump1.FlowRate,
["vibrationMmS"] = (double)@Tag.Pump1.Vibration,
["ambientTempC"] = (double)@Tag.WeatherStation.AmbientTemp,
["runHoursSinceMaint"] = (int)@Tag.Pump1.RunHoursSinceMaint
};
var query = new JObject
{
["system"] = "You are a rotating-equipment reliability engineer. Given a snapshot " +
"of related sensor readings around a pump high-temperature alarm, " +
"produce ONE sentence stating the most likely root cause and ONE " +
"sentence with the next operator action. No preamble.",
["user"] = "Diagnose this alarm.",
["context"] = snapshot
};
string reply = AI.Execute(query.ToString());
string text = JObject.Parse(reply).Value<string>("text") ?? "";
@Tag.Pump1.LastDiagnosisText = text;
@Tag.Pump1.LastDiagnosisJson = reply;
}
Why AI vs. without: a non-AI script could only template a fixed sentence per alarm tag. The LLM correlates the eight numeric inputs against background domain knowledge of pump failure modes and selects the explanation that fits this specific snapshot.
Example 2 — Multi-language alarm message translation
Critical alarm message authored in English; site operators read other languages. Translate while preserving technical terms verbatim.
public void LocalizeCriticalAlarm()
{
string englishText = @Tag.Alarm.LastCriticalMessage;
string targetLang = @Tag.System.LocaleForOperator;
if (targetLang == "en" || string.IsNullOrEmpty(englishText))
{
@Tag.Alarm.LastCriticalMessageLocalized = englishText;
return;
}
var query = new JObject
{
["system"] = "You are a SCADA alarm-message translator. Translate the user's English " +
"alarm into the target language. Preserve tag names, sensor IDs, units, " +
"and numeric values verbatim. Keep it short and operator-friendly.",
["user"] = englishText,
["context"] = new JObject { ["targetLanguage"] = targetLang }
};
string reply = AI.Execute(query.ToString());
string status = JObject.Parse(reply).Value<string>("status") ?? "error";
string text = JObject.Parse(reply).Value<string>("text") ?? "";
@Tag.Alarm.LastCriticalMessageLocalized = (status == "ok") ? text : englishText;
}
Example 3 — Operator note rephrase
Free-text operator notes get filed verbatim, then asynchronously rephrased into a consistent house-style summary for the shift report.
public void RephraseOperatorNote()
{
string raw = @Tag.OperatorNote.LastEntry;
if (string.IsNullOrWhiteSpace(raw))
{
@Tag.OperatorNote.LastEntryRephrased = "";
return;
}
var query = new JObject
{
["system"] = "Rephrase the operator's free-text note into ONE concise sentence in " +
"third-person past tense. Preserve every numeric value and tag reference. " +
"No editorial commentary.",
["user"] = raw
};
string reply = AI.Execute(query.ToString());
string text = JObject.Parse(reply).Value<string>("text") ?? raw;
@Tag.OperatorNote.LastEntryRephrased = text;
}
Synchronous vs async
AI.Execute is synchronous and wraps the async overload via the platform helper T.Library.tRPC.AsyncHelpers.RunSync. Use the synchronous form from a Server.Class method that needs a result inline; use AI.ExecuteAsync from native async script contexts.
Do NOT use raw .Result or .GetAwaiter().GetResult() on AI.ExecuteAsync — those patterns deadlock under a UI SynchronizationContext or surface AggregateException instead of unwrapping the inner exception. The synchronous overload handles both correctly via the platform helper.
Migrating from TK.AIExecute
One-line change. Two cases:
Existing call | Replacement |
|---|---|
|
|
|
|
Behavior is identical — the legacy alias forwards to the canonical implementation. The migration removes the CS0618 compile-time warning and restores IntelliSense for the call site.
What AI.Execute does NOT do
- Does not stream replies. Each call returns one complete envelope when the model finishes.
- Does not maintain a transcript. Every call is independent — the LLM sees only the supplied query.
- Does not dispatch tools. The LLM cannot read tags, browse the namespace, or query alarms during an
AI.Executecall. For tool-equipped chat, use theChatRequestDisplay action. - Does not raise
OnBeforeChatorOnAfterChatReplyhooks. Hooks are scoped to the chat surface only. - Does not retry on transient failure. A failed call returns the error envelope immediately; the calling code decides whether to retry.
- Does not throw on failure (see Exception model).
See also
- Local AI — the parent reference, includes a quick-start.
- ChatRequest Action Reference — the operator-chat counterpart.
- Local AI Configuration — endpoint, master enable, and bitmask configuration.
- Local AI Reply Envelope Schema — full reply schema reference.
In this section...