JavaScript/TypeScript SDK для VS Code Extensions
Подключение к AI бэкенду для индексации, поиска и работы с кодом
JavaScript/TypeScript SDK для работы с Code Solver API. Предоставляет простой интерфейс для индексации кода, семантического поиска функций и работы с AI чатом.
- 💬 Chat API - взаимодействие с AI моделями (Claude, GPT)
- 🔍 Code Search - семантический поиск по коду и функциям
- 📊 Project Indexing - индексация и анализ проектов
- 📝 Context API - получение контекста для AI
- 🛠️ Code Modification - модификация кода через AI
- 🔇 Настраиваемое логирование - полный контроль над выводом в консоль
-
ИСПРАВЛЕНА КРИТИЧЕСКАЯ ОШИБКА 404: Полностью обновлен SDK для работы с унифицированным API
- Все методы теперь используют правильный endpoint
/api/v1/projects
- Убраны ссылки на несуществующий endpoint
/projects/find-or-create
- Полная совместимость с backend API v3.1.14
- Решены все проблемы с дедупликацией проектов
- Все методы теперь используют правильный endpoint
-
Один endpoint для всех операций: Все методы создания проектов используют единый
POST /projects
с автоматической дедупликацией - Никаких дубликатов: Система автоматически находит существующие проекты по пути
- Упрощенная API: Убрана избыточность, улучшена консистентность
-
🔧 Tool choice валидация: Исправлена согласно официальной документации
- Только
tool_choice: "any"
или{ type: "any" }
с thinking (как в документации) - Убраны неточные валидации
auto
,none
с thinking
- Только
-
🛡️ Interleaved thinking: Улучшена логика добавления beta header
- Добавляет
interleaved-thinking-2025-05-14
только еслиoptions.beta
не установлен
- Добавляет
-
📋 onEvent callback: Финальное исправление структуры данных
- 100% соответствие стандарту Anthropic API в onEvent callbacks
- Проблема решена: onEvent callback теперь получает оригинальные события Anthropic API
-
Исправлено:
content_block_start
содержит полныйcontent_block
объект с правильнымиid
,name
,input
-
Исправлено:
input_json_delta
передается какdelta.type: 'input_json_delta'
вместо обычного text -
Убрано: Лишние поля
projectId
,timestamp
которые нарушали стандарт Anthropic - Результат: Полная совместимость с Anthropic API стандартом для tool_use событий
// ❌ БЫЛО (v3.1.7): onEvent получал обработанные данные
onEvent: (type, data) => {
// data содержал: { projectId, timestamp, content_block: null }
}
// ✅ СТАЛО (v3.1.8): onEvent получает оригинальные данные
onEvent: (type, data) => {
// data содержит стандартные Anthropic события:
// content_block_start: { type, index, content_block: { type: 'tool_use', id, name, input } }
// content_block_delta: { type, index, delta: { type: 'input_json_delta', partial_json } }
}
- Проблема решена: SDK больше не создает спам в Developer Console VS Code
-
Новые уровни логирования:
'silent' | 'error' | 'warn' | 'info' | 'debug'
- Детальный контроль потоков: Настройка логирования SSE событий, chunk'ов и callbacks
-
Обратная совместимость: Старые опции
debug: true/false/'verbose'
работают как раньше
-
🔧 КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Восстановлена передача
content_block_start
событий дляtool_use
блоков - ✅ Tool Continuation: Исправлена поддержка tool continuation функциональности
-
🛠️ Новые события: Добавлена обработка
input_json_delta
,signature_delta
для инструментов - 📊 Улучшенная обработка: Корректная обработка всех типов content блоков (thinking, text, tool_use)
-
🔒 Валидация: Исправлена валидация
tool_choice
согласно документации Anthropic
-
✅ Исправлена критическая проблема
toJSON
- решена ошибка сериализации в VS Code IPC -
🆕 Новые API методы:
getIndexingStatus()
,getProjectInfo()
для безопасной работы - 🔧 Безопасная сериализация: Все Date объекты автоматически преобразуются в ISO строки
- 🧠 Thinking API: Полная поддержка мышления Claude с real-time выводом
- 📊 Real-time данные: Приоритет live данных над статическими из БД
Для разработчиков инструментов: v3.1.6 восстанавливает корректную работу tool continuation!
npm install solver-sdk
SDK предлагает гибкую систему логирования для контроля вывода в консоль:
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
// Уровни логирования (от тихого к подробному):
debug: 'silent', // Полное отключение (даже ошибки)
debug: 'error', // Только ошибки (рекомендуется для VS Code)
debug: 'warn', // Предупреждения и ошибки
debug: 'info', // Базовая информация
debug: 'debug', // Подробная отладка
// Обратная совместимость:
debug: false, // Отключено
debug: true, // Базовое логирование
debug: 'verbose' // Подробное (аналог 'debug')
});
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
debug: 'debug', // или любой уровень
// Точная настройка логирования потоков:
streamLogging: {
sseEvents: false, // SSE события (content_block_start/delta/stop)
streamChunks: false, // Chunk'и потока (каждый кусок текста)
eventCallbacks: false,// onEvent callback'и
importantOnly: true // Только важные события (start, stop, errors)
}
});
// 🔹 VS Code Extension (production):
debug: 'error'
// 🔹 Development:
debug: 'info'
// 🔹 Deep debugging:
debug: 'debug',
streamLogging: { sseEvents: true, streamChunks: true }
// 🔹 Полная тишина:
debug: 'silent'
import { CodeSolverSDK } from 'solver-sdk';
// Создание SDK с чистой консолью (рекомендуется для VS Code)
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
debug: 'error' // Только ошибки, никакого спама
});
// Или с детальным логированием для отладки
const debugSdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
debug: 'debug',
streamLogging: {
sseEvents: true, // Логировать SSE события
streamChunks: true, // Логировать chunk'и потока
eventCallbacks: true // Логировать onEvent callbacks
}
});
// Создание и индексация проекта
const project = await sdk.projects.findOrCreateProject(
'/path/to/project',
'My Project'
);
await sdk.projects.startIndexing(project.id);
// 📝 Важно (v3.1.15): Все методы создания проектов теперь используют
// единый endpoint /api/v1/projects с автоматической дедупликацией.
// Никаких дубликатов проектов!
// Поиск кода
const searchResults = await sdk.search.searchCode(project.id, {
query: 'function calculateSum',
limit: 10
});
// Поиск функций
const functions = await sdk.search.searchFunctions(project.id, {
query: 'FileIndexingService',
limit: 5
});
// Работа с чатом
const response = await sdk.chat.chat([
{ role: 'user', content: 'Объясни этот код' }
], { projectId: project.id });
// Потоковый чат с thinking (мышлением)
for await (const chunk of sdk.chat.streamChat([
{ role: 'user', content: 'Объясни рекурсию пошагово' }
], {
projectId: project.id,
thinking: {
type: 'enabled',
budget_tokens: 5000
},
onEvent: (type, data) => {
if (type === 'content_block_delta' && data.delta?.type === 'thinking_delta') {
console.log(`🧠 Думает: ${data.delta.thinking}`);
} else if (type === 'content_block_delta' && data.delta?.type === 'text_delta') {
console.log(`💬 Отвечает: ${data.delta.text}`);
}
}
})) {
if (chunk.text) {
process.stdout.write(chunk.text);
}
}
// Создание проекта (исправленная сигнатура)
await sdk.projects.createProject(
'Project Name', // name
'/project/path', // path
{ description: 'Desc' } // data (опционально)
);
// Получение списка проектов
await sdk.projects.getProjects();
// Получение информации о проекте
await sdk.projects.getProject(projectId);
// Получение готовых проектов
await sdk.projects.getReadyProjects();
// Создание/поиск проекта и запуск индексации
const project = await sdk.projects.findOrCreateProject('/path/to/project', 'Project Name');
await sdk.projects.startIndexing(project.id, { force: false }); // options опционально
// Получение real-time статуса индексации
const indexingStatus = await sdk.projects.getIndexingStatus(project.id);
console.log('Статус:', indexingStatus.status, 'Прогресс:', indexingStatus.progress + '%');
// Получение общей информации о проекте
const projectInfo = await sdk.projects.getProjectInfo(project.id);
// Ожидание завершения индексации
while (true) {
const status = await sdk.projects.getIndexingStatus(project.id);
console.log(`Прогресс: ${status.progress}%, Файлы: ${status.processedFiles}/${status.totalFiles}`);
if (status.status === 'complete') break;
if (status.status === 'failed') throw new Error('Ошибка индексации: ' + status.error);
await new Promise(resolve => setTimeout(resolve, 2000));
}
// Поиск кода (гибкая сигнатура)
// Способ 1: projectId отдельно
await sdk.search.searchCode(projectId, {
query: 'search query',
limit: 20
});
// Способ 2: projectId в параметрах
await sdk.search.searchCode({
projectId: projectId,
query: 'search query',
limit: 20
});
// Поиск функций (гибкая сигнатура)
// Способ 1: projectId отдельно
const functions = await sdk.search.searchFunctions(projectId, {
query: 'calculateSum',
limit: 10
});
// Способ 2: projectId в параметрах
const functions = await sdk.search.searchFunctions({
projectId: projectId,
query: 'calculateSum',
limit: 10
});
// Статистика функций в проекте
const stats = await sdk.search.getFunctionStats(projectId);
console.log(`Всего функций: ${stats.stats.totalFunctions}`);
// Обычный чат (projectId опционален в реализации, но рекомендуется)
const response = await sdk.chat.chat([
{ role: 'user', content: 'Объясни этот код' }
], { projectId: 'your-project-id' }); // projectId опционален
// Потоковый чат
for await (const chunk of sdk.chat.streamChat(messages, { projectId: 'your-project-id' })) {
console.log(chunk.text);
}
// 🧠 Chat с thinking (мышлением Claude)
const response = await sdk.chat.chat([
{ role: 'user', content: 'Объясни рекурсию подробно' }
], {
projectId: 'your-project-id',
thinking: {
type: 'enabled',
budget_tokens: 5000 // Бюджет для мышления
}
});
// 🧠 Потоковый чат с thinking и real-time выводом
for await (const chunk of sdk.chat.streamChat([
{ role: 'user', content: 'Проанализируй архитектуру проекта' }
], {
projectId: 'your-project-id',
thinking: {
type: 'enabled',
budget_tokens: 8000
},
onEvent: (type, data) => {
if (type === 'content_block_delta' && data.delta?.type === 'thinking_delta') {
console.log(`🧠 Думает: ${data.delta.thinking}`);
} else if (type === 'content_block_delta' && data.delta?.type === 'text_delta') {
console.log(`💬 Отвечает: ${data.delta.text}`);
}
}
})) {
if (chunk.text) {
process.stdout.write(chunk.text);
}
}
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000', // Обязательный
apiKey: 'your-api-key', // Рекомендуется
timeout: 30000, // Таймаут запросов
debug: false // Отладка
});
projectId
рекомендуется, но не обязателен в реализации:
// ✅ РАБОТАЕТ (но без контекста проекта)
const response = await sdk.chat.chat(messages);
// ✅ РЕКОМЕНДУЕТСЯ (с контекстом проекта)
const response = await sdk.chat.chat(messages, { projectId: 'your-project-id' });
// 💡 Получить projectId можно так:
const projects = await sdk.projects.getReadyProjects();
const projectId = projects[0].id;
# Все тесты
npm test
# Только HTTP тесты
npm test -- --testNamePattern="HTTP"
# Интеграционные тесты
npm run test:integration
# Тесты индексации
npm test -- --testPathPattern="indexing"
import { CodeSolverSDK } from 'solver-sdk';
async function fullWorkflow() {
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000'
});
try {
// 1. Создаем проект
const project = await sdk.projects.findOrCreateProject(
'/path/to/react-app',
'My React App'
);
// 2. Запускаем индексацию
console.log('Запуск индексации...');
await sdk.projects.startIndexing(project.id);
// 3. Ждем завершения индексации
console.log('Ожидание завершения индексации...');
while (true) {
const status = await sdk.projects.getIndexingStatus(project.id);
if (status.status === 'complete') break;
if (status.status === 'failed') throw new Error('Ошибка индексации: ' + status.error);
await new Promise(resolve => setTimeout(resolve, 2000));
}
// 4. Ищем React компоненты
const components = await sdk.search.searchCode(project.id, {
query: 'React.Component class',
limit: 10
});
// 5. Задаем вопрос AI о коду
const aiResponse = await sdk.chat.chat([
{
role: 'user',
content: `Проанализируй найденные React компоненты: ${JSON.stringify(components)}`
}
], { projectId: project.id });
console.log('✅ Анализ завершен');
console.log('📊 Компоненты:', components.results.length);
console.log('🤖 AI анализ:', aiResponse.content);
} catch (error) {
console.error('❌ Ошибка:', error.message);
}
}
fullWorkflow();
// ❌ СТАРАЯ ОШИБКА (до v3.1.5):
// CodeExpectedError: Method not found: toJSON
// ✅ РЕШЕНИЕ: Обновите SDK до последней версии
npm install solver-sdk@latest # v3.1.15
// ✅ Теперь все API возвращают JSON-совместимые объекты
const status = await sdk.projects.getIndexingStatus(projectId);
// Все Date объекты автоматически преобразуются в ISO строки
// Проверка здоровья API
const isHealthy = await sdk.checkHealth();
console.log('API доступен:', isHealthy);
// Увеличение таймаутов для больших проектов
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
timeout: 120000 // 2 минуты
});
MIT License
async function indexProject(projectPath, projectName) {
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000'
});
// 1. Создать/найти проект
const project = await sdk.projects.findOrCreateProject(projectPath, projectName);
// 2. Запустить индексацию
await sdk.projects.startIndexing(project.id);
// 3. Мониторинг прогресса
while (true) {
const status = await sdk.projects.getIndexingStatus(project.id);
if (status.status === 'complete') {
console.log('✅ Индексация завершена!');
break;
} else if (status.status === 'failed') {
console.log('❌ Ошибка:', status.error);
break;
}
console.log(`📊 Прогресс: ${status.progress || 0}%`);
await new Promise(resolve => setTimeout(resolve, 2000));
}
return project;
}
import { CodeSolverSDK } from 'solver-sdk';
import * as vscode from 'vscode';
let sdk: CodeSolverSDK;
export async function activate(context: vscode.ExtensionContext) {
sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000'
});
// Команда индексации
const indexCmd = vscode.commands.registerCommand('extension.indexProject', async () => {
const folder = vscode.workspace.workspaceFolders?.[0];
if (!folder) return;
return vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Индексация проекта',
cancellable: false
}, async (progress) => {
const project = await sdk.projects.findOrCreateProject(folder.uri.fsPath, folder.name);
await sdk.projects.startIndexing(project.id);
while (true) {
const status = await sdk.projects.getIndexingStatus(project.id);
if (status.status === 'complete') break;
progress.report({ message: `${status.progress || 0}%` });
await new Promise(resolve => setTimeout(resolve, 2000));
}
vscode.window.showInformationMessage('✅ Проект проиндексирован!');
});
});
// Команда поиска функций
const searchCmd = vscode.commands.registerCommand('extension.searchFunctions', async () => {
const query = await vscode.window.showInputBox({ prompt: 'Поиск функций' });
if (!query) return;
const projects = await sdk.projects.getReadyProjects();
if (projects.length === 0) return;
const response = await sdk.search.searchFunctions(projects[0].id, { query, limit: 20 });
if (!response.success || response.results.length === 0) {
vscode.window.showInformationMessage('Функции не найдены');
return;
}
const items = response.results.map(fn => ({
label: fn.name,
description: fn.signature,
detail: `${fn.filePath}:${fn.startLine}`,
function: fn
}));
const selected = await vscode.window.showQuickPick(items);
if (selected) {
const doc = await vscode.workspace.openTextDocument(selected.function.filePath);
const editor = await vscode.window.showTextDocument(doc);
const range = new vscode.Range(
selected.function.startLine - 1, 0,
selected.function.endLine - 1, 0
);
editor.selection = new vscode.Selection(range.start, range.end);
editor.revealRange(range, vscode.TextEditorRevealType.InCenter);
}
});
context.subscriptions.push(indexCmd, searchCmd);
}
// package.json для VS Code Extension
{
"contributes": {
"commands": [
{ "command": "extension.indexProject", "title": "📊 Индексировать проект" },
{ "command": "extension.searchFunctions", "title": "🔍 Поиск функций" }
]
},
"dependencies": { "solver-sdk": "^3.1.5" }
}
🎉 Один файл = полная документация!