@myappraise/sdk
v0.1.2
Published
Appraise SDK — AI-native memory and context layer for apps and agents
Maintainers
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/sdkQuick 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 promptsappraise.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 } | nullError 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
