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

@looopy-ai/core

v3.1.2

Published

RxJS-based AI agent framework

Readme

@looopy-ai/core

RxJS-based AI agent framework with multi-turn conversation management, streaming LLM integration, tool execution, and pluggable storage.

Installation

pnpm add @looopy-ai/core

Quick Start

import {
  Agent,
  InMemoryMessageStore,
  LiteLLMProvider,
  literalPrompt,
  localTools,
  tool,
} from '@looopy-ai/core';
import { z } from 'zod';

const llmProvider = new LiteLLMProvider({
  baseUrl: 'http://localhost:4000',
  model: 'gpt-4o-mini',
});

const agent = new Agent({
  agentId: 'my-agent',
  contextId: 'session-1',
  llmProvider,
  messageStore: new InMemoryMessageStore(),
  plugins: [
    literalPrompt('You are a helpful assistant.'),
    localTools([
      tool({
        id: 'echo',
        description: 'Echo text back',
        schema: z.object({ text: z.string() }),
        handler: ({ text }) => ({ success: true, result: text }),
      }),
    ]),
  ],
});

const events$ = await agent.startTurn('Hello!');
events$.subscribe({
  next: (event) => console.log(event),
  complete: () => console.log('Done'),
});

Core API

Agent

Stateful multi-turn conversation manager. Handles message persistence, turn lifecycle, pause/resume, and graceful shutdown.

const agent = new Agent<AuthContext>({
  agentId: string;
  contextId: string;
  llmProvider: LLMProvider;
  messageStore: MessageStore;
  agentStore?: AgentStore;         // persists AgentState across restarts
  plugins?: Plugin<AuthContext>[];
  autoCompact?: boolean;           // auto-summarize when message limit reached
  maxMessages?: number;
  logger?: pino.Logger;
});

// Start a turn (returns Observable<AgentEvent>)
const events$ = await agent.startTurn('User message');

// Resume after a tool-input-required pause
const events$ = await agent.startTurn('User message', {
  resolvedInputs: new Map([['toolCallId', 'user-supplied-value']]),
});

// Inspect state
agent.state; // AgentState { status, turnCount, lastActivity, ... }

// Graceful shutdown
await agent.shutdown();

AgentState statuses: created | idle | busy | waiting-input | shutdown | error

runLoop

Stateless single-turn execution. Use directly when you don't need session management.

import { runLoop } from '@looopy-ai/core';

const events$ = runLoop(context, { llmProvider }, messages);

LLM Providers

LiteLLMProvider

Connects to a LiteLLM proxy, giving access to 100+ model providers.

const llmProvider = new LiteLLMProvider({
  baseUrl: 'http://localhost:4000',
  model: 'gpt-4o-mini',         // or bedrock/..., claude-3-opus, etc.
  apiKey: process.env.API_KEY,  // optional
  maxTokens: 4096,
  logDir: './logs',             // optional JSONL request log
});

Plugins

Plugins attach behaviour to the agent loop: system prompts, tool sets, skills, and input handling.

System Prompts

import { literalPrompt, asyncPrompt } from '@looopy-ai/core';

// Static string
literalPrompt('You are a helpful assistant.')

// Dynamic — loaded async per turn
asyncPrompt(async ({ authContext }) => `Hello ${authContext.userId}`)

Local Tools

import { localTools, tool, inputRequired } from '@looopy-ai/core';
import { z } from 'zod';

localTools([
  tool({
    id: 'search',
    description: 'Search the web',
    schema: z.object({ query: z.string() }),
    handler: async ({ query }, context) => {
      // Pause and ask for an API key if not yet resolved
      const apiKey = context.resolvedInputs?.get(context.toolCallId);
      if (!apiKey) {
        return inputRequired({ prompt: 'Please provide your search API key' });
      }
      const results = await searchWeb(query, apiKey);
      return { success: true, result: results };
    },
  }),
])

inputRequired() pauses the loop with status waiting-input. Resume by passing resolvedInputs to the next startTurn call.

MCP Tools

Connect to any Model Context Protocol server:

import { mcp } from '@looopy-ai/core';

const mcpTools = mcp({
  serverId: 'filesystem',
  serverUrl: 'http://localhost:8080',
  getHeaders: () => ({ Authorization: `Bearer ${token}` }),
});

Agent-as-Tool (A2A)

Call another Looopy agent as a tool via its HTTP endpoint:

import { AgentToolProvider } from '@looopy-ai/core';

const subAgent = await AgentToolProvider.fromUrl('http://localhost:3001/card.json');
// or
const subAgent = AgentToolProvider.from(agentCard, getHeaders);

Artifact Tools

Give the agent built-in tools to create and manage file, data, and dataset artifacts:

import { createArtifactTools } from '@looopy-ai/core';

const artifactTools = createArtifactTools(artifactStore, taskStateStore);

Tools provided: create_file_artifact, append_file_artifact, create_data_artifact, create_dataset_artifact, append_dataset_rows, list_artifacts.

LLM-Initiated Input Requests

Let the LLM itself ask for clarification mid-loop:

import { requestInputPlugin } from '@looopy-ai/core';

plugins: [requestInputPlugin()]

The LLM can call the built-in request_input tool, which pauses the loop with a tool-input-required event. On resume, a synthetic tool-complete is injected so the LLM sees the answer.

Agent Academy (Skills)

Teach the agent new skills dynamically:

import { agentAcademy, skill } from '@looopy-ai/core';

agentAcademy([
  skill({
    name: 'diagramming',
    description: 'Create Mermaid diagrams',
    instruction: 'Use mermaid syntax wrapped in ```mermaid blocks.',
  }),
])

The agent can activate skills at runtime using the built-in learn_skill tool.

Stores

Message Stores

| Class | Use case | |---|---| | InMemoryMessageStore | Development and testing | | FileSystemMessageStore | Local persistence | | HybridMessageStore | Combines two stores (e.g., in-memory + filesystem) | | Mem0MessageStore | Mem0 memory service |

import { InMemoryMessageStore, FileSystemMessageStore } from '@looopy-ai/core';

new InMemoryMessageStore()
new FileSystemMessageStore({ basePath: './_agent_store', agentId: 'my-agent' })

Agent Stores (state persistence)

| Class | Use case | |---|---| | InMemoryAgentStore | Development and testing | | FileSystemAgentStore | Local persistence |

Artifact Stores

| Class | Use case | |---|---| | MemoryArtifactStore | Development and testing | | FileSystemArtifactStore | Local persistence |

Task State Store

| Class | Use case | |---|---| | InMemoryStateStore | Development and testing | | FileSystemStateStore | Local persistence |

Context Store

FileSystemContextStore manages session metadata (title, tags, lifecycle, locking) for multi-tenant or multi-session deployments.

SSE Server

Stream agent events to HTTP clients via Server-Sent Events:

import { SSEServer, SSEConnection } from '@looopy-ai/core';

const sseServer = new SSEServer();

// Pipe agent events into the server
events$.subscribe((event) => sseServer.publish(event));

// Subscribe a client (framework-agnostic)
const connection = new SSEConnection({
  subscription: { contextId: 'session-1' },
  response: res, // Node HTTP response or similar
});
sseServer.subscribe(connection);

Secure Credential Handoff (Auth)

Utilities for encrypting credentials between agents and clients using ECDH-ES JWE and OAuth 2.0 PKCE. No raw secrets cross event/log boundaries.

import { generateECDHKeyPair, generatePKCEPair, encryptCredential, decryptCredential } from '@looopy-ai/core';

// Agent side — generate keys, emit auth-required event
const { publicKey, privateKeyPem, keyId } = generateECDHKeyPair();
const { codeChallenge, codeVerifier } = generatePKCEPair();

// Client side — encrypt the credential
const jwe = await encryptCredential(userSecret, publicKey, claims);

// Agent side — decrypt on receipt
const credential = await decryptCredential(jwe, privateKeyPem, { authId, contextId });

Supported flows: oauth2 (PKCE), api-key, pat, password, custom.

Observability

OpenTelemetry tracing is built in. Enable via environment variables:

OTEL_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

Spans are created for agent turns, loop iterations, LLM calls, and tool executions.

Event Stream

Every agent.startTurn() returns an Observable<AgentEvent>. Key event kinds:

| Kind | Description | |---|---| | task-created | New task started | | task-status | Status update (working, waiting-input, etc.) | | content-delta | Streaming text chunk | | content-complete | Full content block finalized | | thought-stream | Internal reasoning/thought | | tool-start | Tool call beginning | | tool-complete | Tool call result | | tool-input-required | Loop paused — needs upstream input | | task-complete | Turn finished | | llm-usage | Token usage stats |

Development

pnpm build          # Compile TypeScript
pnpm check:types    # Type check without emit
pnpm test           # Run test suite (Vitest)
pnpm lint           # Biome lint