Compose tools, MCP, Skills, files, sessions and UI around the same runtime. Selecting a tool does not grant permission: every example remains subject to application capabilities and runtime checks.
Custom tools and function calling with defineTool
Implement the execution side of AI tool calling with your own business functions. Parameter definitions generate the model-facing schema; handlers can query orders, tickets or internal data. Enforce tenant and user authorization inside those functions.
import { createSession, defineTool } from '@tansr/sdk';
const searchOrders = defineTool({
name: 'searchOrders',
description: 'Search orders for the authenticated user',
parameters: { keyword: { type: 'string' } },
readOnly: true,
handler: async ({ keyword }) =>
db.searchForUser(verifiedUserId, keyword),
});
const session = await createSession({
token, baseUrl,
tools: { builtin: [], custom: [searchOrders] },
});
readOnly describes tool effects; it does not bypass authorization. Handler exceptions become structured tool errors. Keep credentials and sensitive internal error details out of results.
MCP tool integration over stdio and HTTP
Attach existing MCP services for knowledge and business systems. Configure a toolAllowlist per server and choose lazy discovery or eager loading. Connections can belong to one session or be shared by the application.
import { createMcpHost, createSession } from '@tansr/sdk';
const host = createMcpHost({
servers: {
local: { transport: 'stdio', command: 'node',
args: [mcpServerEntry] },
knowledge: { transport: 'http',
url: 'https://mcp.example.com/mcp',
toolAllowlist: ['search'] },
},
});
const session = await createSession({ token, baseUrl, mcp: host });
// Reuse host across sessions; dispose when the application exits.
// await host.dispose();
An allowlist limits exposed tools; it does not replace runtime approval. MCP calls are treated conservatively as third-party operations. Configure explicit permission rules or askUser. Closing a session does not dispose of a shared host.
Local file processing for an AI file assistant
Read files, list directories, search with Glob/Grep, and enable authorized writes or edits for document assistants, project analysis and desktop workflows. Choose the tools your application needs, then decide which operations require confirmation.
const session = await createSession({
token, baseUrl,
cwd: workspaceDir,
tools: { builtin: ['read', 'glob', 'grep', 'list'] },
});
write, edit and shell can be explicitly selected when authorized. cwd sets a working directory, not an operating-system sandbox. The host must still constrain process privileges and access to data.
Agent Skills for business knowledge and procedures
Use defineSkill for inline instructions or dirs for explicitly supplied SKILL.md directories. A brief index enters context and detailed instructions load on demand, so a business process need not place every document in every prompt.
import { createSession, defineSkill } from '@tansr/sdk';
const review = defineSkill({
name: 'contract-review',
description: 'Contract review procedure',
whenToUse: 'When the user asks to review contract risks',
instructions: '# Review\nList facts, then flag items for human review.',
});
const session = await createSession({
token, baseUrl,
skills: { custom: [review], dirs: ['./assets/skills'] },
});
The SDK does not scan an end user's skill directories automatically. Skills provide knowledge and guidance; they grant no extra permissions and do not guarantee correct model output. Enable the application's skills capability first.
Streaming AI output and tool execution states
createSessionView projects text deltas, tool execution states and usage into immutable UI state for React or another interface. createNarrator can produce readable logs alongside it. AgentSession.events gives each subscriber an independent cursor.
import { createSessionView, createNarrator } from '@tansr/sdk';
const view = createSessionView(session, {
delivery: { text: 'stream', thinking: 'off' },
});
const unsubscribe = view.subscribe(state => render(state));
const narrator = createNarrator(session.events, {
verbosity: 'normal', onLine: line => logger.info(line),
});
view.appendUserMessage(text);
session.send(text);
// Host teardown: unsubscribe(); view.dispose(); narrator.dispose();
Attach subscribers before sending prompts; a late subscriber should not expect a complete replay. Add user messages to the view explicitly. Hiding thinking output does not stop the model from generating or charging for thinking tokens.
Electron AI integration through the main process
For a desktop application AI SDK, run the session and tools in Electron's main process and keep the token there. Send projected state to the renderer; expose a narrow preload bridge for user input and approval responses.
// Electron main process: window is your BrowserWindow.
const session = await createSession({ token, baseUrl });
const view = createSessionView(session);
const unsubscribe = view.subscribe(state => {
window.webContents.send('agent:state', state);
});
// Handle input via a narrow IPC/preload bridge.
// Validate the sender and input before session.send(text).
See the Electron main process, preload and approval bridge examples in the docs. Electron must satisfy the SDK's Node requirement; the example uses Electron ≥39. Do not expose app keys, unrestricted filesystem access or arbitrary execution to the renderer.
Multi-turn conversations, session storage and resume
Start with in-memory agent session management, then inject a SessionStore. createFileSessionStore supplies a filesystem implementation; custom stores can implement the same interface. Loading history and continuing to save it are separate options.
import { createFileSessionStore, createSession } from '@tansr/sdk';
const store = createFileSessionStore({ dir: userDataDir });
const session = await createSession({ token, baseUrl, store });
session.send('Remember the requirements for this task');
await session.idle();
const sessionId = session.sessionId;
session.close();
const resumed = await createSession({
token, baseUrl,
resume: { sessionId, store },
store, // Continue persisting the resumed conversation.
});
Sessions stay in memory when no store or persistence callback is supplied. initialMessages and onHistoryCommit can integrate an existing database. When meta.rewritten is true, replace stored history instead of appending only its tail. The host owns storage authorization, encryption and retention.
Context compaction and restorable checkpoints
The runtime supports automatic compaction when the model's context window is known, plus explicit compact, checkpoint and restore operations. Long tasks can save a context checkpoint and later restore it or continue on a branch.
// A store with checkpoints has been wired into session.
await session.idle();
const mark = await session.checkpoint({ label: 'before-summary' });
const result = await session.compact({
instructions: 'Preserve task constraints and unfinished work',
});
if (result.status === 'compacted') {
console.log(result.compactionId);
}
const restored = await session.restore(mark.checkpointId);
console.log(restored.status);
Compaction is a lossy summary, not a promise to remember every detail forever. Restoring context does not undo file writes, network requests or external business actions. Keep critical facts in your trusted application storage.
Multi-model integration and session model switching
Platform token mode uses the application's authorized model directory and switches subsequent turns through available aliases. Node.js services can also use locally configured managed mode; tests and special integrations can inject a client and model together.
const session = await createSession({ token, baseUrl });
// Use an alias/handle available in this app's authorized bundle.
session.setModel('main');
session.send('Continue using the newly selected model');
An arbitrary vendor model name is not enough to obtain access. setModel affects subsequent turns, not a request already running. Input modalities, context windows and output capabilities depend on the selected model.
System tools for images, video, speech and search
imageGen, videoGen, speechToText and textToSpeech are kernel tools. New integrations select them through tools.builtin. SDK token mode uses platform providers; tool selection and capability authorization remain separate checks.
const session = await createSession({
token, baseUrl,
tools: { builtin: [
'imageGen', 'videoGen', 'speechToText', 'textToSpeech',
] },
});
Select media tools explicitly; they do not enter the default tool set. They also need platform access, authorized models and enabled capabilities. tools.platform is a compatibility alias. webSearch belongs in builtin too and requires both its tool capability and platform search channel; the SDK supplies no BYO search backend.
Agent permissions and tool-call approval
Application capabilities decide what can be assembled; runtime rules decide whether a specific call may execute. askUser routes confirmation to your interface. Platform token mode can also consult the application's appointed adjudicator.
const session = await createSession({
token, baseUrl,
permission: {
rules: {
deny: ['Shell'],
ask: ['Write', 'Edit', 'mcp__knowledge__*'],
},
askUser: async (call, signal) => {
const approved = await confirmTool(call.name, call.args, signal);
return approved ? 'allow' : 'deny';
},
},
});
Calls that still require confirmation do not execute by default without a callback. In 0.11.1, an explicit permission.mode conflicts with an appointed adjudicator, so this example omits mode. Do not rely on the unreleased 0.12.0 compatibility change. Approval is not OS isolation and does not replace business authorization.