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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@skald-labs/skald-node

v0.4.0

Published

Node.js client library for the Skald API

Readme

Skald Node SDK

Node.js client library for the Skald API.

Please note that Skald is evolving fast and we may ship breaking changes across minor versions.

Installation

npm install @skald-labs/skald-node

Requirements

  • Node 18.0.0 or higher

Usage

Initialize the client

import { Skald } from '@skald-labs/skald-node';

const skald = new Skald('your-api-key-here');

Memo Management

Create a Memo

Create a new memo that will be automatically processed (summarized, tagged, chunked, and indexed for search):

const result = await skald.createMemo({
  title: 'Meeting Notes',
  content: 'Full content of the memo...',
  metadata: {
    type: 'notes',
    author: 'John Doe'
  },
  reference_id: 'external-id-123',
  tags: ['meeting', 'q1'],
  source: 'notion',
  expiration_date: '2024-12-31T23:59:59Z'
});

console.log(result); // { memo_uuid: '550e8400-e29b-41d4-a716-446655440000' }

Required Fields:

  • title (string, max 255 chars) - The title of the memo
  • content (string) - The full content of the memo

Optional Fields:

  • project_id (string) - Project UUID (required when using Token Authentication)
  • metadata (object) - Custom JSON metadata
  • reference_id (string, max 255 chars) - An ID from your side that you can use to match Skald memo UUIDs with e.g. documents on your end
  • tags (array of strings) - Tags for categorization
  • source (string, max 255 chars) - An indication from your side of the source of this content, useful when building integrations
  • expiration_date (string) - ISO 8601 timestamp for automatic memo expiration

Create a Memo from File Upload

Upload a document file (PDF, DOC, DOCX, PPTX) that will be processed asynchronously and converted into a memo:

import * as fs from 'fs';

const fileBuffer = fs.readFileSync('./document.pdf');

const result = await skald.createMemoFromFile({
  file: fileBuffer,
  filename: 'document.pdf',
  metadata: {
    type: 'report',
    department: 'engineering'
  },
  tags: ['report', '2024'],
  source: 'google-drive',
  reference_id: 'external-file-123'
});

console.log(result); // { ok: true, memo_uuid: '550e8400-e29b-41d4-a716-446655440000' }

// Poll for processing status
const status = await skald.checkMemoStatus({ memoId: result.memo_uuid });
console.log(status.status); // 'processing' | 'processed' | 'error'

Supported File Types:

  • PDF (.pdf)
  • Microsoft Word (.doc, .docx)
  • Microsoft PowerPoint (.pptx)
  • Maximum file size: 100MB

Required Fields:

  • file (Buffer | Blob) - The file content
  • filename (string) - The name of the file including extension

Optional Fields:

  • reference_id (string, max 255 chars) - Your external reference ID
  • metadata (object) - Custom JSON metadata
  • tags (array of strings) - Tags for categorization
  • source (string, max 255 chars) - Source system identifier

Note: File processing is asynchronous. Use checkMemoStatus() to monitor the processing status.

Check Memo Processing Status

Monitor the processing status of a memo, especially useful after uploading files:

// Check status by UUID
const status = await skald.checkMemoStatus({ memoId: '550e8400-e29b-41d4-a716-446655440000' });
console.log(status.status); // 'processing' | 'processed' | 'error'

if (status.status === 'error') {
  console.error('Processing failed:', status.error_reason);
}

// Check by reference ID
const status2 = await skald.checkMemoStatus({ memoId: 'external-id-123', idType: 'reference_id' });

// Poll until processing completes
while (true) {
  const status = await skald.checkMemoStatus({ memoId: memoUuid });

  if (status.status === 'processed') {
    console.log('Processing complete!');
    break;
  } else if (status.status === 'error') {
    console.error('Processing failed:', status.error_reason);
    break;
  }

  // Wait 2 seconds before checking again
  await new Promise(resolve => setTimeout(resolve, 2000));
}

Status Values:

  • processing - The memo is currently being processed (parsed, summarized, chunked, indexed)
  • processed - Processing completed successfully, memo is ready to use
  • error - An error occurred during processing, check error_reason for details

Parameters: Takes a request object with the following properties:

  • memoId (string, required) - The memo UUID or client reference ID
  • idType (string, optional) - Either 'memo_uuid' or 'reference_id' (default: 'memo_uuid')

Get a Memo

Retrieve a memo by its UUID or your reference ID:

// Get by UUID
const memo = await skald.getMemo({ memoId: '550e8400-e29b-41d4-a716-446655440000' });

// Get by reference ID
const memo = await skald.getMemo({ memoId: 'external-id-123', idType: 'reference_id' });

console.log(memo.title);
console.log(memo.content);
console.log(memo.summary);
console.log(memo.tags);
console.log(memo.chunks);

The getMemo() method returns complete memo details including content, AI-generated summary, tags, and content chunks.

List Memos

List all memos with pagination:

// Get first page with default page size (20)
const memos = await skald.listMemos();

// Get specific page with custom page size
const memos = await skald.listMemos({ page: 2, page_size: 50 });

console.log(`Total memos: ${memos.count}`);
console.log(`Results: ${memos.results.length}`);
console.log(`Next page: ${memos.next}`);

Parameters:

  • page (number, optional) - Page number (default: 1)
  • page_size (number, optional) - Results per page (default: 20, max: 100)

Update a Memo

Update an existing memo by UUID or reference ID:

// Update by UUID
await skald.updateMemo({
  memoId: '550e8400-e29b-41d4-a716-446655440000',
  updateData: {
    title: 'Updated Title',
    metadata: { status: 'reviewed' }
  }
});

// Update by reference ID and trigger reprocessing
await skald.updateMemo({
  memoId: 'external-id-123',
  updateData: {
    content: 'New content that will be reprocessed'
  },
  idType: 'reference_id'
});

Note: When you update the content field, the memo will be automatically reprocessed (summary, tags, and chunks regenerated).

Updatable Fields:

  • title (string)
  • content (string)
  • metadata (object)
  • client_reference_id (string)
  • source (string)
  • expiration_date (string)

Delete a Memo

Permanently delete a memo and all associated data:

// Delete by UUID
await skald.deleteMemo({ memoId: '550e8400-e29b-41d4-a716-446655440000' });

// Delete by reference ID
await skald.deleteMemo({ memoId: 'external-id-123', idType: 'reference_id' });

Warning: This operation permanently deletes the memo and all related data (content, summary, tags, chunks) and cannot be undone.

Search Memos

Search through your memos using semantic search. Returns :

// Basic semantic search
const results = await skald.search({
  query: 'quarterly goals',
  limit: 10
});

// Search with filters
const filtered = await skald.search({
  query: 'python tutorial',
  filters: [
    {
      field: 'source',
      operator: 'eq',
      value: 'notion',
      filter_type: 'native_field'
    },
    {
      field: 'level',
      operator: 'eq',
      value: 'beginner',
      filter_type: 'custom_metadata'
    }
  ]
});

console.log(`Found ${filtered.results.length} results`);
filtered.results.forEach(memo => {
  console.log(`- ${memo.title} (distance: ${memo.distance})`);
});

Search Parameters

  • query (string, required) - The search query
  • limit (integer, optional) - Maximum results to return (1-50, default 10)
  • filters (array, optional) - Array of filter objects to narrow results (see Filters section below)

Search Response

interface SearchResponse {
  results: Array<{
    memo_uuid: string;
    chunk_uuid: string;
    memo_title: string;
    memo_summary: string;
    content_snippet: string;
    distance: number | null;
  }>;
}
  • memo_uuid - Unique identifier for the memo
  • memo_uuid - Unique identifier for the chunk
  • memo_title - Memo title
  • memo_summary - Auto-generated summary for the memo
  • content_snippet - A snippet containing the beginning of the chunk content.
  • distance - A decimal from 0 to 2 determining how close the result was deemed to be to the query when using semantic search (chunk_vector_search). The closer to 0 the more related the content is to the query. null if using title_contains or title_startswith.

Chat with Your Knowledge Base

Ask questions about your memos using an AI agent. The agent retrieves relevant context and generates answers with inline citations.

Non-Streaming Chat

const result = await skald.chat({
  query: 'What were the main points discussed in the Q1 meeting?'
});

console.log(result.response);
// "The main points discussed in the Q1 meeting were:
// 1. Revenue targets [[1]]
// 2. Hiring plans [[2]]
// 3. Product roadmap [[1]][[3]]"

console.log(result.ok); // true
console.log(result.chat_id); // '550e8400-e29b-41d4-a716-446655440000'

// Continue the conversation by passing the chat_id
const followUp = await skald.chat({
  query: 'What were the revenue targets?',
  chat_id: result.chat_id  // Maintains conversation context
});

console.log(followUp.response);
// "Based on the Q1 meeting notes, the revenue targets were... [[1]]"

Streaming Chat

For real-time responses, use streaming chat:

let chatId;

const stream = skald.streamedChat({
  query: 'What are our quarterly goals?'
});

for await (const event of stream) {
  if (event.type === 'token') {
    // Write each token as it arrives
    process.stdout.write(event.content);
  } else if (event.type === 'done') {
    // Capture the chat_id for continuing the conversation
    chatId = event.chat_id;
    console.log('\nDone!');
  }
}

// Continue the conversation with the captured chat_id
const followUpStream = skald.streamedChat({
  query: 'Can you elaborate on the first goal?',
  chat_id: chatId  // Maintains conversation context
});

for await (const event of followUpStream) {
  if (event.type === 'token') {
    process.stdout.write(event.content);
  } else if (event.type === 'done') {
    console.log('\nDone!');
  }
}

Chat Parameters

  • query (string, required) - The question to ask
  • chat_id (string, optional) - Chat ID to continue an existing conversation. When provided, the AI will have context from previous messages in the same conversation
  • system_prompt (string, optional) - A system prompt to guide the AI's behavior
  • filters (array, optional) - Array of filter objects to focus chat context on specific sources (see Filters section below)
  • rag_config (object, optional) - Advanced RAG (Retrieval-Augmented Generation) configuration to customize the search and retrieval behavior (see RAG Configuration section below)
  • project_id (string, optional) - Project UUID (required when using Token Authentication)

Chat Response

Non-Streaming Response:

Non-streaming responses include:

  • ok (boolean) - Success status
  • response (string) - The AI's answer with inline citations in format [[N]] (e.g., [[1]], [[2]])
  • chat_id (string) - Unique identifier for this conversation. Use this to continue the conversation with follow-up questions
  • intermediate_steps (array) - Steps taken by the agent (for debugging)
  • references (object, optional) - Mapping of citation numbers to memo information (only included when rag_config.references.enabled is true)

Streaming Response:

Streaming responses yield events:

  • { type: 'token', content: string } - Each text token as it's generated
  • { type: 'references', content: string } - JSON string containing the references object (only sent when rag_config.references.enabled is true)
  • { type: 'done', chat_id: string } - Indicates the stream has finished and includes the chat_id for continuing the conversation

Understanding References

When you enable references in your RAG config (rag_config.references.enabled: true), the chat response will include inline citations and a references object that maps citation numbers to the source memos.

Citation Format:

The AI's response will include citations in the format [[N]] where N is a number (e.g., [[1]], [[2]], [[3]]). These citations appear inline in the response text to indicate which source memos support specific statements.

References Object Structure:

interface References {
  [key: string]: {
    memo_uuid: string;    // UUID of the referenced memo
    memo_title: string;   // Title of the referenced memo
  };
}

Non-Streaming Example with References:

const result = await skald.chat({
  query: 'What is the main topic discussed in the documentation?',
  rag_config: {
    references: {
      enabled: true
    }
  }
});

console.log(result.response);
// "Based on the documentation, the main topic is about API authentication 
// and authorization. The system uses API keys for authentication [[1]], 
// and supports role-based access control [[2]]. For more details on 
// implementation, see the security guide [[3]]."

console.log(result.references);
// {
//   "1": {
//     "memo_uuid": "123e4567-e89b-12d3-a456-426614174000",
//     "memo_title": "API Authentication Guide"
//   },
//   "2": {
//     "memo_uuid": "223e4567-e89b-12d3-a456-426614174001",
//     "memo_title": "Role-Based Access Control"
//   },
//   "3": {
//     "memo_uuid": "323e4567-e89b-12d3-a456-426614174002",
//     "memo_title": "Security Best Practices"
//   }
// }

Streaming Example with References:

let fullResponse = '';
let references = {};

const stream = skald.streamedChat({
  query: 'What are our security best practices?',
  rag_config: {
    references: {
      enabled: true
    }
  }
});

for await (const event of stream) {
  if (event.type === 'token') {
    // Accumulate response text with citations
    fullResponse += event.content;
    process.stdout.write(event.content);
  } else if (event.type === 'references') {
    // Parse references object
    references = JSON.parse(event.content);
    console.log('\nReferences:', references);
  } else if (event.type === 'done') {
    console.log('\nChat ID:', event.chat_id);
  }
}

// Example output:
// fullResponse: "Our security practices include regular audits [[1]], 
// encryption at rest [[2]], and multi-factor authentication [[1]][[3]]."
//
// references: {
//   "1": { 
//     "memo_uuid": "123e4567-...", 
//     "memo_title": "Security Audit Procedures" 
//   },
//   "2": { 
//     "memo_uuid": "223e4567-...", 
//     "memo_title": "Data Encryption Standards" 
//   },
//   "3": { 
//     "memo_uuid": "323e4567-...", 
//     "memo_title": "Authentication Setup Guide" 
//   }
// }

Filters

Filters allow you to narrow down results based on memo metadata. You can filter by native fields or custom metadata fields. Filters are supported in search(), chat(), generateDoc(), and their streaming variants.

Filter Structure

interface Filter {
  field: string;                      // Field name to filter on
  operator: FilterOperator;           // Comparison operator
  value: string | string[];           // Value(s) to compare against
  filter_type: 'native_field' | 'custom_metadata';
}

Native Fields

Native fields are built-in memo properties:

  • title - Memo title
  • source - Source system (e.g., "notion", "confluence")
  • client_reference_id - Your external reference ID
  • tags - Memo tags (array)

Custom Metadata Fields

You can filter on any field from the metadata object you provided when creating the memo.

Filter Operators

  • eq - Equals (exact match)
  • neq - Not equals
  • contains - Contains substring (case-insensitive)
  • startswith - Starts with prefix (case-insensitive)
  • endswith - Ends with suffix (case-insensitive)
  • in - Value is in array (requires array value)
  • not_in - Value is not in array (requires array value)

Filter Examples

// Filter by source
{
  field: 'source',
  operator: 'eq',
  value: 'notion',
  filter_type: 'native_field'
}

// Filter by multiple tags
{
  field: 'tags',
  operator: 'in',
  value: ['security', 'compliance'],
  filter_type: 'native_field'
}

// Filter by title containing text
{
  field: 'title',
  operator: 'contains',
  value: 'meeting',
  filter_type: 'native_field'
}

// Filter by custom metadata field
{
  field: 'department',
  operator: 'eq',
  value: 'engineering',
  filter_type: 'custom_metadata'
}

// Exclude specific sources
{
  field: 'source',
  operator: 'not_in',
  value: ['draft', 'archive'],
  filter_type: 'native_field'
}

Combining Multiple Filters

When you provide multiple filters, they are combined with AND logic (all filters must match):

const results = await skald.search({
  query: 'security best practices',
  filters: [
    {
      field: 'source',
      operator: 'eq',
      value: 'security-docs',
      filter_type: 'native_field'
    },
    {
      field: 'tags',
      operator: 'in',
      value: ['approved', 'current'],
      filter_type: 'native_field'
    },
    {
      field: 'status',
      operator: 'neq',
      value: 'draft',
      filter_type: 'custom_metadata'
    }
  ]
});

Filters with Chat

Focus chat context on specific sources:

const result = await skald.chat({
  query: 'What are our security practices?',
  filters: [
    {
      field: 'tags',
      operator: 'in',
      value: ['security', 'compliance'],
      filter_type: 'native_field'
    }
  ]
});

Filters with Document Generation

Control which memos are used for document generation:

const doc = await skald.generateDoc({
  prompt: 'Create an API integration guide',
  rules: 'Use technical language with code examples',
  filters: [
    {
      field: 'source',
      operator: 'in',
      value: ['api-docs', 'technical-specs'],
      filter_type: 'native_field'
    },
    {
      field: 'document_type',
      operator: 'eq',
      value: 'specification',
      filter_type: 'custom_metadata'
    }
  ]
});

RAG Configuration

The rag_config parameter allows you to customize the Retrieval-Augmented Generation (RAG) behavior for chat operations. This gives you fine-grained control over how documents are retrieved, ranked, and used to generate responses.

RAG Config Structure

interface RAGConfig {
  llmProvider?: 'openai' | 'anthropic' | 'groq';
  queryRewrite?: {
    enabled: boolean;
  };
  vectorSearch?: {
    topK: number;              // 1-200
    similarityThreshold: number; // 0.0-1.0
  };
  reranking?: {
    enabled: boolean;
    topK: number;              // 1-100
  };
  references?: {
    enabled: boolean;
  };
}

RAG Config Options

llmProvider (string, optional)

  • Specifies which LLM provider to use for generating responses
  • Options: 'openai', 'anthropic', 'groq'
  • Defaults to your project's configured provider

queryRewrite (object, optional)

  • enabled (boolean) - Whether to rewrite the user's query for better retrieval
  • Query rewriting can improve search results by reformulating vague queries
  • Default: false

vectorSearch (object, optional)

  • topK (number, 1-200) - How many chunks to retrieve from vector search
  • similarityThreshold (number, 0.0-1.0) - Minimum similarity score (0 = most similar)
  • Lower similarity thresholds are more restrictive
  • Default: topK: 100, similarityThreshold: 0.8

reranking (object, optional)

  • enabled (boolean) - Whether to rerank search results for better relevance
  • topK (number, 1-100) - How many top results to keep after reranking (must be ≤ vectorSearch.topK)
  • Reranking uses a more sophisticated model to order results by relevance
  • Default: enabled: true, topK: 50

references (object, optional)

  • enabled (boolean) - Whether to include inline citations in the response (e.g., [[1]], [[2]])
  • Default: false

Basic RAG Config Examples

Enable References with Citations:

const result = await skald.chat({
  query: 'What are our security best practices?',
  rag_config: {
    references: {
      enabled: true
    }
  }
});

console.log(result.response);
// "Our security practices include: 1) Regular audits [[1]], 
// 2) Encryption at rest [[2]], and 3) Multi-factor authentication [[1]][[3]]"

Customize Vector Search Parameters:

const result = await skald.chat({
  query: 'Tell me about our product roadmap',
  rag_config: {
    vectorSearch: {
      topK: 150,                  // Retrieve more chunks
      similarityThreshold: 0.7    // Be less restrictive
    },
    reranking: {
      enabled: true,
      topK: 30                    // Keep top 30 after reranking
    }
  }
});

Use a Specific LLM Provider:

const result = await skald.chat({
  query: 'Summarize our Q4 goals',
  rag_config: {
    llmProvider: 'anthropic',    // Use Claude
    references: {
      enabled: true
    }
  }
});

Enable Query Rewriting for Better Results:

const result = await skald.chat({
  query: 'how do we handle that thing with customers?',  // Vague query
  rag_config: {
    queryRewrite: {
      enabled: true  // AI will reformulate this into a clearer query
    },
    vectorSearch: {
      topK: 100,
      similarityThreshold: 0.8
    }
  }
});

Disable Reranking for Faster Responses:

const result = await skald.chat({
  query: 'What is our company mission?',
  rag_config: {
    reranking: {
      enabled: false,  // Skip reranking for faster response
      topK: 50
    }
  }
});

Advanced RAG Config Examples

Fine-tune All RAG Parameters:

const result = await skald.chat({
  query: 'What security measures do we have in place?',
  system_prompt: 'You are a security expert. Provide detailed, technical answers.',
  rag_config: {
    llmProvider: 'anthropic',
    queryRewrite: {
      enabled: true
    },
    vectorSearch: {
      topK: 200,                  // Maximum retrieval
      similarityThreshold: 0.6    // Cast a wider net
    },
    reranking: {
      enabled: true,
      topK: 50                    // Keep top 50 most relevant
    },
    references: {
      enabled: true               // Include citations
    }
  },
  filters: [
    {
      field: 'tags',
      operator: 'in',
      value: ['security', 'compliance'],
      filter_type: 'native_field'
    }
  ]
});

Streaming Chat with RAG Config:

const stream = skald.streamedChat({
  query: 'Explain our data processing pipeline',
  rag_config: {
    llmProvider: 'groq',        // Use Groq for fast streaming
    vectorSearch: {
      topK: 120,
      similarityThreshold: 0.75
    },
    reranking: {
      enabled: true,
      topK: 40
    },
    references: {
      enabled: true
    }
  }
});

for await (const event of stream) {
  if (event.type === 'token') {
    process.stdout.write(event.content);
  } else if (event.type === 'done') {
    console.log('\nChat ID:', event.chat_id);
  }
}

Optimize for Precision (Narrow, Focused Results):

const result = await skald.chat({
  query: 'What is the exact version number of our API?',
  rag_config: {
    vectorSearch: {
      topK: 50,                   // Fewer chunks
      similarityThreshold: 0.9    // Very strict matching
    },
    reranking: {
      enabled: true,
      topK: 10                    // Only keep top 10
    }
  }
});

Optimize for Recall (Broad, Comprehensive Results):

const result = await skald.chat({
  query: 'Tell me everything about our customer onboarding process',
  rag_config: {
    vectorSearch: {
      topK: 200,                  // Maximum chunks
      similarityThreshold: 0.5    // More permissive
    },
    reranking: {
      enabled: true,
      topK: 80                    // Keep more results
    }
  }
});

RAG Config Best Practices

  1. Start with defaults: The default settings work well for most use cases. Only customize when you have specific needs.

  2. Enable references for transparency: If you need to verify information or provide source attribution, enable references.enabled: true.

  3. Balance topK values:

    • Higher vectorSearch.topK = more comprehensive but slower
    • Ensure reranking.topKvectorSearch.topK
    • Typical range: vectorSearch 80-150, reranking 30-60
  4. Adjust similarity threshold based on need:

    • Strict matching (0.9-1.0): Use when you need exact information
    • Balanced (0.7-0.8): Good default for most queries
    • Broad matching (0.5-0.6): Use for exploratory or vague queries
  5. Use query rewriting for user-facing applications: Enable queryRewrite.enabled: true when users might provide unclear or ambiguous queries.

  6. Choose LLM provider based on requirements:

    • anthropic (Claude): Great for nuanced understanding and longer context
    • openai (GPT): Fast and reliable for most use cases
    • groq: Optimized for speed with streaming responses

TypeScript Support for RAG Config

import { Skald, RAGConfig, LLMProvider } from '@skald-labs/skald-node';

const ragConfig: RAGConfig = {
  llmProvider: 'anthropic' as LLMProvider,
  queryRewrite: {
    enabled: true
  },
  vectorSearch: {
    topK: 150,
    similarityThreshold: 0.75
  },
  reranking: {
    enabled: true,
    topK: 50
  },
  references: {
    enabled: true
  }
};

const result = await skald.chat({
  query: 'What are our company values?',
  rag_config: ragConfig
});

Error Handling

try {
  const result = await skald.createMemo({
    title: 'My Memo',
    content: 'Content here'
  });
  console.log('Success:', result);
} catch (error) {
  console.error('Error:', error.message);
}

TypeScript Support

This package includes TypeScript type definitions out of the box.

import {
  Skald,
  MemoData,
  CreateMemoResponse,
  MemoFileData,
  CreateMemoFromFileResponse,
  MemoStatus,
  MemoStatusResponse,
  Memo,
  ListMemosResponse,
  UpdateMemoData,
  UpdateMemoResponse,
  DeleteMemoResponse,
  IdType,
  GetMemoRequest,
  UpdateMemoRequest,
  DeleteMemoRequest,
  CheckMemoStatusRequest,
  Filter,
  FilterOperator,
  FilterType,
  SearchRequest,
  SearchResponse,
  ChatRequest,
  ChatResponse,
  ChatStreamEvent,
  RAGConfig,
  LLMProvider,
  QueryRewriteConfig,
  VectorSearchConfig,
  RerankingConfig,
  ReferencesConfig,
  MemoReference,
  References
} from '@skald-labs/skald-node';

const skald = new Skald('your-api-key-here');

// Create a memo with types
const memoData: MemoData = {
  title: 'My Memo',
  content: 'Content here',
  tags: ['tag1', 'tag2'],
  metadata: { department: 'engineering' }
};

const createResponse: CreateMemoResponse = await skald.createMemo(memoData);

// Get memo with types
const memo: Memo = await skald.getMemo({ memoId: '550e8400-e29b-41d4-a716-446655440000' });
const memoByRef: Memo = await skald.getMemo({ memoId: 'external-id-123', idType: 'reference_id' as IdType });

// List memos with types
const memos: ListMemosResponse = await skald.listMemos({ page: 1, page_size: 20 });

// Update memo with types
const updateData: UpdateMemoData = {
  title: 'Updated Title',
  metadata: { status: 'reviewed' }
};
const updateResponse: UpdateMemoResponse = await skald.updateMemo({
  memoId: '550e8400-e29b-41d4-a716-446655440000',
  updateData
});

// Delete memo
await skald.deleteMemo({ memoId: '550e8400-e29b-41d4-a716-446655440000' });

// Upload a file
import * as fs from 'fs';
const fileBuffer = fs.readFileSync('./document.pdf');
const fileData: MemoFileData = {
  file: fileBuffer,
  filename: 'document.pdf',
  metadata: { type: 'report' },
  tags: ['document'],
  source: 'local'
};
const uploadResponse: CreateMemoFromFileResponse = await skald.createMemoFromFile(fileData);

// Check processing status
const statusResponse: MemoStatusResponse = await skald.checkMemoStatus({ memoId: uploadResponse.memo_uuid });
const status: MemoStatus = statusResponse.status; // 'processing' | 'processed' | 'error'

// Search with filters and types
const filters: Filter[] = [
  {
    field: 'source',
    operator: 'eq' as FilterOperator,
    value: 'notion',
    filter_type: 'native_field' as FilterType
  },
  {
    field: 'department',
    operator: 'eq' as FilterOperator,
    value: 'engineering',
    filter_type: 'custom_metadata' as FilterType
  }
];

const searchRequest: SearchRequest = {
  query: 'quarterly goals',
  limit: 10,
  filters
};

const searchResponse: SearchResponse = await skald.search(searchRequest);

// Chat with filters and types
const chatResponse: ChatResponse = await skald.chat({
  query: 'What are our quarterly goals?',
  filters
});

// Streaming chat with types
const stream = skald.streamedChat({
  query: 'What are our quarterly goals?',
  filters
});

for await (const event of stream) {
  const typedEvent: ChatStreamEvent = event;
  if (typedEvent.type === 'token') {
    process.stdout.write(typedEvent.content || '');
  }
}

// Chat with references and types
const chatWithRefs: ChatResponse = await skald.chat({
  query: 'What are our security best practices?',
  rag_config: {
    references: {
      enabled: true
    }
  }
});

console.log(chatWithRefs.response); // Response with [[1]], [[2]], etc.

if (chatWithRefs.references) {
  const refs: References = chatWithRefs.references;
  Object.entries(refs).forEach(([num, ref]) => {
    const memoRef: MemoReference = ref;
    console.log(`[${num}] ${memoRef.memo_title} (${memoRef.memo_uuid})`);
  });
}

// Streaming chat with references and types
let fullResponse = '';
let streamedRefs: References | undefined;

const streamWithRefs = skald.streamedChat({
  query: 'Explain our authentication system',
  rag_config: {
    references: {
      enabled: true
    }
  }
});

for await (const event of streamWithRefs) {
  const typedEvent: ChatStreamEvent = event;
  
  if (typedEvent.type === 'token') {
    fullResponse += typedEvent.content || '';
    process.stdout.write(typedEvent.content || '');
  } else if (typedEvent.type === 'references') {
    streamedRefs = JSON.parse(typedEvent.content || '{}') as References;
    console.log('\nReferences received:', Object.keys(streamedRefs).length);
  } else if (typedEvent.type === 'done') {
    console.log('\nChat completed:', typedEvent.chat_id);
  }
}