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

@papaya-ai/tracing

v0.1.1

Published

Papaya AI agent trace capture SDK for production apps.

Readme

Papaya AI SDK

Papaya is a TypeScript tracing SDK for production AI agents. It wraps your existing OpenAI, Anthropic/Claude, Gemini, Bedrock, Vercel AI SDK, or fetch calls without proxying them. It captures traces locally, redacts payloads by default, and sends them when you call flush().

Install

npm install @papaya-ai/tracing

Set a Papaya ingest token for your service:

PAPAYA_API_KEY=ppy_live_...

AI IDE Prompt

If you want your AI IDE to add tracing for you, paste this prompt:

Add the @papaya-ai/tracing SDK to my existing project so my LLM calls show up as
traces in Papaya. Keep the changes minimal. Do not refactor anything else.
Reference: https://github.com/Nile-AI-Inc/papaya-ai

1. Install:
   npm i @papaya-ai/tracing

2. Initialize once, in a shared module:

   import { Papaya } from "@papaya-ai/tracing";

   export const papaya = Papaya.init({
     apiKey: process.env.PAPAYA_API_KEY,
     project: "<my-project>",
   });

3. Apply one of these, matching how I call the model:

   A. If I use a provider SDK, wrap the client once and keep calling it as before:

      const openai = papaya.openai(new OpenAI());
      await openai.chat.completions.create({ ... });

      Use the matching wrapper if I use Anthropic/Claude, Bedrock, Gemini, or Vercel AI SDK.

   B. If I call the model over raw HTTP, swap fetch for wrapped fetch:

      const llmFetch = papaya.fetch(globalThis.fetch);
      await llmFetch(url, { method, headers, body, papaya: { provider, model } });

   C. If I use LangChain or LangGraph in TypeScript, use the callback handler:

      import { PapayaCallbackHandler } from "@papaya-ai/tracing/langchain";

      const callback = new PapayaCallbackHandler(papaya, { workflowKey, sessionId, userId });
      await agent.invoke(input, { callbacks: [callback] });

   D. If this is a Python app, use the Python SDK. For LangChain/LangGraph:

      pip install "papaya-ai[langchain]"

      import os
      from papaya_ai import Papaya
      from papaya_ai.integrations.langchain import PapayaCallbackHandler

      papaya = Papaya.init(api_key=os.environ["PAPAYA_API_KEY"], project="<my-project>")
      callback = PapayaCallbackHandler(papaya, workflow_key="<workflow>")
      result = agent.invoke(input, config={"callbacks": [callback]})

      For direct Python provider SDK calls, wrap the client once:

      openai = papaya.openai(OpenAI())

      Use one capture path for the same model call: callback handler for
      LangChain/LangGraph trees, provider wrapper for direct SDK calls.

4. Make sure traces are sent even when my code fails:

   try {
     // ... my model calls ...
   } finally {
     await papaya.flush();
   }

   In a long-running server, flush on an interval and once more on shutdown.

Find where I create my model client and where my request or job ends. Show me the
exact lines to add for init, the wrapper, and the try/finally flush. Leave the
rest of my code unchanged.

Quick Start

import OpenAI from "openai";
import { Papaya } from "@papaya-ai/tracing";

const papaya = Papaya.init({
  apiKey: process.env.PAPAYA_API_KEY!,
});

const openai = papaya.openai(new OpenAI());

await openai.chat.completions.create({
  model: "gpt-4.1-mini",
  messages,
});

await papaya.flush();

Fetch-Based Agent Loops

Use papaya.fetch() when your agent loop calls providers directly. The wrapper calls the provider URL with your original request, strips the Papaya-only papaya field before the provider sees it, records header names instead of header values, and preserves streaming responses.

import { Papaya, type PapayaFetchInit } from "@papaya-ai/tracing";

const papaya = Papaya.init({
  apiKey: process.env.PAPAYA_API_KEY!,
  project: "support-agent",
  environment: "production",
});

const llmFetch = papaya.fetch(globalThis.fetch, {
  workflowKey: "customer_support_agent",
});

await papaya.run({ sessionId, userId }, async () => {
  const response = await llmFetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      authorization: `Bearer ${process.env.OPENAI_API_KEY!}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-4.1-mini",
      stream: true,
      messages,
    }),
    papaya: {
      provider: "openai",
      model: "gpt-4.1-mini",
      spanName: "openai.chat",
      metadata: { route: "/api/agent/chat" },
    },
  } satisfies PapayaFetchInit);

  return response;
});

await papaya.flush();

Gemini REST calls work the same way:

await llmFetch("https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent", {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "x-goog-api-key": process.env.GEMINI_API_KEY!,
  },
  body: JSON.stringify({
    contents: [{ parts: [{ text: "Summarize this customer issue." }] }],
  }),
  papaya: {
    provider: "gemini",
    model: "gemini-flash-latest",
  },
} satisfies PapayaFetchInit);

SDK Wrappers

The package is intentionally provider-SDK-free. The SDK wraps clients by shape, so you do not need a Papaya-specific provider dependency.

const openai = papaya.openai(new OpenAI());
const anthropic = papaya.anthropic(new Anthropic());
const claude = papaya.claude(new Anthropic());
const gemini = papaya.gemini(genAI);
const bedrock = papaya.bedrock(bedrockRuntimeClient);
const vercel = papaya.vercel(aiSdkObject);

Pass run metadata either when you wrap the client or on a single provider call:

const openai = papaya.openai(new OpenAI(), {
  workflowKey: "claim_triage",
  metadata: { release: process.env.GIT_SHA },
});

await openai.chat.completions.create({
  model: "gpt-4.1-mini",
  messages,
  papaya: {
    sessionId,
    userId: customerUserId,
    metadata: { claimId },
  },
});

The papaya field is stripped before the provider SDK or REST endpoint receives the request.

TypeScript LangChain Callback Handler

For TypeScript LangChain or LangGraph apps, install the optional callback handler from the langchain entrypoint and pass it through the normal runnable config.

import { Papaya } from "@papaya-ai/tracing";
import { PapayaCallbackHandler } from "@papaya-ai/tracing/langchain";

const papaya = Papaya.init({ apiKey: process.env.PAPAYA_API_KEY, project: "support-agent" });
const callback = new PapayaCallbackHandler(papaya, {
  workflowKey: "support_agent",
  sessionId,
  userId,
});

try {
  const result = await agent.invoke(
    { messages: [{ role: "user", content: userMessage }] },
    { callbacks: [callback] },
  );
} finally {
  await papaya.flush();
}

See examples/langchain-callback.ts for a runnable local example with a real OpenAI-backed LangChain chat model.

Python LangChain Callback Handler

For LangChain or LangGraph apps, use the Python callback handler to capture the agent tree directly instead of wrapping a provider SDK call. The callback maps LangChain run_id / parent_run_id events into native Papaya spans, so chains, chat model calls, tools, and retrievers stay queryable as structured spans. It does not ship the conversation tree as a serialized JSON string.

import os

from papaya_ai import Papaya
from papaya_ai.integrations.langchain import PapayaCallbackHandler

papaya = Papaya.init(api_key=os.environ["PAPAYA_API_KEY"], project="support-agent")
callback = PapayaCallbackHandler(
    papaya,
    workflow_key="support_agent",
    session_id=session_id,
    user_id=user_id,
)

try:
    result = agent.invoke(
        {"messages": [{"role": "user", "content": user_message}]},
        config={"callbacks": [callback]},
    )
finally:
    papaya.flush()

Use one capture path for the same execution: callback handler for the LangChain/LangGraph tree, provider wrapper for direct SDK calls. Combining both around the same model call can duplicate LLM spans unless that is intentional. See examples/python-langchain-callback.py for a runnable local example.

Python Provider SDK Wrappers

The Python package also mirrors the TypeScript provider-wrapper model for direct SDK calls:

import os

from papaya_ai import Papaya

papaya = Papaya.init(api_key=os.environ["PAPAYA_API_KEY"], project="support-agent")
openai = papaya.openai(OpenAI())

try:
    with papaya.run({"workflowKey": "support_agent", "sessionId": session_id}):
        result = openai.chat.completions.create(
            model="gpt-4.1-mini",
            messages=[{"role": "user", "content": user_message}],
        )
finally:
    papaya.flush()

Convenience wrappers are available as papaya.openai(...), papaya.anthropic(...), papaya.claude(...), papaya.gemini(...), and papaya.bedrock(...). Use these for direct SDK calls; use the callback handler for LangChain/LangGraph run trees.

Workflow Boundaries

Papaya creates an implicit single-call run when no explicit run is active. Use papaya.run() when one business workflow spans several model calls, retries, retrievals, tools, guardrails, or provider SDKs.

await papaya.run({
  workflowKey: "refund_agent",
  workflowLabel: "Refund agent",
  sessionId,
  userId,
}, async () => {
  await openai.responses.create({ model: "gpt-4.1-mini", input });
  await llmFetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "anthropic-version": "2023-06-01",
      "x-api-key": process.env.ANTHROPIC_API_KEY!,
      "content-type": "application/json",
    },
    body: JSON.stringify({ model: "claude-3-5-sonnet-latest", messages }),
    papaya: { provider: "anthropic" },
  });
});

await papaya.flush();

Capture Modes

Configure capture with Papaya.init({ capture }).

  • metadata: records payload type and byte length only.
  • redacted: records payloads after local redaction. This is the default.
  • full: records payloads without local redaction. Use only when your Papaya token policy allows it.

Redaction runs locally before export. The hosted ingest API also enforces the token capture policy before raw trace landing.

Flush Behavior

The first package slice exports traces when you call await papaya.flush(). Provider calls are awaited normally, and Papaya export failures do not change provider results. When debug: true is enabled, export failures are logged to console.warn.

Typical server usage:

try {
  await handleAgentRequest();
} finally {
  await papaya.flush();
}

Configuration

const papaya = Papaya.init({
  apiKey: process.env.PAPAYA_API_KEY,
  endpoint: "https://papaya.fyi/api/v1/ingest/traces",
  project: "support-agent",
  environment: "production",
  serviceName: "agent-api",
  serviceVersion: process.env.GIT_SHA,
  capture: "redacted",
  debug: false,
});

apiKey defaults to PAPAYA_API_KEY and then PAPAYA_INGEST_TOKEN. endpoint defaults to https://papaya.fyi/api/v1/ingest/traces.

Safety Defaults

  • Capture defaults to redacted.
  • Redaction runs locally before export.
  • Provider API keys are not exported by the fetch wrapper; it records header names only.
  • SDK errors are swallowed unless debug: true is enabled.
  • Provider calls are awaited normally; Papaya export happens on flush().
  • Papaya-only call metadata is stripped before provider SDK and REST calls.
  • Streaming fetch responses are returned without reading the response body.
  • The hosted ingest API enforces capture policy again before raw landing.

Development

npm install
npm run typecheck
npm test
npm pack --dry-run

Before publishing, follow RELEASE.md.