
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@natyapp/langchain
Advanced tools
TypeScript client for Naty LangChain API with async file uploads, real-time progress tracking, and Chat support
TypeScript client for the Naty LangChain API - Updated for OpenAPI 3.1.0 specification with full support for RAG, Chat, and File Upload features.
npm install @natyapp/langchain
# or
yarn add @natyapp/langchain
import { NatyLangChainClient } from '@natyapp/langchain';
const client = new NatyLangChainClient({
baseURL: 'http://localhost:8000',
apiKey: 'nlck-key_prod_1', // X-API-Key authentication
tenantId: 'demo-tenant', // X-Tenant-ID header (for multi-tenancy)
requestId: 'custom-request-id', // Optional: Custom X-Request-ID
});
const response = await client.qa.ask({
question: 'Como funciona o RAG?',
k: 3,
});
console.log(response.answer);
import { ChatMessage, ChatQARequest } from '@natyapp/langchain';
const chatHistory: ChatMessage[] = [
{ role: 'user', content: 'Olá!' },
{ role: 'assistant', content: 'Oi! Como posso ajudá-lo?' }
];
const request: ChatQARequest = {
question: 'Como funciona o sistema de RAG?',
system_prompt: 'Você é um especialista em IA',
chat_history: chatHistory,
rag_enabled: true,
k: 5,
max_history_messages: 10,
strict_context: true,
include_metadata: false
};
// Non-streaming response (NEW)
const response = await client.chat.chat(request);
console.log(response.answer);
console.log(`Used ${response.rag_documents_used} documents`);
// Streaming response
const stream = await client.chat.stream(request);
const reader = stream.getReader();
// Or use async iterator
for await (const chunk of client.chat.streamIterator(request)) {
if (chunk.type === 'content') {
console.log(chunk.data.text);
}
}
import { ExcelUploadOptions } from '@natyapp/langchain';
const files = [excelFile1, excelFile2]; // File objects
const options: ExcelUploadOptions = {
chunk_size: 1000,
text_format: 'structured',
include_sheets: 'Sheet1,Sheet2',
max_rows: 1000
};
const result = await client.fileUpload.uploadExcel(files, options);
console.log(`Processed ${result.sheets_processed.length} sheets`);
const preview = await client.fileUpload.previewExcel(excelFile, {
max_rows: 10,
text_format: 'csv'
});
import { PDFUploadOptions } from '@natyapp/langchain';
const options: PDFUploadOptions = {
extract_by_page: true,
chunk_size: 800,
page_range_start: 1,
page_range_end: 10
};
const result = await client.fileUpload.uploadPDF(pdfFiles, options);
import { WordUploadOptions } from '@natyapp/langchain';
const options: WordUploadOptions = {
extract_by_paragraph: false,
include_tables: true,
include_headers_footers: true,
preserve_formatting: false
};
const result = await client.fileUpload.uploadWord(wordFiles, options);
import { CSVUploadOptions } from '@natyapp/langchain';
const options: CSVUploadOptions = {
delimiter: ',',
encoding: 'utf-8',
output_format: 'structured',
row_chunk_size: 100,
skip_empty_rows: true
};
const result = await client.fileUpload.uploadCSV(csvFiles, options);
const health = await client.health.check();
console.log(`Status: ${health.status}`);
console.log(`Checks:`, health.checks);
import { CustomQAStreamRequest } from '@natyapp/langchain';
const request: CustomQAStreamRequest = {
system_prompt: 'Responda como especialista técnico',
question: 'Explique machine learning',
contexts_text: 'Machine Learning é...', // Optional explicit context
strict_context: true,
k: 4
};
const stream = await client.customQA.stream(request);
// Process streaming response...
import { NatyClient } from '@natyapp/langchain';
// Legacy client still works (shows deprecation warning)
const legacyClient = new NatyClient({
baseURL: 'http://localhost:8000',
token: 'legacy-token', // Will be used as X-API-Key
tenantId: 'demo-tenant',
});
The following client usage:
const client = new NatyLangChainClient({
baseURL: 'http://localhost:8000',
apiKey: 'nlck-key_prod_1',
tenantId: 'demo-tenant',
requestId: 'demo-request-id',
});
await client.qa.ask({ question: 'Olá?', k: 3 });
Is equivalent to this cURL command:
curl -X POST http://localhost:8000/v1/qa \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: demo-tenant" \
-H "X-API-Key: nlck-key_prod_1" \
-H "X-Request-ID: demo-request-id" \
-d '{"question": "Olá?", "k": 3}'
interface NatyLangChainClientConfig {
baseURL: string;
apiKey?: string; // API key for X-API-Key header
tenantId?: string; // Tenant ID for X-Tenant-ID header
requestId?: string; // Custom request ID (auto-generated if not provided)
}
// Backward compatibility
interface NatyClientConfig extends NatyLangChainClientConfig {
token?: string; // Legacy token (deprecated, use apiKey)
}
The client automatically manages the following headers:
Content-Type: application/json - Always includedX-API-Key - API key authentication (replaces Bearer tokens)X-Tenant-ID - Multi-tenant support (when tenantId provided)X-Request-ID - Request tracking (auto-generated UUID if not provided)// Simple QA request
const qaResponse = await client.qa.ask({
question: 'What is LangChain?',
k: 4, // Optional: number of documents to retrieve
filters: { // Optional: vector store filters
category: { $eq: 'tech' }
}
});
// Override tenant ID per request
const response = await client.qa.ask(request, 'different-tenant-id');
// Custom QA with system prompt
const customResponse = await client.customQA.ask({
system_prompt: 'You are a helpful assistant that responds in Portuguese.',
question: 'Como posso ajudar você hoje?',
contexts_text: 'Optional explicit context', // Optional
filters: { tenant_id: { $eq: 'demo-tenant' } }, // Optional
k: 4, // Optional
strict_context: true, // Optional
});
// Streaming custom QA
const stream = await client.customQA.stream({
system_prompt: 'You are a helpful assistant.',
question: 'Tell me about AI',
strict_context: false,
});
// Process stream
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(new TextDecoder().decode(value));
}
// Create documents
const createResponse = await client.documents.create([
{
text: 'Document content here',
metadata: {
title: 'Document Title',
category: 'technology',
source: 'internal',
},
},
]);
// Create documents in batch (async operation)
const batchResponse = await client.documents.createBatch([...documents]);
// List documents
const listResponse = await client.documents.list();
// Search documents
const searchResponse = await client.documents.search({
query: 'search term',
filters: { category: { $eq: 'technology' } },
k: 5,
});
// Delete documents by IDs
const deleteResponse = await client.documents.delete(['doc-id-1', 'doc-id-2']);
The client uses enhanced error handling with NatyLangChainError:
import { NatyLangChainError } from '@natyapp/langchain';
try {
const response = await client.qa.ask({ question: 'Test' });
} catch (error) {
if (error instanceof NatyLangChainError) {
console.error('API Error:', error.message);
console.error('Status:', error.status); // HTTP status code
console.error('Code:', error.code); // Error code
console.error('Details:', error.details); // Additional error details
} else {
console.error('Unknown error:', error);
}
}
The client automatically logs request headers (with API key masking for security):
// Example log output:
// Request headers: {
// 'X-Tenant-ID': 'demo-tenant',
// 'X-Request-ID': 'a90e-fb3b-4931-8dc4-51cc8adabf4e',
// 'X-API-Key': 'nlck...od_1' // Masked for security
// }
import { generateRequestId, maskApiKey } from '@natyapp/langchain';
// Generate UUID-like request ID
const requestId = generateRequestId();
console.log(requestId); // "a90e-fb3b-4931-8dc4-51cc8adabf4e"
// Mask API key for logging
const maskedKey = maskApiKey('nlck-key_prod_1234567890');
console.log(maskedKey); // "nlck...7890"
Update client initialization:
// Old
const client = new NatyClient({
baseURL: 'http://localhost:8000',
token: 'bearer-token',
tenantId: 'tenant-id',
});
// New
const client = new NatyLangChainClient({
baseURL: 'http://localhost:8000',
apiKey: 'nlck-key_prod_1', // Changed from token
tenantId: 'tenant-id',
});
Update API URLs:
/documents → /v1/documents/v1/qa (unchanged)/v1/qa/custom (unchanged)Remove query parameters:
llm, embeddings, retriever query parametersUpdate error handling:
// Old
catch (error) {
console.error(error.message);
}
// New
catch (error) {
if (error instanceof NatyLangChainError) {
console.error('Status:', error.status);
console.error('Code:', error.code);
console.error('Message:', error.message);
}
}
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run integration tests only
npm test -- tests/integration.test.ts
# Lint
npm run lint
# Format code
npm run format
See the examples/ directory for complete usage examples:
examples/usage-example.ts - Comprehensive usage demonstrationgit checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)MIT License
FAQs
TypeScript client for Naty LangChain API with async file uploads, real-time progress tracking, and Chat support
We found that @natyapp/langchain demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.