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

@maniac-ai/agents

v0.4.1

Published

TypeScript port of the Maniac agents SDK.

Readme

@maniac-ai/agents

TypeScript port of the Maniac agents SDK. As of 0.4.0, the TS port is at feature parity with the Python SDK on the inference, runtime, observability, dispatcher, and ACP-server surfaces — native AnthropicModel, MCPToolset, OTelTracer, BackgroundTaskDispatcher, parallel tool execution, budget enforcement, structured output with repair, multimodal Message.content, Anthropic prompt caching, partial-turn persistence on errored / interrupted runs, and the Agent Client Protocol server (with plan primitive, capability-gated builtin tools, and the maniac-agents-acp bin) all ship in the published tarball. 0.4.0 also adds the TypeScript-only @maniac-ai/agents/channels surface for serving a registered agent on Slack / Discord / Telegram / Microsoft Teams / WhatsApp. See docs/reference/typescript/divergences.md for the remaining intentional differences.

The package mirrors the Python SDK's durable JSON contracts while using TypeScript-native ergonomics for tools and model adapters. REPL execution remains Python-backed: PythonSandboxClient speaks the existing subprocess worker protocol so top-level await, persistent namespace state, stdout/stderr capture, and injected callable RPC preserve Python behavior.

Install

npm install @maniac-ai/agents

ESM-only. This package ships only the ECMAScript module entrypoint ("type": "module" with no require field in exports). Use it from ESM consumers (import { runAgent } from "@maniac-ai/agents"), from TypeScript with "module": "esnext" or "nodenext", or from CommonJS via the dynamic await import("@maniac-ai/agents") form. A direct require("@maniac-ai/agents") call is not supported; track the dual-package roadmap in the repository changelog.

For local development in this repository:

cd typescript/packages/agents
npm install
npm test

Quickstart

import { StaticModel, runAgent, tool } from "@maniac-ai/agents";

const lookup = tool({
  name: "lookup_order",
  description: "Look up an order by id.",
  inputSchema: {
    type: "object",
    properties: { order_id: { type: "string" } },
    required: ["order_id"]
  },
  handler: ({ order_id }) => ({ order_id, status: "in_transit" })
});

const model = new StaticModel([
  {
    content: "",
    usage: { prompt: 1, completion: 1 },
    finish_reason: "stop",
    tool_calls: [
      { id: "call_1", name: "lookup_order", arguments: { order_id: "ord_123" } }
    ]
  },
  {
    content: "Your order is in transit.",
    usage: { prompt: 1, completion: 4 },
    finish_reason: "stop",
    tool_calls: []
  }
]);

const result = await runAgent(
  { id: "support", instructions: "Use tools.", model, tools: [lookup] },
  "Where is my order?"
);

For a live OpenAI-compatible provider, use the bundled adapter:

import { OpenAICompatibleModel, runAgent } from "@maniac-ai/agents";

const model = new OpenAICompatibleModel({
  slug: "gpt-4o-mini"
});

const result = await runAgent(
  { id: "assistant", instructions: "Be concise.", model },
  "Summarize the release checks."
);

OpenAICompatibleModel reads OPENAI_API_KEY by default. OpenRouterModel is also exported and reads OPENROUTER_API_KEY. VercelGatewayModel targets the Vercel AI Gateway and reads AI_GATEWAY_API_KEY with a VERCEL_OIDC_TOKEN fallback.

Streaming Terminal Chat

For a minimal multi-turn terminal chat backed by a live provider:

cd typescript/packages/agents
OPENAI_API_KEY=... npm run example:chat

The chat uses OpenAICompatibleModel by default with OPENAI_MODEL falling back to gpt-4o-mini. Set OPENAI_BASE_URL for a local or proxy OpenAI-compatible endpoint.

To use OpenRouter instead:

cd typescript/packages/agents
AGENTS_PROVIDER=openrouter OPENROUTER_API_KEY=... npm run example:chat

OPENROUTER_MODEL defaults to openai/gpt-4o-mini. Pass --verbose or set AGENTS_CHAT_VERBOSE=1 to print per-turn token usage. The chat supports /help, /clear, /exit, and /quit; /clear resets the in-memory conversation history while the process keeps running.

To verify the CLI starts without making a provider call:

npm run example:chat -- --help

Subagent Stream Contract

Future subagent support should render nested model output inline in the same visible assistant turn. The terminal renderer should consume runAgentStream events in order and print text tokens where they arrive, including tokens from nested agents, so output continues under the same assistant > response block instead of jumping to a separate transcript.

Trace metadata such as depth, principal, span_id, and parent_span_id can route events internally and power verbose/debug annotations. Normal chat mode should keep the user-facing output visually continuous with the main answer, and should not buffer subagent text for replay later except for tiny terminal-smoothing chunks.

Persistent Memory

InMemoryMemory is the default Memory and lives entirely in process. For durable storage on a single host, the package ships a SQLite adapter built on Node's bundled node:sqlite module:

import { SqliteMemory } from "@maniac-ai/agents/memory/sqlite";
import { ConversationStore } from "@maniac-ai/agents/memory";

const memory = new SqliteMemory({ filename: "./agent.db" });
await memory.setup();

const conversations = new ConversationStore(memory);
await conversations.saveTurn("support", "thread-1", [
  { role: "user", content: "hi" }
]);

SqliteMemory adds zero npm dependencies and no native build step but requires Node >= 22.5.0 (use --experimental-sqlite on Node 22.x; unflagged from 23.5+). It implements both Memory and the optional MemorySequencer protocol, so it drops into ConversationStore, ObservationStore, RunCheckpointStore, and BackgroundTaskStore without further changes. See docs/sqlite-memory.md for the schema, setup() semantics, BYO DatabaseSync handle, and the "when to reach for Postgres instead" guidance.

Honcho memory (managed reasoning layer)

HonchoMemory opts into Honcho, a hosted reasoning layer that maintains per-peer representations server-side. Wiring it in swaps the default ConversationStore for HonchoConversationStore (loads the prefix via session.context({ tokens, peerTarget }).toOpenAI(...), mirrors writes via session.addMessages) and auto-injects the ask_about_user(query) LM tool that wraps the Dialectic API. @honcho-ai/sdk is an optional peer dependency loaded lazily.

import { HonchoMemory, Maniac } from "@maniac-ai/agents";

const memory = new HonchoMemory({
  apiKey: process.env.HONCHO_API_KEY!,
  environment: "production"
});
const app = new Maniac({ model, memory });
app.agent({ id: "support", instructions: "Help the user." });

await app.chat("support", "hi", { threadId: "thread-1", resourceId: "user-42" });

See the docs/how-to/use-honcho-memory.md recipe for the full surface (peer attribution, working-memory peer-card mirror, observational-memory advisory, demo vs production semantics).

Persistence on errored / interrupted turns

From v0.3 onwards, Maniac.chat / chatStream persist the partial transcript when a run finishes with status: "errored" (budget / output-validation / guardrail block) and when the runner aborts mid-turn by raising. RunCancelledError (caller AbortSignal fired) and RunInterruptedError (LM provider crash, sub-agent throw) both carry the in-flight transcript as error.partial; chat peels the wrapper, persists the new turn delta, and re-throws the original cause for non-cancel throws. (RunCancelledError continues to surface as an errored AgentResult from runAgent, just enriched with messages from the partial.)

Before writing, the persisted turn is sealed: every tool_call.id from the trailing assistant message that didn't get a tool reply gets a synthetic { ok: false, error: "tool call interrupted before completion" } observation. Without sealing, the next request would be rejected by every native tool-calling provider.

Reflectors (ObservationBuffer.afterTurn, WorkingMemoryRunner.afterTurn) still only run on completed turns. Set Maniac({ persistPartialOnError: false }) to opt out and restore the v0.2 "errored runs are not written" behaviour.

Python Worker

PythonSandboxClient starts python -u -m runtime.adapters._subprocess_worker. In this repository it auto-detects .venv/bin/python when available and prepends the repository root to PYTHONPATH.

In a packaged application, pass pythonExecutable and pythonPath if the worker module is shipped separately:

import { PythonSandboxClient } from "@maniac-ai/agents/runtime";

const sandbox = new PythonSandboxClient({
  pythonExecutable: "/path/to/python",
  pythonPath: ["/path/to/maniac-agents"]
});

For sidecar and process-image deployment notes, see docs/repl-python-worker.md.

Streaming Resume

Pause-then-resume runs (e.g. an approval-pending agent that the operator approved out of band) can now be streamed from the resume call:

import { runAgentResumeStream } from "@maniac-ai/agents";

for await (const env of runAgentResumeStream(spec, checkpoint, responses)) {
  if (env.type === "event") render(env.event);
  else handleResult(env.result);
}

runAgentResumeStream mirrors runAgentStream ergonomics (live StreamEnvelope events terminated by a single { type: "result" } envelope) and is also exposed as Maniac.resumeStream(...) on the app entrypoint.

Agent Client Protocol (ACP)

@maniac-ai/agents/acp exposes any registered Maniac agent over the Agent Client Protocol so editors (Zed, Neovim, Gemini CLI) can drive Maniac agents through the same JSON-RPC subprocess transport they already speak. Install the optional @agentclientprotocol/sdk peer dep, then:

import { Maniac } from "@maniac-ai/agents";
import { serveAcpStdio } from "@maniac-ai/agents/acp";

const app = new Maniac({ /* agents, model, conversationStore, ... */ });
await serveAcpStdio(app, "support");

The package also ships a maniac-agents-acp CLI bin (registered in package.json's bin field) that mirrors the Python maniac acp subcommand:

npx maniac-agents-acp serve <agent_id> --app ./path/to/app.js:app
npx maniac-agents-acp client ./external-acp-agent --prompt "hello"

Plan-aware agents (Agent.plans_enabled = true) auto-inject the LM-facing set_plan tool whose emissions surface as ACP session/update sessionUpdate=plan notifications. Capability-gated builtin tools (acp_read_text_file / acp_write_text_file / acp_run_command) auto-register onto the agent for the duration of every prompt turn whose ACP client advertised the matching capability.

See docs/reference/typescript/acp.md for the full reference and docs/concepts/acp.md for the cross-language design.

Trace Event Correlation IDs

Every trace event carries the standard envelope (run_id, event_id, seq, span_id, parent_span_id) and now optionally surfaces the following correlation IDs:

  • turn_id — UUID per LM iteration. Set on step, lm_call_start, token, lm_call, and downstream events emitted within the same iteration.
  • message_id — UUID for the assistant message produced by the LM iteration. Tokens that contributed to the message and the corresponding lm_call event share this ID.
  • block_id — UUID per contiguous run of the same chunk_kind on token events.
  • thread_id — Caller-scoped conversation thread, sourced from RunOptions.threadId and propagated through nested runs.

All four fields are optional; consumers that do not need them can safely ignore them. JSON Schema for the trace envelope is published at @maniac-ai/agents/trace-event.schema.json (also written to dist/trace-event.schema.json during the build).

Tool Result Previews

tool completed and failed events now include an optional result_preview describing the underlying ToolResult so trace consumers can render the value without a separate join. The preview is JSON-safe and capped at ~16 KB; oversized values are stringified and elided with result_truncated: true. The raw ToolResult continues to flow through messages unchanged.

Tool Argument Validation

When provider streams emit malformed tool-call arguments (incomplete JSON, non-object payloads, etc.), mergeStreamChunks and the OpenAI-compatible adapter no longer silently coerce to {}. The merged response carries arguments_error plus the raw provider text on the affected ToolCall, and the runner emits a structured tool failed event with reason: "tool_arguments_invalid" instead of invoking the handler with empty arguments.

Reasoning configuration

Reasoning-capable model families (OpenAI gpt-5 / o-series, Anthropic extended thinking, DeepSeek-R1, etc.) accept different parameter names on the wire. The SDK exposes a single normalized ReasoningConfig shape on both InferenceRequest.reasoning and Agent.reasoning, and the adapters translate it to the provider-native field:

| Field | OpenAI-compatible (OpenAICompatibleModel, OpenRouterModel) | Anthropic (AnthropicModel) | | --- | --- | --- | | effort: "minimal" \| "low" \| "medium" \| "high" | top-level reasoning_effort | mapped to thinking.budget_tokens (1024 / 4096 / 10000 / 24000) | | max_tokens: number | (ignored — Responses-API only) | thinking.budget_tokens (exact value) | | summary: "auto" \| "concise" \| "detailed" | (ignored — Responses-API only) | (no equivalent — ignored) |

Set it once on Agent to apply to every LM call the runner makes for that agent:

import { runAgent, OpenAICompatibleModel, AnthropicModel, type Agent } from "@maniac-ai/agents";

const spec: Agent = {
  id: "researcher",
  instructions: "Be thorough.",
  model: new OpenAICompatibleModel({ slug: "gpt-5", apiKey: process.env.OPENAI_API_KEY }),
  reasoning: { effort: "high" }
};

await runAgent(spec, "What are the second-order effects of...?");

When Anthropic enables extended thinking the adapter automatically bumps max_tokens above budget_tokens (Anthropic requires max_tokens > budget_tokens). A prepare_step hook can override the spec-level reasoning per turn by setting request.reasoning on the returned StepDecision; the runner does not merge the spec default on top of a hook-supplied request.

Adapters that don't recognize the field (e.g. older OpenAI chat models that reject reasoning_effort) surface the provider error verbatim; the SDK does not strip the field silently.

On the response side, OpenAICompatibleModel surfaces provider reasoning text from both wire variants:

  • message.reasoning / delta.reasoning — OpenRouter's normalized form, used by microsoft/mai-ds-r1, qwen/qwen3-235b-a22b, x-ai/grok-3-mini-beta, etc.
  • message.reasoning_content / delta.reasoning_content — DeepSeek-R1, vLLM, SGLang, Qwen native form.

It populates InferenceResponse.reasoning on infer() and emits StreamChunk(kind: "reasoning") deltas on stream(), so consumers see the reasoning channel on both paths regardless of which provider naming the upstream chose.

Feature surface (0.4.0)

  • Inference adapters: OpenAICompatibleModel, OpenRouterModel, VercelGatewayModel, native AnthropicModel (streaming, tool-use, extended-thinking reasoning chunks, prompt-cache passthrough), RetryingModel, FallbackModel, StaticModel. Implement Model directly to integrate any other provider.
  • Model discovery: adapters that can enumerate their catalog implement listModels() (feature-detect with supportsModelCatalog(model)), returning normalized ModelSpec[] (context_window, per-token ModelPricing, modalities, supported_parameters, and the verbatim provider entry). Adapters that cannot list throw ModelCatalogUnsupportedError.
  • Generation parameters: InferenceRequest accepts normalized OpenAI-compatible sampling knobs — top_p, top_k, frequency_penalty, presence_penalty, seed, logit_bias, parallel_tool_calls, and user. Each is omitted from the wire payload unless set; adapters translate or ignore per provider (e.g. Anthropic maps user to metadata.user_id).
  • Multimodal & prompt caching: Message.content accepts both string (back-compat) and ContentPart[] (text / image / file with optional cache_control: { type: "ephemeral" }). Anthropic forwards cache_control natively; OAI-compat adapters strip it with a one-time warning.
  • Toolsets: BaseToolset, StaticToolset, MCPToolset (under @maniac-ai/agents/tools/adapters; speaks stdio / sse / streamable_http). @modelcontextprotocol/sdk is an optional peer dep.
  • Compaction: LMSummarizingCompactor and the lower-level safeTailStart helper, both under @maniac-ai/agents/agents.
  • Memory: InMemoryMemory (default), plus SqliteMemory (@maniac-ai/agents/memory/sqlite, zero-dependency node:sqlite), VectorMemory (semantic-search wrapper with a default InMemoryVectorIndex), and HonchoMemory (@maniac-ai/agents/memory/honcho, hosted reasoning layer). Memory-backed ConversationStore, ObservationStore, RunCheckpointStore, BackgroundTaskStore, and WorkingMemoryStore all share the one Memory protocol.
  • Runtime: parallel tool execution, AgentBudget (max_tokens / max_cost_usd / max_wall_seconds) enforcement, structured output (Agent.output_model) with output_repair_attempts, reasoning stream chunk kind, paused/resume + checkpointing.
  • Background tasks: BackgroundTaskDispatcher with concurrency caps, lifecycle hooks, and Maniac.runUntilIdle / runStreamUntilIdle / enqueueBackground. Maniac.backgroundTasks is no longer @deprecated.
  • Observability: OTelTracer under @maniac-ai/agents/observability, mapping every TraceEvent to OTel spans following the GenAI semantic conventions. @opentelemetry/api and @opentelemetry/sdk-trace-base are optional peer deps.
  • Streaming: runAgentStream and runAgentResumeStream emit a tagged StreamEnvelope<T> ({ type: "event" } | { type: "result" }); cancellation via RunOptions.signal: AbortSignal.
  • Channels (TypeScript-only): @maniac-ai/agents/channels (serveChannels + ChatToolset + framework-agnostic webhook helpers) wraps Vercel's Chat SDK to serve a registered agent on Slack / Discord / Telegram / Microsoft Teams / WhatsApp, with structured multimodal inbound, multi-user attribution, signed-webhook + idempotency hardening, and approval-card round-trips through Maniac.resumeCheckpoint. Behind optional chat / @chat-adapter/* peers; Python parity is tracked as a divergence.
  • JSON Schema artifact: @maniac-ai/agents/trace-event.schema.json for non-TS consumers (Python validators, IDE tooling, fixture generators).