Package Exports
- solver-sdk
Readme
Code Solver SDK v8.1.0
AI-powered code analysis SDK with WorkCoins billing system. 100% typed, production ready.
Install
npm install solver-sdk@8.1.0Quick 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
const sdk = await CodeSolverSDK.create({
baseURL: 'https://api.example.com',
getAuthToken: async () => {
if (isTokenExpired()) {
await refreshToken();
}
return getToken();
}
});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
Auth Errors
By default, 401/403 auth errors return null instead of throwing:
const projects = await sdk.projects.getAllProjects();
if (!projects) {
// Token expired - refresh and retry
await refreshToken();
}
// To throw errors instead:
const sdk = await CodeSolverSDK.create({
suppressAuthErrors: false
});Usage Limits & Rate Limiting
SDK automatically handles usage limit and rate limit errors with specialized error classes:
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);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