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

@myappraise/sdk

v0.1.2

Published

Appraise SDK — AI-native memory and context layer for apps and agents

Readme

@myappraise/sdk

The official SDK for Appraise — AI-native memory and context layer for apps and agents.

Installation

npm i @myappraise/sdk
# or
yarn add @myappraise/sdk
# or
pnpm add @myappraise/sdk

Quick Start

import { Appraise } from '@myappraise/sdk';

const appraise = new Appraise({
  apiKey: 'appraise_sk_...',
  baseUrl: 'https://api.appraise.dev', // optional, defaults to this
});

// 1. Track product events as they happen
await appraise.track({
  sessionId: "customer_123",
  workflow: "customer_support",
  event: "order_delayed",
  externalId: "shopify-order-ORD-8842-delay-2",
  content: "Order ORD-8842 was delayed for the second time. Latest ETA is Friday.",
  metadata: {
    customerId: "customer_123",
    orderId: "ORD-8842",
    delayCount: 2,
    priority: "high"
  }
});

// 2. Get decision context — THE core API
const context = await appraise.context.get({
  sessionId: "customer_123",
  workflow: "customer_support",
  intent: "resolve_customer_issue"
});

console.log(context.urgencySignals);
// ["delivery_issue", "time_sensitive"]

console.log(context.suggestedActions);
// ["check_delivery_status", "escalate_support_ticket"]

// 3. Use in your LLM prompt
const promptContext = await appraise.context.getFormattedForPrompt({
  sessionId: "customer_123",
  workflow: "customer_support",
  intent: "resolve_customer_issue"
});

// Inject into OpenAI/Anthropic call
const response = await openai.chat.completions.create({
  messages: [
    { role: "system", content: "You are a customer support assistant." },
    { role: "user", content: `Context:
${promptContext}

Customer asks: Where is my order? This is getting annoying.` }
  ]
});

Customer Support Chatbot Example

import { Appraise } from '@myappraise/sdk';

const appraise = new Appraise({
  apiKey: process.env.APPRAISE_API_KEY!,
});

async function onSupportMessage(customerId: string, message: string) {
  const context = await appraise.context.getFormattedForPrompt({
    sessionId: customerId,
    workflow: 'customer_support',
    intent: 'resolve_customer_issue',
  });

  return llm.chat({
    system: 'You are a support chatbot. Use context when available.',
    user: `${context}\n\nCustomer message:\n${message}`,
  });
}

See examples/customer-support-chatbot.ts for a fuller integration snippet.

Real Support Agent Flow

Here is the practical loop for a product like QuickAI, a WhatsApp support agent for ecommerce businesses.

import { Appraise } from '@myappraise/sdk';

const appraise = new Appraise({
  apiKey: process.env.APPRAISE_API_KEY!,
  baseUrl: process.env.APPRAISE_API_URL,
});

const result = await appraise.chatbots.compare({
  type: 'customer_support',
  sessionId: 'quickai_whatsapp_customer_123_thread_8842',
  workflow: 'customer_support',
  message: 'Where is my order? I already asked yesterday.',
  intent: 'resolve_customer_issue',
  metadata: {
    customerId: 'customer_123',
    orderId: 'ORD-8842',
    channel: 'whatsapp',
    product: 'QuickAI',
  },
});

console.log(result.withAppraise.response);
console.log(result.withAppraise.usedMemories);
console.log(result.debug?.prompts.withAppraise);

This lets you:

  • store the new customer turn
  • retrieve Appraise context
  • compare a stateless response against a contextual one
  • inspect the exact prompt that the Appraise side used

See examples/quickai-whatsapp-support.ts for a fuller integration example.

Generic AI Application Flow

Appraise is not only for chatbots. Any AI application can track product events, retrieve context, and inject that context before reasoning.

import { Appraise } from '@myappraise/sdk';

const appraise = new Appraise({
  apiKey: process.env.APPRAISE_API_KEY!,
  baseUrl: process.env.APPRAISE_API_URL,
});

await appraise.track({
  sessionId: 'account_acme_123',
  workflow: 'account_review',
  event: 'user_message_received',
  content: 'Summarize the current blockers for this account.',
  metadata: {
    accountId: 'acme_123',
    surface: 'internal_ai_workspace',
  },
  createMemory: false,
});

const context = await appraise.context.get({
  sessionId: 'account_acme_123',
  workflow: 'account_review',
  intent: 'generate_next_best_response',
  query: 'Summarize the current blockers for this account.',
});

console.log(context.recentMemories);
console.log(context.suggestedActions);

See examples/ai-application-context-loop.ts for a fuller non-chatbot integration example.

Workspace-Aware Server Usage

If your server is proxying requests on behalf of a signed-in user, you can forward Appraise workspace headers once at client creation time.

const appraise = new Appraise({
  apiKey: process.env.APPRAISE_CONSOLE_API_KEY!,
  baseUrl: process.env.APPRAISE_API_URL,
  headers: {
    'X-Appraise-User-Id': user.id,
    'X-Appraise-User-Email': user.email,
    'X-Appraise-Organization-Id': activeWorkspaceId,
  },
});

This keeps the SDK pointed at the same workspace the user is currently working inside.

API Reference

Appraise — Main Class

const appraise = new Appraise({
  apiKey: string;           // Required. Your API key (appraise_sk_...)
  baseUrl?: string;         // Optional. Defaults to https://api.appraise.dev
  timeout?: number;         // Optional. Request timeout in ms. Default: 30000
  retries?: number;         // Optional. Retry attempts. Default: 3
  headers?: Record<string, string>; // Optional. Forward user/workspace headers from your server
});

appraise.memory — Memory Operations

appraise.track / appraise.events — Event Tracking

const event = await appraise.track({
  sessionId: string;        // Required. User/customer/session identifier
  event: string;            // Required. e.g. order_delayed
  workflow?: string;        // Optional. e.g. customer_support
  content?: string;         // Optional. Human-readable event memory
  externalId?: string;      // Optional. Idempotency key from your system
  entityIds?: string[];     // Optional. Link event to known entities
  metadata?: object;        // Optional. Structured event details
  importance?: number;      // Optional. 0-1
  occurredAt?: string;      // Optional. ISO date
  createMemory?: boolean;   // Optional. Default true
  memoryPolicy?: 'always' | 'never' | 'auto'; // Optional. Auto is useful for assistant replies
});
// Returns: { eventId, memoryId, deduplicated }

const events = await appraise.events.list({
  sessionId?: string;
  workflow?: string;
  limit?: number;
  offset?: number;
});
// Assistant replies can use auto memory policy so Appraise stores only durable turns.
await appraise.track({
  sessionId: 'chat_123',
  workflow: 'chat_app_memory',
  event: 'assistant_response_generated',
  content: assistantReply,
  metadata: {
    role: 'assistant',
    surface: 'web_chat',
  },
  createMemory: true,
  memoryPolicy: 'auto',
});
// Add memory (auto-extracts entities)
const result = await appraise.memory.add({
  content: string;          // Required. Raw memory text
  sessionId: string;        // Required. Session identifier
  workflow?: string;        // Optional. Workflow ID
  type?: MemoryType;        // Optional. conversation|action|observation|decision|...
  metadata?: object;        // Optional. Custom key-value data
  extractEntities?: boolean; // Optional. Auto-extract entities. Default: true
});
// Returns: { memoryId, extractedEntities[], summary, urgencySignals[], confidence }

// Get memory by ID
const memory = await appraise.memory.get("mem_abc123");

// Search memories
const results = await appraise.memory.search({
  query: string;            // Required. Search query
  workflow?: string;        // Optional. Filter by workflow
  type?: MemoryType;        // Optional. Filter by type
  tags?: string[];          // Optional. Filter by tags
  semanticSearch?: boolean; // Optional. Use vector similarity. Default: true
  limit?: number;           // Optional. Max results. Default: 20
});

// List memories
const list = await appraise.memory.list({
  sessionId?: string;
  workflow?: string;
  limit?: number;
  offset?: number;
});

// Feedback — reinforce or demote a memory
await appraise.memory.feedback("mem_abc123", {
  action: "promote" | "demote" | "neutral",
  reason?: string;
});

appraise.chatbots — Real Chatbot Flow

const reply = await appraise.chatbots.respond({
  type: 'customer_support',
  sessionId: 'customer_123',
  workflow: 'customer_support',
  message: 'Where is my order?',
  intent: 'resolve_customer_issue',
});

const comparison = await appraise.chatbots.compare({
  type: 'customer_support',
  sessionId: 'customer_123',
  workflow: 'customer_support',
  message: 'Where is my order?',
  intent: 'resolve_customer_issue',
});

console.log(comparison.withAppraise.response);
console.log(comparison.debug?.prompts.withAppraise);

appraise.context — Context Retrieval (The Magic)

// Get decision-relevant context
const context = await appraise.context.get({
  sessionId: string;        // Required. Session identifier
  workflow?: string;        // Optional. Workflow ID for relevance boost
  intent?: string;          // Optional. What are you trying to do?
  currentStage?: string;    // Optional. Current workflow stage
  query?: string;           // Optional. Additional query for semantic search
  entityIds?: string[];     // Optional. Explicitly include these entities
  maxMemories?: number;     // Optional. Max memories to return. Default: 10
  maxEntities?: number;     // Optional. Max entities to return. Default: 5
});
// Returns: {
//   sessionId,
//   activeEntities[],       // Ranked by decision relevance
//   recentMemories[],       // Ranked by decision relevance
//   inferredGoals[],        // Extracted goals from context
//   urgencySignals[],       // Time-sensitive items
//   suggestedActions[],     // Recommended next actions
//   workflowContext?,       // Current stage, blockers, next action
//   relevanceScores{}       // Score per memory
// }

// Get formatted context for LLM prompt injection
const promptText = await appraise.context.getFormattedForPrompt({
  sessionId: "interview-sarah-001",
  intent: "prepare_follow_up_email"
});
// Returns a structured markdown string ready to prepend to prompts

appraise.entities — Structured Memory

// Get entity by ID (with related memories and workflows)
const entity = await appraise.entities.get("ent_sarah_123");

// Search entities
const results = await appraise.entities.search({
  q: string;                // Required. Search query
  type?: EntityType;        // Optional. Filter by type
  limit?: number;          // Optional. Max results
});

// List entities
const list = await appraise.entities.list({
  type?: EntityType;
  status?: "active" | "decaying" | "archived";
  limit?: number;
  offset?: number;
});

// Update entity
await appraise.entities.update("ent_sarah_123", {
  importance?: number;      // 0-1
  status?: "active" | "decaying" | "archived";
  attributes?: object;      // Merge with existing
  relatedEntities?: string[]; // Add relationships
});

// Promote entity (increase importance)
await appraise.entities.promote("ent_sarah_123", 0.3);

// Extract entities from raw text (without storing memory)
const extraction = await appraise.entities.extract("Sarah Chen is a backend engineer...");

appraise.workflows — Workflow Management

// Create workflow
const workflow = await appraise.workflows.create({
  name: string;
  description?: string;
  stages?: string[];        // e.g., ["sourced", "screening", "interview", "offer"]
  activeStage?: string;
  priority?: number;        // 0-1
  config?: object;
});

// Get workflow with nodes
const wf = await appraise.workflows.get("wf_recruiting_001");

// List workflows
const list = await appraise.workflows.list({ active?: boolean });

// Update workflow
await appraise.workflows.update("wf_recruiting_001", {
  activeStage?: string;
  priority?: number;
  active?: boolean;
});

// Add node to pipeline builder
const node = await appraise.workflows.addNode("wf_recruiting_001", {
  type: "Input" | "MemoryRetrieval" | "Reasoning" | "ContextInjection" | "Action" | "FeedbackLoop" | "Condition" | "Output";
  label: string;
  positionX?: number;
  positionY?: number;
  config?: object;
  connections?: string[];   // Node IDs to connect to
});

// Connect nodes
await appraise.workflows.connectNodes("wf_recruiting_001", "node_1", "node_2", "condition");

// Get workflow-aware context
const context = await appraise.workflows.getContext("wf_recruiting_001", "session_001", "prepare_email");

appraise.decisions — Decision Support

// Rank candidates for a decision
const ranked = await appraise.decisions.rank({
  for: string;              // Required. Decision description
  candidates: string[];     // Required. Entity IDs to compare
  criteria: string[];       // Required. e.g., ["salary_fit", "timeline", "competition"]
  workflow?: string;        // Optional. Workflow context
  context?: object;          // Optional. Additional context
});
// Returns: {
//   rankings: [{ entityId, score, breakdown, reasoning, entity, recentMemories[] }],
//   topRecommendation: string
// }

// Compare side-by-side
const comparison = await appraise.decisions.compare({
  entityIds: string[];
  criteria?: string[];
  decision?: string;
});

// Get top recommendation
const recommendation = await appraise.decisions.recommend(
  "should_we_extend_offer",
  ["sarah-123", "mike-456"],
  ["salary_fit", "timeline", "competition"]
);
// Returns: { entityId, name, reasoning } | null

Error Handling

import { AppraiseError } from '@myappraise/sdk';

try {
  await appraise.memory.add({ ... });
} catch (error) {
  if (error instanceof AppraiseError) {
    console.log(error.code);      // e.g., "VALIDATION_ERROR"
    console.log(error.statusCode); // e.g., 400
    console.log(error.details);    // Additional error info
  }
}

Types

import { 
  MemoryType, 
  EntityType, 
  WorkflowNodeType,
  ContextWindow,
  DecisionRankResult 
} from '@myappraise/sdk';

License

MIT © Appraise Team