Package Exports
- solver-sdk
Readme
Code Solver SDK v8.2.0
AI-powered code analysis SDK with WorkCoins billing system. 100% typed, production ready.
Install
npm install solver-sdk@8.2.0✨ What's New in v8.2.0
Centralized Error Handling - Full typed error system with 15+ error classes:
- 🎯 Typed exceptions instead of
nullreturns - 🔍 TypeScript autocomplete for all error types
- 🛡️ Better debugging with
requestId,timestamp,details - ✅ Backward compatible - existing code continues to work
See Error Handling section for details.
Quick Start
import { CodeSolverSDK } from 'solver-sdk';
const sdk = await CodeSolverSDK.create({
baseURL: 'https://api.example.com',
getAuthToken: async () => getToken()
});
// Projects
const projects = await sdk.projects.getAllProjects();
await sdk.projects.createProject('MyProject');
// Chat with Thinking
const response = await sdk.chat.chat([
{ role: 'user', content: 'explain this code' }
], { thinking: { type: 'enabled', budget_tokens: 10000 } });
// Search
const results = await sdk.search.searchCode({
projectId,
query: 'authentication function'
});
// User & Updates
const profile = await sdk.user.getProfile();
const update = await sdk.updates.checkForUpdates({...});API Overview
| Feature | Methods | Status |
|---|---|---|
| Projects | 19 | ✅ Full CRUD + state |
| Delta Chunking | 7 | ✅ Encrypted sync |
| Chat | 12 | ✅ Streaming + Extended Thinking |
| Search | 4 | ✅ Vector-based |
| Tools | 5 | ✅ AI tool schemas |
| Models | 5 | ✅ Provider info |
| Updates | 5 | ✅ Auto-check + changelog |
| User | 3 | ✅ Profile + Limits |
| Credits | 7 | ✅ Balance + Overage management |
| Auth | 2 | ✅ Token revocation + logout |
Auth
// Local dev
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
getAuthToken: async () => 'your-token'
});
// Production with token refresh + error handling
import { AuthenticationError } from 'solver-sdk';
const sdk = await CodeSolverSDK.create({
baseURL: 'https://api.example.com',
getAuthToken: async () => {
if (isTokenExpired()) {
await refreshToken();
}
return getToken();
}
});
// All methods throw AuthenticationError on 401
try {
await sdk.user.getProfile();
} catch (error) {
if (error instanceof AuthenticationError) {
await refreshToken();
// retry
}
}WebSocket (Real-time)
// Connect
await sdk.connectWebSocket();
// Subscribe to project
sdk.projectSync.subscribeToProject(projectId);
// Listen for updates
sdk.projectSync.on('sync-progress', (data) => {
console.log(`Progress: ${data.processedFiles}/${data.totalFiles}`);
});
sdk.projectSync.on('sync-completed', (data) => {
console.log(`Done: ${data.statistics.totalFiles} files`);
});Error Handling
v8.2.0+ All SDK methods throw typed exceptions instead of returning null. This enables better error handling with TypeScript autocomplete.
Available Error Types
import {
// Auth errors
AuthenticationError, // 401 - token expired/invalid
ForbiddenError, // 403 - access denied
// Client errors
ValidationError, // 422 - invalid data
NotFoundError, // 404 - resource not found
ConflictError, // 409 - data conflict
BadRequestError, // 400 - bad request
// Server errors
InternalServerError, // 500 - server error
ServiceUnavailableError, // 503 - service down
GatewayTimeoutError, // 504 - timeout
// Special errors
LimitExceededError, // 403 - credits limit exceeded
RateLimitError, // 429 - too many requests
NetworkError, // 0 - network failure
TimeoutError, // 408 - request timeout
DatabaseError // 400 - database error
} from 'solver-sdk';Basic Error Handling
try {
const status = await sdk.credits.getStatus();
console.log(status.balance);
} catch (error) {
// All errors have common properties:
console.log(error.statusCode); // HTTP status code
console.log(error.errorType); // Error type string
console.log(error.requestId); // For correlation with backend logs
console.log(error.timestamp); // When error occurred
console.log(error.rawResponse); // Full backend response
}Auth Error Handling
import { AuthenticationError } from 'solver-sdk';
try {
const balance = await sdk.credits.getBalance();
} catch (error) {
if (error instanceof AuthenticationError) {
// Token expired or invalid
console.log('Token expired, refreshing...');
await refreshToken();
// Retry the request
return retry();
}
}Usage Limits & Rate Limiting
SDK provides specialized error classes for limits:
Checking Limit Status
import { CodeSolverSDK } from 'solver-sdk';
const sdk = await CodeSolverSDK.create({ /* ... */ });
// Get detailed limit status
const status = await sdk.user.getLimitStatus();
console.log(`Status: ${status.status}`); // 'ok' | 'warning' | 'critical' | 'blocked' | 'on_demand'
console.log(`Can make requests: ${status.canMakeRequest}`);
if (status.status === 'warning' || status.status === 'critical') {
console.warn(`Warning: ${status.message}`);
}
if (status.action) {
console.log(`Recommendation: ${status.action.suggestion}`);
}Handling Limit Exceeded (403)
import { CodeSolverSDK, LimitExceededError } from 'solver-sdk';
try {
await sdk.chat.streamChat([
{ role: 'user', content: 'Hello' }
]);
} catch (error) {
if (error instanceof LimitExceededError) {
console.log('Usage limit exceeded!');
console.log(`Type: ${error.statusType}`); // e.g. 'debt_limit_exceeded'
console.log(`Blocked: ${error.isBlocked()}`); // true/false
if (error.action) {
console.log(`Action: ${error.action.suggestion}`);
console.log(`URL: ${error.getActionUrl()}`);
}
if (error.balance) {
console.log(`Balance: ${error.balance.currentRub}₽`);
console.log(`Required topup: ${error.balance.requiredTopup}₽`);
}
}
}Handling Rate Limit (429)
import { CodeSolverSDK, RateLimitError } from 'solver-sdk';
try {
// Making multiple requests rapidly
for (let i = 0; i < 100; i++) {
await sdk.user.getProfile();
}
} catch (error) {
if (error instanceof RateLimitError) {
console.log('Rate limit exceeded!');
console.log(`Wait ${error.retryAfter} seconds`);
console.log(`Retry at: ${error.retryAt}`);
console.log(`Time remaining: ${error.getRetryDelayMs()}ms`);
// Wait and retry
await new Promise(resolve => setTimeout(resolve, error.getRetryDelayMs()));
// ... retry request
}
}Proactive Limit Checking
// Check before making expensive operations
async function sendChatMessage(message: string) {
// 1. Check limit status first
const status = await sdk.user.getLimitStatus();
if (!status.canMakeRequest) {
console.error('Cannot make request:', status.message);
return;
}
if (status.status === 'warning') {
console.warn('Low on tokens:', status.message);
}
// 2. Make the request
try {
await sdk.chat.streamChat([
{ role: 'user', content: message }
]);
} catch (error) {
if (error instanceof LimitExceededError) {
// Handle limit error
} else if (error instanceof RateLimitError) {
// Handle rate limit
}
}
}Credits System (WorkCoins)
Note: In the WorkAI UI, this system is referred to as "WorkCoins" for user clarity. The API and SDK continue to use
creditsin method names and responses for backward compatibility.
SDK provides full support for WorkCoins-based pricing model:
Check WorkCoins Balance
const balance = await sdk.credits.getBalance();
console.log(`WorkCoins limit: ${balance.creditsLimit}`);
console.log(`WorkCoins used: ${balance.creditsUsed}`);
console.log(`WorkCoins remaining: ${balance.creditsRemaining}`);
console.log(`Usage: ${balance.percentUsed}%`);
if (balance.bonusCredits) {
console.log(`Bonus WorkCoins: ${balance.bonusCredits}`);
}
if (balance.overageEnabled) {
console.log(`Overage WorkCoins used: ${balance.overageCreditsUsed}/${balance.overageLimit}`);
}Check WorkCoins Status (with recommendations)
const status = await sdk.credits.getStatus();
console.log(`Status: ${status.status}`); // 'ok' | 'warning' | 'critical' | 'depleted'
console.log(`Can make request: ${status.canMakeRequest}`);
console.log(`Message: ${status.message}`);
if (status.action) {
console.log(`Action: ${status.action.type}`); // 'info' | 'upgrade' | 'enable_overage'
console.log(`Suggestion: ${status.action.suggestion}`);
console.log(`URL: ${status.action.url}`);
}Estimate Operation Cost (WorkCoins)
// Estimate before making a request
const estimate = await sdk.credits.estimate(
50000, // tokens (technical parameter for estimation)
'haiku', // model: 'haiku' | 'sonnet' | 'auto'
'code_generation' // operation type
);
console.log(`Estimated WorkCoins: ${estimate.estimatedCredits}`);
console.log(`Confidence: ${estimate.confidence}`); // 'low' | 'medium' | 'high'
console.log(`Breakdown:`, estimate.breakdown);Manage Overage (Pay-as-you-go)
// Get overage config
const config = await sdk.credits.getOverageConfig();
console.log(`Enabled: ${config.enabled}`);
console.log(`Limit: ${config.limitCredits} WorkCoins`);
console.log(`Price: ₽${config.pricePerCreditRub} per WorkCoin`);
// Enable/disable overage
await sdk.credits.toggleOverage(true);
// Update overage limit
await sdk.credits.updateOverageLimit(1000);
// Get overage stats for current month
const stats = await sdk.credits.getOverageStats();
console.log(`Total WorkCoins used: ${stats.totalCreditsUsed}`);
console.log(`Total cost: ₽${stats.totalCostRub}`);
console.log(`Usage count: ${stats.usageCount}`);
console.log(`Avg per operation: ${stats.avgCreditsPerOperation}`);Handle WorkCoins Errors
import { CodeSolverSDK, CreditsStatus } from 'solver-sdk';
try {
// Check before making request
const status = await sdk.credits.getStatus();
if (!status.canMakeRequest) {
console.error('No WorkCoins available');
return;
}
// Make AI request
await sdk.chat.chat([...]);
} catch (error) {
if (error.response?.data?.error === 'credits_limit_exceeded') {
console.error('WorkCoins exhausted. Please upgrade or enable overage.');
} else if (error.response?.data?.error === 'overage_limit_exceeded') {
console.error('Overage limit reached.');
}
}Types
import {
ChatMessage,
ChatOptions,
Project,
ProjectState,
SearchResult,
UserProfile,
LimitStatus,
LimitExceededError,
RateLimitError
} from 'solver-sdk';Debug
const sdk = await CodeSolverSDK.create({
debug: 'verbose', // silent | error | warn | info | debug | verbose
webSocket: { debug: true }
});Delta Chunking (Indexing)
// ✅ Main indexing method
await sdk.deltaManager.syncEncryptedChunks(projectId, chunks, rootHash, {
batchSize: 50,
onProgress: (current, total) => console.log(`${current}/${total}`)
});
// Check sync status
const state = await sdk.projects.getProjectState(projectId, clientRootHash);
if (state.syncRequired) {
// Needs sync
}
// Cancel ongoing sync
await sdk.deltaManager.cancelSync(projectId);File Invalidation
// Инвалидировать файл при изменении
const result = await sdk.deltaManager.invalidateFile(projectId, {
filePath: 'src/app.tsx',
reason: 'file_changed'
});
console.log(`Invalidated ${result.chunksInvalidated} chunks`);
console.log(`Cache invalidated: ${result.cacheInvalidated}`);
// Отправить новые chunks после инвалидации
await sdk.deltaManager.syncEncryptedChunks(projectId, newChunks, rootHash);Session Recovery
// Always check on project open
const recovery = await sdk.projects.getRecoveryStatus(projectId);
if (recovery.needsRecovery) {
const { processedFiles, totalFiles, percentage } = recovery.progress;
// Show dialog: "Continue (67%) — 480/642 files" or "Start Fresh"
await sdk.projects.resumeSync(projectId); // Continue
// OR
await sdk.projects.cancelRecovery(projectId); // Start over
}Key Types
ProjectState
interface ProjectState {
projectId: string;
merkleRootHash: string | null;
totalFiles: number; // For UI display
indexingStatus: 'pending' | 'in-progress' | 'complete' | 'failed';
syncRequired?: boolean; // Compare with client hash
}SyncProgressEvent
interface SyncProgressEvent {
projectId: string;
progress: number; // 0-100
processedFiles: number; // 450
totalFiles: number; // 722
stage: 'receiving_chunks' | 'processing_chunks' | 'creating_embeddings' | 'finalizing';
}RecoveryInfo
interface RecoveryInfo {
needsRecovery: boolean;
progress: {
processedFiles: number;
totalFiles: number;
percentage: number; // 0-100
};
canResume: boolean;
}LimitStatus
interface LimitStatus {
status: 'ok' | 'warning' | 'critical' | 'blocked' | 'on_demand';
statusType: string; // e.g. 'using_bonus_tokens', 'debt_limit_exceeded'
message: string; // Human-readable message
canMakeRequest: boolean; // Can user make API requests?
currentSource?: 'bonus' | 'subscription' | 'on_demand';
remaining?: {
bonusTokens?: number; // Remaining bonus tokens
bonusPercent?: number; // % remaining
subscriptionTokens?: number; // Remaining subscription tokens
subscriptionPercent?: number;
};
balance?: {
currentRub?: number; // Current balance in rubles
maxDebtRub?: number; // Max allowed debt
requiredTopup?: number; // Required topup amount
};
action?: {
type: 'info' | 'urgent' | 'required';
suggestion: string; // "Top up balance" / "Upgrade plan"
ctaUrl?: string; // Dashboard URL
};
}Troubleshooting
"0 files" after indexing
const state = await sdk.projects.getProjectState(projectId);
console.log(state.totalFiles); // Should be > 0
// If 0: update backend to latest versionNo WebSocket updates
// 1. Check connection
console.log(sdk.isWebSocketConnected); // should be true
// 2. Verify subscription
sdk.projectSync.subscribeToProject(projectId);
// 3. Ensure OAuth token (production)
const sdk = await CodeSolverSDK.create({
getAuthToken: () => authManager.getAccessToken()
});
// 4. Fallback to HTTP polling
const status = await sdk.projects.getIndexingStatus(projectId);Interrupted sync
const recovery = await sdk.projects.getRecoveryStatus(projectId);
if (recovery.needsRecovery) {
// Option 1: Resume
await sdk.projects.resumeSync(projectId);
// Option 2: Cancel and restart
await sdk.projects.cancelRecovery(projectId);
}API Reference
Projects (sdk.projects)
getAllProjects(): Promise<Project[]>
getProjects(): Promise<Project[]>
getProject(projectId: string): Promise<Project>
createProject(name: string, data?: any, options?: ProjectOptions): Promise<Project>
findOrCreateProject(name: string): Promise<Project>
deleteProject(projectId: string): Promise<void>
getReadyProjects(): Promise<Project[]>
getProjectState(projectId: string, clientRootHash?: string): Promise<ProjectState>
getProjectStatus(projectId: string): Promise<any>
getIndexingStatus(projectId: string): Promise<any>
cancelIndexing(projectId: string): Promise<boolean>
clearIndexingError(projectId: string): Promise<boolean>
getRecoveryStatus(projectId: string): Promise<RecoveryInfo>
resumeSync(projectId: string, options?: any): Promise<any>
cancelRecovery(projectId: string): Promise<void>
initializeDeltaSync(projectId: string, params: any): Promise<any>
resetIndexing(projectId: string): Promise<any>
restartIndexing(projectId: string): Promise<any>
getFilePathMapping(projectId: string): Promise<any>Delta Manager (sdk.deltaManager)
initSync(projectId: string, request: SyncInitRequest): Promise<any>
uploadChunkBatch(projectId: string, chunks: any[]): Promise<any>
uploadChunksWithRetry(projectId: string, chunks: any[], options?: any): Promise<any>
finalizeSync(projectId: string): Promise<SyncResult>
getSyncStatus(projectId: string): Promise<SyncStatus>
cancelSync(projectId: string): Promise<{ success: boolean; message?: string }>
cleanupFiles(projectId: string, activeFiles: string[]): Promise<any>Chat (sdk.chat)
chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
chatCompletion(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
chatWithRegionFailover(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
streamChat(messages: ChatMessage[], options?: ChatStreamOptions): AsyncGenerator<ChatStreamChunk>
streamPrompt(prompt: string, options?: ChatStreamOptions): AsyncGenerator<ChatStreamChunk>
sendContinuation(requestId: string, messages: ChatMessage[]): AsyncGenerator<ChatStreamChunk>
sendPromptWithRegionFailover(prompt: string, options?: ChatOptions): Promise<string>
checkAvailability(): Promise<boolean>
cancelRequest(requestId: string): Promise<void>
getStreamsStats(): Promise<any>
cleanupStaleStreams(timeoutMs?: number): Promise<any>
cancelUserStreams(reason?: string): Promise<number>Search (sdk.search)
searchCode(projectIdOrParams: string | SearchCodeParams, params?: SearchCodeParams): Promise<SearchResult[]>
searchFunctions(projectIdOrParams: string | SearchFunctionsParams, params?: SearchFunctionsParams): Promise<FunctionSearchResult>
semanticSearch(projectId: string, params: SearchCodeParams): Promise<SearchResult[]>
getFunctionStats(projectId: string): Promise<{ stats: { totalFunctions: number } }>Tools (sdk.tools)
getSchemas(): Promise<ToolsResponse>
findToolByName(name: string): Promise<ToolSchema | null>
getToolsStats(): Promise<{ total: number; categories: Record<string, number>; mostUsed?: string[] }>
validateToolSchema(tool: ToolSchema): boolean
createToolSchema(name: string, description: string, properties: any, required?: string[]): ToolSchemaUser (sdk.user)
getProfile(): Promise<UserProfile>
getLimitStatus(): Promise<LimitStatus>
checkAvailability(): Promise<boolean>Auth (sdk.auth)
revokeToken(token: string): Promise<{ ok: boolean }>
logout(): Promise<{ ok: boolean }>Models (sdk.models)
getAllModels(): Promise<any[]>
getModels(): Promise<any[]>
getAvailableModels(): Promise<any[]>
getProviderModels(providerId: string): Promise<ProviderModels>
getModelInfo(modelId: string): Promise<any>Updates (sdk.updates)
checkForUpdates(options: UpdateCheckOptions): Promise<UpdateResponse>
getChangelog(version: string, locale: string): Promise<string>
sendStats(event: UpdateStatsEvent): Promise<void>
getLatestVersion(channel?: string): Promise<LatestVersionInfo>
checkAvailability(): Promise<boolean>WebSocket (sdk.projectSync)
connectWebSocket(): Promise<void>
disconnectWebSocket(): void
isWebSocketConnected: boolean
projectSync.subscribeToProject(projectId: string): void
projectSync.unsubscribeFromProject(projectId: string): void
projectSync.on('sync-status-update', callback): void
projectSync.on('sync-progress', callback): void
projectSync.on('sync-completed', callback): void
projectSync.on('sync-error', callback): void
projectSync.off(event: string, callback): voidUtility
checkHealth(): Promise<boolean>
version: string
baseURL: stringDocs
- Full verification: SDK_v7.2.0_FINAL_REPORT.md
- Migration guide: SDK_v7.2.0_MIGRATION.md
- Architecture: ARCHITECTURE_NOTES.md
All methods have JSDoc comments - check IDE autocomplete for full reference.
Status: ✅ Production Ready | v8.1.0 | License: MIT