Provider Architecture & Security
The @magmacomputing/tempo-plugin-ai plugin is designed to be highly flexible, supporting both direct Bring Your Own Key (BYOK) integrations for backend systems, and Proxied integrations for frontend clients.
Bring Your Own Key (BYOK) & Zero-Config Discovery
For Node.js, Deno, and Bun backends, @magmacomputing/tempo-plugin-ai supports Zero-Config Auto-Discovery. If standard environment variables (GROQ_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, MISTRAL_API_KEY) are present, calling initAI() is optional—the plugin will automatically discover credentials and wire up provider defaults lazily on first function call.
Alternatively, you can supply your API keys and execution options explicitly via initAI:
import { initAI } from '@magmacomputing/tempo-plugin-ai';
initAI({
providers: [
...(process.env.GROQ_API_KEY ? [{ id: 'groq', key: process.env.GROQ_API_KEY }] : []),
...(process.env.GEMINI_API_KEY ? [{ id: 'gemini', key: process.env.GEMINI_API_KEY }] : []),
...(process.env.OPENAI_API_KEY ? [{ id: 'openai', key: process.env.OPENAI_API_KEY }] : [])
]
});Advanced Configuration (Custom Models & LLM Options)
By default, standard providers automatically map to their optimal APIs and default models. However, you can explicitly override URLs, models, and inject arbitrary LLM parameters (like temperature) for power-user control!
initAI({
providers: [
// 1. Enterprise Azure OpenAI (via Entra ID Bearer token or backend proxy wrapper)
// Note: BYOK requests send 'Authorization: Bearer <key>'. When connecting to Azure OpenAI,
// supply an Entra ID bearer token as provider.key or route through an Azure API gateway.
...(process.env.AZURE_ENTRA_BEARER_TOKEN ? [{
id: 'openai',
key: process.env.AZURE_ENTRA_BEARER_TOKEN,
url: 'https://my-enterprise.openai.azure.com/v1/chat/completions',
model: 'your-enterprise-model',
options: { temperature: 0.2, seed: 42 }
}] : []),
// 2. Local Open-Source Models (e.g. Ollama)
{
id: 'local',
key: 'no-key-needed',
url: 'http://localhost:11434/v1/chat/completions',
model: 'your-local-model',
options: { timeout: 5000 } // Custom provider-level timeout (5s)
}
]
});Per-Request Lazy Resolution & Fallback Defaults
When dispatching requests via transport.ts, all provider fields (key, url, model) and execution context (timeZone, locale, calendar, sphere) are resolved lazily just-in-time using functional evaluation (evaluate / evaluateAsync):
- Explicit Dynamic Suppliers: If a supplier function was provided (e.g.
key: async () => await getRotatedKey()), it is called per-dispatch. - Built-in Fallbacks: If a property is omitted or resolves to
undefined, the transport layer seamlessly cascades to the compiledDEFAULT_PROVIDERStemplates, remote manifest endpoints, and auto-discovered environment variables. - No Configuration Mutation: The dynamic resolution runs ephemerally per HTTP dispatch without mutating or locking shared global provider state.
Dynamic Provider Manifests & Remote Endpoint Trust
By default, @magmacomputing/tempo-plugin-ai lazily fetches provider defaults (model IDs, endpoints, token parameter keys) from https://tempo.magmacomputing.com.au/providers.v1.json once per application lifecycle.
- Remote Manifest Trust & Endpoint Enforcement:
remoteConfigUrlis restricted to fixed trusted hosts (tempo.magmacomputing.com.auor trusted internal HTTPS endpoints).- Any dynamic
provider.urlvalues received from the manifest or dynamically returned viafetchDefaultsare strictly validated against an enforced provider host allowlist (or must use verified HTTPS/localhost origins) beforegetResolvedProviderDefaults()merges them into runtime provider configurations. Untrusted or unauthenticated endpoints are rejected and stripped before merging.
- Validation on
fetchDefaultsHook: The exact same host allowlist and HTTPS origin verification is enforced when resolving custom provider options via thefetchDefaultscallback. Any dynamic hook attempting to return unauthenticated or disallowed host URLs will have theurlproperty safely discarded. - Async Resolution & Promise Lifecycle:
initAI()returns aPromise<void>.- Synchronous Fire-and-Forget: Calling
initAI(...)synchronously withoutawaitimmediately initializes system state with compiled local provider defaults (DEFAULT_PROVIDERS). You can executeparseAI()immediately on the next line without blocking. The remote manifest is fetched in the background and transparently updates provider defaults once received. - Guaranteed Remote Resolution: If your application strictly requires remote provider defaults to be resolved before executing your first AI request, you can
await initAI(...):typescript// Await guaranteed remote manifest completion before proceeding await initAI({ providers: [{ id: 'groq', key: process.env.GROQ_API_KEY! }] });
- Synchronous Fire-and-Forget: Calling
- Fail-Open & Air-Gapped Fallback: If the network request fails, times out (1500ms limit), or the application is running offline or in an air-gapped environment,
initAI()automatically and silently falls back to compiled local defaults (DEFAULT_PROVIDERS). - Disabling Remote Manifest: Pass
remoteConfigUrl: falseto disable remote manifest fetching entirely:typescriptinitAI({ providers: [{ id: 'groq', key: process.env.GROQ_API_KEY! }], remoteConfigUrl: false // Disable remote manifest fetching });
Frontend Security Warning
CAUTION
Never expose a raw LLM API key in a client-side browser bundle (like React, Vue, or Svelte) or store it in browser storage (localStorage, sessionStorage, IndexedDB, or browser cache). Any Cross-Site Scripting (XSS) vulnerability, compromised NPM dependency, or malicious browser extension can inspect client-side memory/storage and extract secret keys, leading to quota drainage, unexpected billing spikes, or account bans. BYOK provider keys are only safe on backend servers and edge workers.
Browser & Client-Side Proxy Architecture
To execute AI functions within client-side browser applications safely, route requests through a secure self-hosted backend proxy or unified AI Gateway (such as a Cloudflare Worker, Next.js API route, Express server, OpenRouter, Portkey, or LiteLLM):
1. Browser Configuration Example
Configure initAI in your browser code to target your backend proxy or AI Gateway URL:
import { initAI, parseAI } from '@magmacomputing/tempo-plugin-ai';
// Safe for browser deployment: No private LLM API keys are bundled
await initAI({
providers: [
{
id: 'my-gateway',
url: 'https://api.mycompany.com/v1/ai/chat/completions', // Your secure proxy endpoint
key: userSessionToken, // Short-lived user Bearer JWT token
model: 'llama-3.3-70b-instruct'
}
]
});
// All Tempo AI functions now execute securely through your proxy
const date = await parseAI("Team standup next Wednesday at 9:30am");2. Backend Proxy Handler Example (Next.js / Cloudflare Worker / Express)
Your backend endpoint receives the request, validates the user's session, enforces ingress quotas, attaches your private LLM API key, and forwards the validated payload to the upstream provider:
// Example: Next.js API Route / Cloudflare Worker / Express Proxy Handler
export async function POST(req: Request, env?: { GROQ_API_KEY?: string }) {
// 1. Authenticate user session
const authHeader = req.headers.get('Authorization');
const session = await validateUserSession(authHeader);
if (!session) {
return new Response('Unauthorized', { status: 401 });
}
// 2. Ingress validation & per-user quota enforcement
const body = await req.json();
if (typeof body?.prompt !== 'string' || body.prompt.length > 4096) {
return new Response('Invalid prompt or payload exceeds size limit', { status: 400 });
}
if (!checkUserRateLimit(session.userId)) {
return new Response('Too Many Requests', { status: 429 });
}
// 3. Resolve API key (Cloudflare Worker env binding or Node/Next.js process.env)
const apiKey = env?.GROQ_API_KEY || (typeof process !== 'undefined' ? process.env?.GROQ_API_KEY : undefined);
if (!apiKey) {
return new Response('Provider key configuration missing', { status: 500 });
}
// 4. Construct upstream fetch with bounded timeout and cleanup
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s upstream limit
try {
const upstreamResponse = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'openai/gpt-oss-120b',
messages: body.messages,
temperature: 0.1,
}),
signal: controller.signal
});
// 5. Return provider payload to client
const data = await upstreamResponse.json();
return new Response(JSON.stringify(data), {
status: upstreamResponse.status,
headers: { 'Content-Type': 'application/json' }
});
} catch (err: any) {
if (err.name === 'AbortError' || controller.signal.aborted) {
return new Response(JSON.stringify({ error: 'Upstream provider gateway timeout' }), {
status: 504,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response(JSON.stringify({ error: 'Upstream connection failure' }), {
status: 502,
headers: { 'Content-Type': 'application/json' }
});
} finally {
clearTimeout(timeoutId);
}
}🔒 Security & Privacy Guarantees
TIP
For an in-depth breakdown of our automated PII redaction, Smart Debug infrastructure, and tamper-resistant Proxy introspection, see the dedicated Security & Privacy Architecture Guide (security.md).
Whether running directly on backend servers (Node.js, Deno, Bun, Edge Workers) or through a client-side browser proxy, @magmacomputing/tempo-plugin-ai enforces strict security and privacy standards:
1. Transport Security (HTTPS / TLS)
All network communication—both from client to proxy and from proxy/server to upstream LLM endpoints—is required over HTTPS. Negotiated TLS versions (such as TLS 1.2 or TLS 1.3) depend on deployment environment and server configuration unless strictly enforced by your reverse proxy. Plaintext HTTP endpoints are disallowed in production environments (permitted only on localhost during local development).
2. Ephemeral Processing & Cache Retention Controls
Temporal processing payloads (dates, times, context snippets, prompts) are processed ephemerally. The plugin does not send telemetry or store user prompt data on external analytics servers. However, functions supporting caching (e.g. parseAI, formatAI, diffAI) may retain prompt-derived cache keys and final results in local memory or configured custom cache adapters according to the resolved TTL. Requests requiring zero cache retention must explicitly pass cache: false.
3. In-Memory Credential Redaction & Immutability
- Automated Key Redaction: Calling
getAiConfig()returns a sanitized, deeply read-only snapshot of active configurations with all providerkeyvalues replaced with[REDACTED], preventing accidental exposure in log files, APM traces, or crash dumps. - Frozen Metadata: All diagnostic metadata attached to
Tempoinstances via.aiand all structured AI result objects (TempoAiFormatResult,TempoAiExtractResult,TempoAiDiffResult,TempoScheduleResult,TempoRecurrenceResult,TempoContext) are deeply frozen withObject.freeze()and guarded via runtimeProxywrappers, protecting against direct runtime mutation.
4. Deterministic Schema Guardrails & Confidence Range Verification
All LLM prompts are paired with rigid, machine-verifiable JSON schemas. Responses undergo strict boundary validation, regex parsing, confidence range verification (0.0 to 1.0), and schema verification before any native Tempo date object or structured result payload is instantiated. If an LLM returns malformed, out-of-range, or unparseable data, the plugin throws a typed TempoAiError or triggers automatic provider fallback rather than silently propagating corrupt data.
5. Partitioned Caching & Fail-Open Storage Resilience
- Strict Cache Key Partitioning: Caches are namespaced and hashed (
ai:<namespace>::...) with timezone, locale, calendar, and anchor date isolation to prevent cross-tenant or cross-regional cache poisoning. - Fail-Open Protection: If a custom distributed cache adapter (e.g. Redis or Cloudflare KV) encounters network disruption or errors, the plugin automatically fails open to direct LLM resolution, preserving application uptime.
Multi-Provider Execution Strategies (AiMode)
Because third-party APIs can experience downtime, latency spikes, or quota exhaustion, @magmacomputing/tempo-plugin-ai provides six dedicated dispatch strategies configured via AiMode (or string literals):
| Strategy | Enum (AiMode) | Primary Advantage | Typical Use Case |
|---|---|---|---|
| Fallback (Default) | AiMode.Fallback | Minimum token cost (sequential cascade) | Default production baseline & background tasks |
| Hedged | AiMode.Hedged | Ultra-fast latency with low token overhead (~1.15x) | Latency-sensitive interactive search & chatbots |
| RoundRobin | AiMode.RoundRobin | Cyclic rotation across multi-key pools | High-throughput batch ingestion across API keys |
| Adaptive | AiMode.Adaptive | Telemetry-driven rate-limit avoidance | Multi-tier provider pools with mixed quotas |
| Race | AiMode.Race | Absolute minimum response latency | Real-time typeahead & autocomplete |
| Consensus | AiMode.Consensus | Cross-LLM verification & hallucination trapping | High-stakes legal, financial, and contract dates |
👉 For detailed architecture breakdowns, Mermaid decision trees, and configuration guides for each mode, see the Multi-Provider Execution Modes Guide (modes.md).
Provider ID Canonicalization
Provider IDs are normalized case-insensitively during initAI lookup (e.g. 'Gemini', 'gemini', 'OpenAI'), automatically applying default endpoints and models while preserving the caller's registered identifier for logging and metadata.