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

@aipexstudio/aipex-core

v0.0.15

Published

AIPex Agent - Pure TypeScript AI Agent Framework

Readme

@aipexstudio/aipex-core

Platform-agnostic TypeScript building blocks for creating streaming, tool-using AI agents.

@aipexstudio/aipex-core wraps @openai/agents and adds a few opinionated layers that are useful for productizing agents:

  • A stable event stream (AgentEvent) that UIs can consume
  • Optional conversation/session management (persistence, listing, forking)
  • Optional conversation compression for long-running sessions
  • A context system for attaching external data to a turn (ContextManager + ContextProvider)
  • Tool utilities, including a schema-first ToolRegistry

Why a separate "core" package?

  • Platform boundary: no Chrome APIs, no Node-only assumptions. This keeps core usable in browsers, servers, and extensions.
  • Streaming-first: instead of returning a single string, the agent emits structured events (text deltas, tool lifecycle, metrics, errors).
  • Composable integrations: persistence, context providers, and UI are all optional and pluggable.

Core concepts

Agent + event stream

AIPex.chat() returns an AsyncGenerator<AgentEvent>. Typical consumers:

  • CLI: print content_delta as it streams
  • UI: render streaming text, show tool calls, attach contexts, show metrics

Key event types include:

  • content_delta: incremental text tokens
  • tool_call_start / tool_call_complete / tool_call_error
  • tool_call_args_streaming_start / tool_call_args_streaming_complete (best-effort, provider-dependent)
  • session_created / session_resumed (when conversation management is enabled)
  • metrics_update / execution_complete
  • contexts_attached / context_error

Tools

There are two complementary ways to work with tools:

  1. Direct function tools via tool() (re-exported from @openai/agents)
  • Define name/description + a Zod schema
  • Provide an execute() implementation
  1. Registry-managed tools via ToolRegistry
  • Register a UnifiedToolDefinition (schema + handler(input, ctx))
  • Execute locally (registry.execute(...))
  • Convert to OpenAI-compatible function tools (registry.toOpenAIFunctions())

Built-in tools shipped by core:

  • calculatorTool: basic arithmetic
  • httpFetchTool: simple HTTP GET fetch (returns JSON when content-type is JSON)

Conversations, sessions, and compression

When conversation management is enabled (default), the agent creates a session and persists turn items via a SessionStorageAdapter.

  • Disable sessions by setting conversation: false
  • Persist sessions by providing your own storage adapter
  • Fork sessions (branch conversation history) with ConversationManager.forkSession(...)
  • Compress sessions using ConversationCompressor to summarize older turns

Contexts

A context is an additional piece of information you attach to a single turn (e.g. current page text, a selected tab, a file, a screenshot, etc.).

  • Implement a ContextProvider for your environment
  • Register providers with a ContextManager
  • Attach contexts to a message via ChatOptions.contexts (either full Context objects or context IDs)

Plugins

Plugins are a lightweight way to observe and customize runtime behavior without forking the agent. They can:

  • mutate input before a turn (beforeChat)
  • observe tool lifecycle events (onToolEvent)
  • observe per-turn usage metrics (onMetrics)
  • observe the final response (afterResponse)

Installation

npm install @aipexstudio/aipex-core
# or
pnpm add @aipexstudio/aipex-core

Optional peer dependencies (model providers)

@aipexstudio/aipex-core integrates well with the AI SDK ecosystem. Install the provider(s) you plan to use:

  • @ai-sdk/openai
  • @ai-sdk/google
  • @ai-sdk/anthropic
  • @openrouter/ai-sdk-provider

Usage

1) Basic streaming chat

import { google } from "@ai-sdk/google";
import { AIPex, aisdk } from "@aipexstudio/aipex-core";

const agent = AIPex.create({
  instructions: "You are a helpful assistant.",
  model: aisdk(google("gemini-2.5-flash")),
});

for await (const event of agent.chat("Say hello in one sentence.")) {
  if (event.type === "content_delta") process.stdout.write(event.delta);
}

2) Using built-in tools (calculatorTool, httpFetchTool)

import { google } from "@ai-sdk/google";
import { AIPex, aisdk, calculatorTool, httpFetchTool } from "@aipexstudio/aipex-core";

const agent = AIPex.create({
  instructions: "Use tools when appropriate.",
  model: aisdk(google("gemini-2.5-flash")),
  tools: [calculatorTool, httpFetchTool],
});

for await (const event of agent.chat("What is 15 * 234?")) {
  if (event.type === "content_delta") process.stdout.write(event.delta);
  if (event.type === "tool_call_start") {
    console.log("\n[tool_call_start]", event.toolName, event.params);
  }
  if (event.type === "tool_call_complete") {
    console.log("\n[tool_call_complete]", event.toolName, event.result);
  }
}

3) Define a custom tool (schema-first with Zod)

import { z } from "zod/v3";
import { tool } from "@aipexstudio/aipex-core";

export const weatherTool = tool({
  name: "get_weather",
  description: "Get the weather for a city (demo tool).",
  parameters: z.object({
    city: z.string().describe("The city name"),
  }),
  execute: async ({ city }) => {
    return `The weather in ${city} is sunny and 72°F`;
  },
});

4) Sessions: continue a conversation with sessionId

By default, each chat() call starts a new session. To continue a conversation, pass the sessionId returned in the session_created event:

import { google } from "@ai-sdk/google";
import { AIPex, aisdk } from "@aipexstudio/aipex-core";

const agent = AIPex.create({
  instructions: "You remember things within a session.",
  model: aisdk(google("gemini-2.5-flash")),
});

let sessionId: string | undefined;

for await (const event of agent.chat("My name is Alice.")) {
  if (event.type === "session_created") sessionId = event.sessionId;
}

if (sessionId) {
  for await (const event of agent.chat("What is my name?", { sessionId })) {
    if (event.type === "content_delta") process.stdout.write(event.delta);
  }
}

5) Conversation compression (summarize older turns)

import { google } from "@ai-sdk/google";
import { AIPex, aisdk } from "@aipexstudio/aipex-core";

const model = aisdk(google("gemini-2.5-flash"));

const agent = AIPex.create({
  instructions: "You are a helpful assistant.",
  model,
  compression: {
    model,
    summarizeAfterItems: 20,
    keepRecentItems: 10,
    maxSummaryLength: 500,
  },
});

6) Attaching contexts to a turn

import { google } from "@ai-sdk/google";
import { AIPex, aisdk, ContextManager, type Context } from "@aipexstudio/aipex-core";

const contextManager = new ContextManager();

const agent = AIPex.create({
  instructions: "Use attached contexts when answering.",
  model: aisdk(google("gemini-2.5-flash")),
  contextManager,
});

const pageContext: Context = {
  id: "page:example",
  type: "page",
  providerId: "manual",
  label: "Example page",
  value: "This page describes the AIPex Core API.",
  timestamp: Date.now(),
};

for await (const event of agent.chat("Summarize the page.", { contexts: [pageContext] })) {
  if (event.type === "content_delta") process.stdout.write(event.delta);
}

7) Plugins

import { google } from "@ai-sdk/google";
import { AIPex, aisdk, type AgentPlugin } from "@aipexstudio/aipex-core";

const loggerPlugin: AgentPlugin = {
  id: "logger",
  hooks: {
    beforeChat: (payload) => {
      console.log("[beforeChat]", payload.input);
      return payload;
    },
    onToolEvent: ({ event }) => {
      if (event.type === "tool_call_start") {
        console.log("[tool]", event.toolName, event.params);
      }
    },
  },
};

const agent = AIPex.create({
  instructions: "You are a helpful assistant.",
  model: aisdk(google("gemini-2.5-flash")),
  plugins: [loggerPlugin],
});

8) ToolRegistry (register and execute tools dynamically)

import { z } from "zod/v3";
import { ToolRegistry } from "@aipexstudio/aipex-core";

const registry = new ToolRegistry();

registry.register({
  name: "echo_tool",
  description: "Echo text back",
  schema: z.object({ text: z.string() }),
  handler: ({ text }) => `echo:${text}`,
});

const result = await registry.execute("echo_tool", { text: "hello" }, { sessionId: "s1" });
console.log(result); // "echo:hello"

API reference

AIPex

  • AIPex.create(options: AIPexOptions): AIPex
  • agent.chat(input: string, options?: ChatOptions): AsyncGenerator<AgentEvent>
  • agent.getConversationManager(): ConversationManager | undefined
  • agent.getContextManager(): ContextManager | undefined

ChatOptions

  • sessionId?: string - resume an existing session
  • contexts?: Context[] | string[] - attach contexts for this turn (IDs require contextManager)

AgentEvent (stream contract)

export type AgentEvent =
  | { type: "session_created"; sessionId: string }
  | { type: "session_resumed"; sessionId: string; itemCount: number }
  | { type: "content_delta"; delta: string }
  | { type: "tool_call_args_streaming_start"; toolName: string }
  | { type: "tool_call_args_streaming_complete"; toolName: string; params: unknown }
  | { type: "tool_call_start"; toolName: string; params: unknown }
  | { type: "tool_call_complete"; toolName: string; result: unknown }
  | { type: "tool_call_error"; toolName: string; error: Error }
  | { type: "contexts_attached"; contexts: Context[] }
  | { type: "contexts_loaded"; providerId: string; count: number }
  | { type: "context_error"; providerId: string; error: Error }
  | { type: "metrics_update"; metrics: AgentMetrics }
  | { type: "error"; error: AgentError }
  | { type: "execution_complete"; finalOutput: string; metrics: AgentMetrics };

AIPexOptions

Key fields:

  • instructions: string
  • model: AiSdkModel
  • tools?: FunctionTool[]
  • maxTurns?: number
  • conversation?: false (disable session management)
  • storage?: SessionStorageAdapter
  • compression?: { model: AiSdkModel; summarizeAfterItems?; keepRecentItems?; maxSummaryLength? }
  • conversationManager?: ConversationManager (advanced override)
  • contextManager?: ContextManager
  • plugins?: AgentPlugin[]

Conversations

  • ConversationManager: createSession, getSession, saveSession, deleteSession, listSessions, forkSession, compressSession, getSessionTree
  • Session: implements the OpenAI Agents Session interface and adds helpers like getItemCount, getSummary, fork, addMetrics, getSessionMetrics
  • SessionStorage: adapts a KeyValueStorage<SerializedSession> to a SessionStorageAdapter
  • ConversationCompressor: summarizes older turns and keeps the most recent items

Contexts

  • ContextManager: register/unregister providers, list/query contexts, fetch by ID, watch providers
  • ContextProvider: interface for pluggable context sources
  • Context: { id, type, providerId, label, value, metadata?, timestamp? }

Tools

  • tool(...): re-export from @openai/agents to define FunctionTools with a Zod parameters schema
  • ToolRegistry: registry for schema-first tools + execution + conversion to function tools
  • Built-ins: calculatorTool, httpFetchTool

Storage

  • KeyValueStorage<T>: save, load, delete, listAll, query, watch
  • InMemoryStorage<T>: reference implementation of KeyValueStorage

Development (monorepo)

From the repository root:

pnpm --filter @aipexstudio/aipex-core build
pnpm --filter @aipexstudio/aipex-core typecheck
pnpm --filter @aipexstudio/aipex-core test

Run the included examples:

pnpm --filter @aipexstudio/aipex-core example:basic
pnpm --filter @aipexstudio/aipex-core example:fork
pnpm --filter @aipexstudio/aipex-core example:metrics

License

MIT