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

@mp-lb/agents-framework

v0.6.0

Published

Langfuse-backed agent definitions, boot-time prompt caching, typed tools, and inspectable agent metadata.

Readme

@mp-lb/agents-framework

Backend-resolved agent definitions and runtimes for MAP Lab apps.

Code owns the agent contract: agent ids, instruction prompt keys, input prompt keys, required variables, tools, runtime context, and inspectable metadata. The configured backend owns prompt storage, LLM calls, tracing, and prompt/run metadata.

const agents = createAgentRuntime({
  app: "instantagent",
  environment: "local",
  backend: langfuseBackend({
    llm: openAICompatibleLlm({
      apiKey: process.env.OPENROUTER_API_KEY,
      baseUrl: "https://openrouter.ai/api/v1",
      model: "openai/gpt-5.5",
    }),
  }),
  agents: [conciergeAgent],
});

await agents.boot();

const result = await agents.run("concierge", {
  context: {
    PRODUCT_NAME: "InstantAgent",
    userMessage: "Can you check this lease?",
  },
});

Use prompt(...) for backend-resolved instruction and input templates:

export const conciergeAgent = defineAgent({
  id: "concierge",
  name: "Concierge",
  instructions: [
    prompt("instantagent/concierge-system", {
      variables: ["PRODUCT_NAME"],
    }),
  ],
  input: prompt("instantagent/concierge-input", {
    variables: ["userMessage"],
  }),
  tools: [lookupPolicy],
});

Tools

Use defineTool(...) for tools the model can call. A tool definition includes its Zod input schema and its executable handler, so the framework only advertises tools it knows how to run:

const lookupPolicy = defineTool({
  name: "lookup_policy",
  description: "Look up policy text by id",
  inputSchema: z.object({ id: z.string() }),
  describe: ({ input, output, phase }) => {
    if (phase === "started") return `Looking up policy ${input.id}`;
    if (phase === "failed") return `Could not look up policy ${input?.id}`;

    return `Found policy ${output.id}`;
  },
  handler: async (input, { context }) => {
    return policyStore.forTenant(String(context.tenantId)).lookup(input.id);
  },
});

Handlers receive schema-validated input. If model output does not match the schema, the framework emits a structured tool.failed event instead of passing raw JSON into application code.

If a tool is deliberately unavailable in a runtime path, make that explicit:

const fileDocument = defineTool({
  name: "file_doc",
  description: "File a generated document",
  inputSchema: z.object({ documentId: z.string() }),
  handler: notImplementedToolHandler("file_doc"),
});

ToolNotImplemented is treated like any other tool failure: it is emitted through onEvent and captured by tracing/error handling.

await agents.run("concierge", {
  context: { PRODUCT_NAME: "InstantAgent", tenantId: "tenant_1" },
  input: "Check this lease",
  onEvent: (event) => {
    agentTelemetry.record(event);
  },
});

The event stream includes tool.started, tool.succeeded, tool.failed, tool.missing_handler, model.retry, model.failure, agent.no_submit_tool_call, and agent.degraded_completion. Tool lifecycle events include event.narration, using the tool's deterministic describe callback when present and a generic fallback otherwise.

Use describe for UI progress copy that should not depend on model-generated text:

const requestSignature = defineTool({
  name: "request_signature",
  description: "Create and email a contract signing request.",
  inputSchema: z.object({
    contractId: z.string(),
    recipientEmail: z.email(),
  }),
  describe: ({ error, input, output, phase }) => {
    if (phase === "started") {
      return `Sending contract to ${input.recipientEmail}`;
    }

    if (phase === "failed") {
      return `Could not send contract to ${input?.recipientEmail}: ${String(error)}`;
    }

    return `Contract sent to ${output.recipientEmail ?? input.recipientEmail}`;
  },
  handler: async (input) => {
    return signatureService.request(input);
  },
});

Migrating Existing Tools

defineAgentTool(...) remains available for older call sites. During migration, you can either add handler/execute to the tool definition or keep passing a per-run toolHandlers map:

const lookupPolicy = defineAgentTool({
  name: "lookup_policy",
  description: "Look up policy text by id",
  inputSchema: z.object({ id: z.string() }),
});

await agents.run("concierge", {
  input: "Check this lease",
  toolHandlers: {
    lookup_policy: ({ toolCall, context }) => {
      const input = toolCall.input as { id: string };

      return policyStore.forTenant(String(context.tenantId)).lookup(input.id);
    },
  },
});

Before every model call, the framework validates that each advertised non-submit tool has either a definition-level handler or a legacy toolHandlers entry. Missing handlers emit tool.missing_handler and fail before the model sees the tool. Submit tools are framework-handled because their validated input is the agent's final result.