npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tarileo/core

v0.1.2

Published

Core engine for the Tari framework - AI agent runtime, sessions, and planning

Readme

@tarileo/core

Core engine for the Tari framework. Provides the AI agent runtime, session management, tool execution, sub-agents, planning, event publishing, and database schema.

Additional guides:

Installation

npm install @tarileo/core

Core concepts

  • Tari: root container that owns the session store, agent registry, event integration, and the high-level execute() API.
  • Agent: LLM runtime configured with a model, system prompt, tools, prompt layers, plugins, optional state, and optional sub-agents.
  • Sub-agent: specialist agent delegated by an orchestrator through the framework-provided delegate_to_subagent tool.
  • AISession: persisted conversation/runtime state. Stores messages, stream parts, metadata, active executions, cancellation state, and planner task state.
  • State: typed accessors over session metadata, registered with defineState() and consumed from runtime contexts with ctx.state(token).
  • Tari tool definition: lazy tool definition created with createTariToolFactory(tari). It is resolved with the runtime context so tools can access typed ctx, tari, services, logger, and execution metadata without capturing stale context.
  • Planner: optional capability that lets an agent generate a task plan and execute tasks concurrently through sub-agents.
  • Events: optional integration with @tarileo/events to publish session, message, stream, and execution lifecycle events.

Quick start

Create a Tari Instance

import { createTari } from "@tarileo/core";

const tari = createTari<AppContext>({
  database: db,
  eventBus,
  context: {
    getTenantId: (ctx) => ctx.restaurantId,
    getActorId: (ctx) => ctx.userId,
    getActorType: () => "user",
    getLogger: (ctx) => ctx.log,
  },
});

database must be a Drizzle instance with Tari tables registered. eventBus is optional, but required for execution lifecycle events and standalone sub-agent generation.

Define and register an agent

import { AgentBuilder, createTariToolFactory } from "@tarileo/core";
import { z } from "zod";

const tools = createTariToolFactory(tari);

const assistantTools = {
  get_status: tools.define({
    description: "Get the current status.",
    inputSchema: z.object({}),
    execute: async (_input, { ctx, tari, log }) => {
      log.info({ tenantId: ctx.restaurantId }, "Status requested");
      return { status: "ok", hasAgent: tari.hasAgent("assistant") };
    },
  }),
};

const assistant = AgentBuilder.define<AppContext>("assistant")
  .withModel(() => model)
  .withSystemPrompt("You are a helpful assistant.")
  .withMaxSteps(8)
  .addTools(assistantTools)
  .build();

tari.registerAgent("assistant", assistant);

Execute a prompt

const result = await tari.execute("assistant", ctx, {
  content: "Hola, revisa el estado actual.",
});

console.log(result.sessionId, result.executionId);

execute() creates a new session unless sessionId is provided. It persists the user message, starts an async agent execution, and returns immediately with identifiers.

Public API

createTari(config)

Creates a Tari root instance.

type TariConfig<TContext> = {
  database: TariDatabase;
  eventBus?: EventBus;
  context: {
    getTenantId: (ctx: TContext) => string;
    getActorId?: (ctx: TContext) => string | undefined;
    getActorType?: (ctx: TContext) => "user" | "system" | "agent";
    getLogger: (ctx: TContext) => TariLogger;
  };
};

The context callbacks are used for tenant isolation, actor attribution, and logging. All session operations receive the application context explicitly.

Tari

Main runtime container.

tari.registerAgent(name, agent);
tari.getAgent(name);
tari.hasAgent(name);
tari.execute(agentName, ctx, options);

registerAgent(name, agent)

Registers an agent by name and binds it to the Tari runtime. The registration name must match agent.getName().

getAgent(name)

Returns a registered agent or throws if it is missing.

hasAgent(name)

Checks whether an agent is registered.

execute(agentName, ctx, options)

High-level prompt API for application code.

await tari.execute("assistant", ctx, {
  sessionId: "optional-existing-session",
  content: "User prompt",
  attachments: [
    { url: "https://...", mimeType: "image/png", name: "photo.png", intent: "reference" },
  ],
  selection: [
    { id: "prod_1", type: "product", label: "Pizza", metadata: { category: "food" } },
  ],
  uiTools: [
    {
      name: "open_product_picker",
      description: "Open product picker in the UI.",
      inputSchema: { type: "object", properties: {} },
    },
  ],
  userContext: [
    { key: "currentPage", value: "/products" },
  ],
});

Returns:

{ sessionId: string; executionId: string }

createTariToolFactory(tari)

Creates a typed factory for lazy Tari tool definitions. The factory captures the Tari<TContext> instance once and preserves TContext in each tool's execution environment.

import { createTariToolFactory } from "@tarileo/core";
import { z } from "zod";

const tools = createTariToolFactory(tari);

const productTools = {
  create_product: tools.define<{ name: string }, { productId: string }>({
    description: "Create a product draft.",
    inputSchema: z.object({
      name: z.string(),
    }),
    execute: async ({ name }, { ctx, tari, services, log, execution, toolCall }) => {
      log.info({ toolCallId: toolCall.toolCallId }, "Creating product");

      const product = await services.productService.createDraft(ctx, { name });

      return {
        productId: product.id,
        sessionId: execution?.runtime?.sessionId,
      };
    },
  }),
};

The execution environment contains:

  • ctx: the current runtime context, typed from Tari<TContext>.
  • tari: the root Tari<TContext> instance captured by the factory.
  • log: ctx.log.
  • services: inferred from TContext["services"] when the application context has a services property; otherwise never.
  • execution: optional runtime execution metadata. It is present only when the context has been enhanced by the agent runtime.
  • toolCall: AI SDK tool-call options such as toolCallId, messages, and abortSignal.

tools.define(...) returns a lazy TariToolDefinition, not an eager AI SDK Tool. Core resolves it with resolveTariToolDefinition(definition, ctx) at runtime so tools use the current request/session context.

UI-only tools can omit execute:

const uiTools = {
  open_product_picker: tools.define({
    description: "Ask the frontend to open a product picker.",
    inputSchema: z.object({
      mode: z.enum(["single", "multiple"]),
    }),
  }),
};

tari.sessions

Session facade for persisted conversations.

const session = await tari.sessions.create(ctx, { source: "web" });
const existing = await tari.sessions.load(ctx, session.id);
const sessions = await tari.sessions.list(ctx, { limit: 20 });
const running = await tari.sessions.isRunning(ctx, session.id);
const cancelled = await tari.sessions.cancel(ctx, session.id, "user-cancelled");
await tari.sessions.delete(ctx, session.id);
  • create(ctx, metadata?): creates a root session.
  • load(ctx, sessionId): loads an active session, throwing when not found or archived.
  • list(ctx, filters?): lists sessions using repository filters.
  • delete(ctx, sessionId): archives a session and publishes deletion events when events are configured.
  • isRunning(ctx, sessionId): checks whether a session has an active execution.
  • cancel(ctx, sessionId, reason?): cancels the active execution for a session.

AISession

Represents a persisted session and runtime cancellation boundary.

Metadata

await session.refresh();
await session.update({ metadata: { source: "web" } });
await session.patchMetadata((metadata) => ({ ...metadata, activePanel: "chat" }));

Messages

await session.addMessage({
  role: "user",
  parts: [{ type: "text", text: "Hola" }],
});

const messages = await session.getMessages();
const recent = await session.listMessages({ limit: 20, order: "desc" });
const message = await session.getMessage("message-id");
await session.upsertMessage("message-id", "assistant", [{ type: "text", text: "Listo" }]);
await session.deleteMessage("message-id");

Stream parts

const parts = await session.listParts();
const part = await session.getPart("message-id", "part-id");
await session.createPart({ messageId: "message-id", type: "text", sequence: 0, payload: {} });
await session.deletePart("message-id", "part-id");

Runtime control

session.abort("manual-cancel");
session.onCancel((reason) => console.log(reason));
session.cancelActiveExecution("user-cancelled");
session.isStreaming();
session.getCurrentExecution();

Task-level cancellation is available with registerTaskController(), cancelTask(), unregisterTask(), and hasTask().

Planner helpers

session.hasActivePlan();
session.getActivePlan();
await session.getTasks();
await session.getTask("task-id");
await session.getTaskDetail("task-id");

Agent API

AgentBuilder

Builds orchestrator agents.

const agent = AgentBuilder.define<AppContext>("catalog-agent")
  .withModel(() => model)
  .withSystemPrompt(SYSTEM_PROMPT)
  .withMaxSteps(12)
  .withProviderOptions({ openai: { reasoningEffort: "low" } })
  .withTools(staticTools)
  .addTools(tariToolDefinitions)
  .addToolProvider((ctx) => createTenantTools(ctx))
  .withPromptLayer({ priority: "policy", content: "Follow restaurant policies." })
  .addContextLayer(async (ctx) => [
    { priority: "context", content: `Restaurant: ${ctx.restaurantName}` },
  ])
  .withSubAgent(productSubAgent)
  .addPlugin(plugin)
  .addState(cartState)
  .build();

Common methods:

  • withModel(factory): sets the Vercel AI SDK language model factory.
  • withSystemPrompt(prompt): sets the base system prompt.
  • withMaxSteps(steps): limits tool-call steps.
  • withProviderOptions(options): passes provider-specific options to streamText().
  • withDeps(deps): stores dependency references on the definition.
  • withTools(tools): registers static AI SDK tools.
  • addTools(tools): registers direct tool objects. Values may be AI SDK Tool objects or lazy TariToolDefinition objects from createTariToolFactory(tari).
  • addToolProvider(provider): resolves tools per request/context.
  • withPromptLayer(layer): adds a static layered prompt section.
  • addContextLayer(provider): injects dynamic prompt layers.
  • withSubAgent(agent): registers a specialist agent.
  • addPlugin(plugin): contributes tools and runtime prompt layers.
  • addState(token): enables typed session state for runtime tools.
  • withPlanner(config): enables planner tools and state.
  • withSessionStore(store): required when enabling planner directly on an unregistered agent.
  • build(): returns an Agent.

When an agent is registered with tari.registerAgent(), Tari binds the session store, event bus, and sub-agent session creation automatically.

SubAgentBuilder

Builds specialist agents for delegated work.

const productSubAgent = SubAgentBuilder.define<AppContext>("product-writer")
  .withLabel("Product Writer")
  .withDescription("Creates and improves product descriptions.")
  .withWhenToUse("Use when the task is about product copy.")
  .withInputFormat("A clear task with product identifiers and constraints.")
  .withOutputFormat("A concise summary and structured result.")
  .withModel(() => model)
  .withSystemPrompt(PRODUCT_PROMPT)
  .withMaxSteps(6)
  .addTools(productTools)
  .withAutonomyRules({
    whenContextMissing: "make_best_assumption",
    whenUncertain: "proceed_with_caution",
    defaultAssumptionBehavior: "Document assumptions in the final response.",
  })
  .build();

Specialist metadata is used in the orchestrator prompt so the parent agent knows when and how to delegate.

Agent

Runtime instance returned by the builders.

agent.getName();
agent.getDefinition();
agent.getMode();
agent.getModel();
agent.getMaxSteps();
agent.getTools(ctx);
agent.getSubAgents();
agent.buildSystemPrompt(ctx);
agent.prepare(ctx, messages);
agent.execute(input);
agent.prompt(ctx, { content: "..." });
agent.stream(ctx, input, { session });
agent.generate(ctx, "task", tools);

Use tari.execute() or agent.prompt() for application-level chat flows. Use prepare() + stream() when integrating with lower-level HTTP streaming handlers.

State API

defineState() creates a typed token over session metadata. The token must be registered with addState() and is then available from runtime tools through ctx.state(token).

import { defineState } from "@tarileo/core";

const cartState = defineState((meta) => ({
  getCart: async () => meta.get("cart"),
  setCart: async (cart) => meta.update((current) => ({ ...current, cart })),
  clearCart: async () => meta.update((current) => ({ ...current, cart: undefined })),
}));

const agent = AgentBuilder.define<AppContext>("cart-agent")
  .withModel(() => model)
  .withSystemPrompt("Manage the cart.")
  .addState(cartState)
  .addToolProvider(() => ({
    clear_cart: tool({
      description: "Clear the active cart.",
      inputSchema: z.object({}),
      execute: async (_input, { experimental_context }) => {
        const ctx = experimental_context as AppContextWithState;
        await ctx.state(cartState).clearCart();
        return { ok: true };
      },
    }),
  }))
  .build();

State is backed by session metadata, so it is scoped to one session and persists across turns.

Plugins

Plugins can add tools, prompt layers, and execution hooks.

import { createPlugin } from "@tarileo/core";

const plugin = createPlugin<AppContext>("restaurant-plugin")
  .addTools(restaurantTools)
  .addSystemPromptLayer(() => ({
    priority: "policy",
    content: "Use restaurant data safely.",
  }))
  .build();

createPlugin<TContext>() is generic so plugin tool definitions receive the same application context as the agent. Legacy plugins can still implement getTools(ctx) directly or use .addTool((ctx, deps) => tools).

Planner capability

Enable planner support when an orchestrator needs to split a batch request into multiple tasks and execute them concurrently.

const agent = AgentBuilder.define<AppContext>("batch-products")
  .withModel(() => model)
  .withSystemPrompt(SYSTEM_PROMPT)
  .withSubAgent(productSubAgent)
  .withPlanner({
    model: () => fastModel,
    concurrency: 3,
    maxTasks: 50,
    taskTimeoutMs: 300_000,
  })
  .build();

Defaults:

  • concurrency: 3
  • maxTasks: 50
  • taskTimeoutMs: 300000

The planner injects framework tools for plan generation/execution and stores the active plan in session metadata. Use session.getTasks() and session.getTaskDetail(taskId) to inspect progress.

Prompt layers

LayeredPromptBuilder composes prompt sections by priority. Agents use it internally for base prompts, context layers, plugin layers, planner layers, and sub-agent descriptions.

const prompt = new LayeredPromptBuilder()
  .addLayer("base", "You are an assistant.")
  .addLayer("context", "Restaurant: Central")
  .addLayer("policy", "Never expose secrets.")
  .build();

Database schema

The package exports Drizzle tables and TypeScript types:

import {
  tariAiSessions,
  tariAiMessages,
  tariAiMessageParts,
  tariAiSessionKinds,
  tariSessionStatuses,
} from "@tarileo/core";

Register these tables in the consuming application's Drizzle schema before passing the database to createTari().

Export reference

Root

  • createTari
  • Tari
  • TariConfig
  • TariDatabase
  • TariSchema
  • TariContext
  • TariActorType
  • TariLogger
  • ContextWithLogger

Agents and runtime

  • AgentBuilder
  • SubAgentBuilder
  • Agent
  • AgentPlugin
  • AgentMeta
  • AgentAutonomyRules
  • PreparedAgentInput
  • AgentStreamOptions
  • UIStrategy
  • StructuredOutputConfig
  • StructuredOutputResolver

Sessions

  • AISession
  • SessionRepository
  • session schemas and DTO types from @tarileo/core/agents/session

State

  • defineState
  • StateToken
  • StateMethods

Planner

  • PlannerCapabilityConfig
  • createGeneratePlanTool
  • createExecutePlanTool
  • planner types, state, and runtime helpers

Tools

  • createDelegateTool
  • createTariToolFactory
  • resolveTariToolDefinition
  • isTariToolDefinition
  • TariToolFactory
  • TariToolDefinition
  • TariToolDefinitionInput
  • TariToolExecute
  • TariToolExecuteApi
  • TariToolExecution
  • TariToolServices
  • TariToolCallOptions
  • InferTariContext

Prompt and context

  • LayeredPromptBuilder
  • PromptLayer
  • PromptLayerPriority
  • mergeContributions
  • consumeNextTurnContributions
  • normalizeContributions

Events and schema

  • TariEventPublisher
  • tariAiSessions
  • tariAiMessages
  • tariAiMessageParts
  • tariAiSessionKinds
  • tariSessionStatuses
  • Drizzle row/insert types for sessions, messages, and parts

License

MIT