@intertrace-runtime/runtime
v0.4.1
Published
Intertrace runtime protection SDK — authorize+permit tool gates and agent-builder adapters
Maintainers
Readme
@intertrace-runtime/runtime
Authorize every tool call before it runs. The SDK talks to the Intertrace
edge at https://intertrace.fly.dev.
npm install @intertrace-runtime/runtimeLLM plane
Point any OpenAI-compatible client at the edge with a runtime key. No tool wrapper required.
import { openaiCompatibleConfig } from "@intertrace-runtime/runtime";
import OpenAI from "openai";
const edge = openaiCompatibleConfig({
apiKey: process.env.INTERTRACE_RUNTIME_API_KEY!,
assetId: "support-agent",
projectId: process.env.INTERTRACE_PROJECT_ID,
agentId: process.env.INTERTRACE_AGENT_ID,
});
const client = new OpenAI(edge);Use the same baseURL + itr_rt_* key with LangGraph ChatOpenAI, CrewAI
LLM, LiteLLM, Mastra, Pydantic AI, LlamaIndex, AutoGen, Semantic Kernel, and
OpenAI Agents (set_default_openai_client + often
set_default_openai_api("chat_completions")).
A runtime key is enough for chat. Send project + agent headers together, or send neither — agent-id alone is rejected.
Tool plane
Wrap tools so authorize + an execution permit run before the body.
import { IntertraceRuntime } from "@intertrace-runtime/runtime";
const runtime = IntertraceRuntime.fromEnv();
const { sessionId } = await runtime.startSession({ taskSummary: "Handle ticket" });
const sendEmail = runtime.protectTool(
{
name: "send_email",
category: "external_communication",
actionType: "write",
dataBoundary: "external",
possibleDataClasses: ["customer_pii"],
},
async (args: { to: string; body: string }) => ({ ok: true, to: args.to })
);
await sendEmail({ to: "[email protected]", body: "Hello" });
await runtime.endSession(sessionId);fromEnv() reads INTERTRACE_API_KEY / INTERTRACE_RUNTIME_API_KEY,
INTERTRACE_PROJECT_ID, INTERTRACE_AGENT_ID, INTERTRACE_AGENT_PURPOSE,
INTERTRACE_MODE. The first protectTool starts a real gateway session if you
skip startSession() — it never invents a fake session UUID.
Ask your app's own user
Some asks are the user's to answer, not your security team's: during an
agent's learning period, an installer, a project's .env, outside
production. Pass confirm and Intertrace hands those to you instead of
opening an approval in its inbox; everything the organization decides
(approval rules, payments, admin changes, anything leaving the company,
production) still waits for a person in Intertrace.
const runtime = new IntertraceRuntime({
// ...
confirm: async ({ question, toolName }) => window.confirm(`${question}\n\n(${toolName})`),
});
// The user's latest message lets Intertrace skip asking when the call is
// plainly what they asked for. Untrusted text; never stored.
runtime.setUserRequest(lastUserMessage);A yes re-runs the authorize with the user's confirmation and the tool runs; a
no throws IntertraceBlockedActionError. Without confirm, those asks wait
for a person in Intertrace as before.
Framework adapters
Duck-typed. No framework packages required at install. Every adapter routes
through protectTool → authorize → permit.
| Builder | Method | What it wraps |
|---|---|---|
| LangChain / LangGraph | protectLangChainTool | func, invoke, and call (one authorize; no double-gate) |
| Vercel AI SDK 4/5+ | protectVercelAiTool | execute (keeps parameters and inputSchema) |
| OpenAI Agents | protectOpenAIAgentsTool | execute, invoke(runContext, input), on_invoke_tool |
| Mastra | protectMastraTool | execute (keeps context arg) |
| LlamaIndex | protectLlamaIndexTool | fn / call / acall |
| CrewAI | protectCrewAiTool | _run / run |
| AutoGen / AG2 | protectAutoGenTool | run / _run / func |
| Semantic Kernel | protectSemanticKernelTool | invoke / invokeAsync |
| Pydantic AI, Haystack, Agno, DSPy | protectPydanticAiTool | a function, or func / run |
const search = runtime.protectLangChainTool(
{ name: "crm.search", category: "crm", actionType: "read", dataBoundary: "internal" },
{ name: "crm.search", description: "Search CRM", func: async ({ q }) => ({ q }), invoke: async ({ q }) => ({ q }) }
);
await search.invoke!({ q: "acme" });const email = runtime.protectVercelAiTool(
{ name: "email.send", category: "external_communication", actionType: "send", dataBoundary: "external" },
{
description: "Send an email",
inputSchema: { type: "object", properties: { to: { type: "string" } } },
execute: async ({ to }) => ({ sent: true, to }),
}
);Blocked (BLOCK) throws IntertraceBlockedActionError without running the
executor.
When an action needs a person (REQUIRE_APPROVAL), the call waits for the
decision and then runs by itself once approved. No resend is needed:
const runtime = new IntertraceRuntime({
// …
approvalWait: {
onWaiting: ({ ruleName, stage }) => console.log("Waiting for approval", ruleName, stage?.name),
// maxWaitMs: 5 * 60_000, // default: until the approval expires (max 60 min)
// enabled: false, // throw IntertraceReviewRequiredError immediately instead
},
});A denial throws IntertraceApprovalDeniedError (a subclass of the blocked
error). An expiry or timeout throws IntertraceReviewRequiredError. The tool
never runs without an approval, even under a fail-open policy.
runtime.waitForApproval(id) is available for custom flows. Enforce mode is fail-closed. Authorize defaults to a 15s timeout
(decisionTimeoutMs) so a cold edge path is not aborted.
Subpath: @intertrace-runtime/runtime/adapters.
Errors
Catch the typed errors. isIntertraceError(err) is the type guard.
| Class | code | When |
|---|---|---|
| IntertraceAuthenticationError | INVALID_API_KEY | 401 |
| IntertraceBlockedActionError | BLOCKED | Policy denied the tool |
| IntertraceApprovalDeniedError | BLOCKED | A person denied the action (or the approval was already used) |
| IntertraceReviewRequiredError | APPROVAL_REQUIRED | Approval expired, wait timed out, or waiting is turned off |
| IntertraceUnavailableError | INTERNAL_ERROR | Edge timeout / 5xx (retryable) |
| IntertraceInvalidConfigurationError | INVALID_CONFIGURATION | Missing key, project, or agent |
Edge
baseUrl defaults to https://intertrace.fly.dev. Override with
INTERTRACE_GATEWAY_URL or the baseUrl constructor field.
License
Intertrace Proprietary License — see LICENSE. Licensed for use with an Intertrace account. Contact [email protected] for redistribution.
