| # Архитектурный Обзор: Kiro Gateway |
|
|
| ## 1. Назначение и Цели Системы |
|
|
| Проект представляет собой высокоуровневый прокси-шлюз, реализующий структурный паттерн проектирования **"Адаптер" (Adapter)**. |
|
|
| Основная цель системы — обеспечить прозрачную совместимость между несколькими гетерогенными интерфейсами: |
|
|
| ### Поддерживаемые API форматы |
|
|
| | API | Эндпоинты | Статус | |
| |-----|-----------|--------| |
| | **OpenAI** | `/v1/models`, `/v1/chat/completions` | ✅ Поддерживается | |
| | **Anthropic** | `/v1/messages` | ✅ Поддерживается | |
|
|
| ### Архитектурная модель |
|
|
| ``` |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ Клиенты │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │ OpenAI SDK/Tools │ │ Anthropic SDK/Tools │ │ |
| │ │ (Cursor, Cline, │ │ (Claude Code, │ │ |
| │ │ Continue, etc.) │ │ Anthropic SDK) │ │ |
| │ └──────────┬──────────┘ └──────────┬──────────┘ │ |
| └─────────────┼──────────────────────────────┼───────────────────┘ |
| │ │ |
| ▼ ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ Kiro Gateway │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │ OpenAI Adapter │ │ Anthropic Adapter │ │ |
| │ │ /v1/chat/... │ │ /v1/messages │ │ |
| │ └──────────┬──────────┘ └──────────┬──────────┘ │ |
| │ └──────────────┬───────────────┘ │ |
| │ ▼ │ |
| │ ┌─────────────────────────────┐ │ |
| │ │ Core Layer │ │ |
| │ │ (Общая логика конвертации) │ │ |
| │ └──────────────┬──────────────┘ │ |
| └────────────────────────────┼────────────────────────────────────┘ |
| │ |
| ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ Kiro API │ |
| │ (AWS CodeWhisperer Backend) │ |
| └─────────────────────────────────────────────────────────────────┘ |
| ``` |
|
|
| Система выступает в роли "переводчика", позволяя использовать любые инструменты, библиотеки и IDE-плагины, разработанные для экосистем OpenAI и Anthropic, с моделями Claude через Kiro API. |
|
|
| **Оба API работают одновременно** на одном сервере без необходимости переключения в настройках. |
|
|
| ## 2. Структура Проекта |
|
|
| Проект организован в виде модульного Python-пакета `kiro/`: |
|
|
| ``` |
| kiro-gateway/ |
| ├── main.py # Точка входа, создание FastAPI приложения |
| ├── requirements.txt # Зависимости Python |
| ├── .env.example # Пример конфигурации окружения |
| │ |
| ├── kiro/ # Основной пакет |
| │ ├── __init__.py # Экспорты пакета, версия |
| │ │ |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ │ # SHARED LAYER - Переиспользуется всеми API |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ ├── config.py # Конфигурация и константы |
| │ ├── auth.py # KiroAuthManager - управление токенами |
| │ ├── cache.py # ModelInfoCache - кэш моделей |
| │ ├── http_client.py # HTTP клиент с retry логикой |
| │ ├── parsers.py # Парсеры AWS SSE потоков |
| │ ├── utils.py # Вспомогательные утилиты |
| │ ├── tokenizer.py # Подсчёт токенов (tiktoken) |
| │ ├── debug_logger.py # Отладочное логирование запросов |
| │ ├── exceptions.py # Обработчики исключений |
| │ ├── thinking_parser.py # Парсер thinking блоков |
| │ │ |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ │ # CORE LAYER - Общее ядро для всех API |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ ├── converters_core.py # Общая логика построения Kiro payload |
| │ ├── streaming_core.py # Общая логика парсинга Kiro stream |
| │ │ |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ │ # OPENAI API LAYER |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ ├── models_openai.py # Pydantic модели OpenAI API |
| │ ├── converters_openai.py # OpenAI → Kiro адаптер |
| │ ├── routes_openai.py # FastAPI роуты OpenAI |
| │ ├── streaming_openai.py # Kiro → OpenAI SSE форматтер |
| │ │ |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ │ # ANTHROPIC API LAYER |
| │ │ # ═══════════════════════════════════════════════════════ |
| │ ├── models_anthropic.py # Pydantic модели Anthropic API |
| │ ├── converters_anthropic.py # Anthropic → Kiro адаптер |
| │ ├── routes_anthropic.py # FastAPI роуты Anthropic |
| │ └── streaming_anthropic.py # Kiro → Anthropic SSE форматтер |
| │ |
| ├── tests/ # Тесты |
| │ ├── conftest.py # Pytest fixtures |
| │ ├── unit/ # Юнит-тесты |
| │ └── integration/ # Интеграционные тесты |
| │ |
| ├── docs/ # Документация |
| │ ├── ru/ # Русская версия |
| │ └── en/ # Английская версия |
| │ |
| └── debug_logs/ # Отладочные логи (генерируются при DEBUG_LAST_REQUEST=true) |
| ``` |
|
|
| ### Принцип организации: Общее ядро + тонкие адаптеры |
|
|
| Архитектура построена на принципе **максимального переиспользования кода**: |
|
|
| | Слой | Назначение | Файлы | |
| |------|------------|-------| |
| | **Shared Layer** | Инфраструктура, не зависящая от формата API | `auth.py`, `http_client.py`, `cache.py`, `parsers.py`, `tokenizer.py` | |
| | **Core Layer** | Общая бизнес-логика конвертации | `converters_core.py`, `streaming_core.py` | |
| | **API Layer** | Тонкие адаптеры для конкретных форматов | `*_openai.py`, `*_anthropic.py` | |
|
|
| ## 3. Архитектурная Топология и Компоненты |
|
|
| Система построена на базе асинхронного фреймворка `FastAPI` и использует событийную модель управления жизненным циклом (`Lifespan Events`). |
|
|
| ### 3.1. Точка входа (`main.py`) |
|
|
| Файл `main.py` отвечает за: |
|
|
| 1. **Конфигурацию логирования** — настройка Loguru с цветным выводом |
| 2. **Валидацию конфигурации** — функция `validate_configuration()` проверяет: |
| - Наличие файла `.env` |
| - Наличие credentials (REFRESH_TOKEN или KIRO_CREDS_FILE) |
| 3. **Lifespan Manager** — создание и инициализация: |
| - `KiroAuthManager` для управления токенами |
| - `ModelInfoCache` для кэширования моделей |
| 4. **Регистрация обработчиков ошибок** — `validation_exception_handler` для ошибок 422 |
| 5. **Подключение роутов** — `app.include_router(router)` |
|
|
| ### 3.2. Модуль конфигурации (`kiro/config.py`) |
|
|
| Централизованное хранение всех настроек: |
|
|
| | Параметр | Описание | Значение по умолчанию | |
| |----------|----------|----------------------| |
| | `PROXY_API_KEY` | API ключ для доступа к прокси | `changeme_proxy_secret` | |
| | `REFRESH_TOKEN` | Refresh token Kiro | из `.env` | |
| | `PROFILE_ARN` | ARN профиля AWS CodeWhisperer | из `.env` | |
| | `REGION` | Регион AWS | `us-east-1` | |
| | `KIRO_CREDS_FILE` | Путь к JSON файлу credentials | из `.env` | |
| | `TOKEN_REFRESH_THRESHOLD` | Время до обновления токена | 600 сек (10 мин) | |
| | `MAX_RETRIES` | Макс. количество повторов | 3 | |
| | `BASE_RETRY_DELAY` | Базовая задержка retry | 1.0 сек | |
| | `MODEL_CACHE_TTL` | TTL кэша моделей | 3600 сек (1 час) | |
| | `DEFAULT_MAX_INPUT_TOKENS` | Макс. input токенов по умолчанию | 200000 | |
| | `TOOL_DESCRIPTION_MAX_LENGTH` | Макс. длина описания tool | 10000 символов | |
| | `DEBUG_LAST_REQUEST` | Включить отладочное логирование | `false` | |
| | `DEBUG_DIR` | Директория для debug логов | `debug_logs` | |
| | `APP_VERSION` | Версия приложения | `0.0.0` | |
|
|
| **Вспомогательные функции:** |
| - `get_kiro_refresh_url(region)` — URL для обновления токена |
| - `get_kiro_api_host(region)` — хост основного API |
| - `get_kiro_q_host(region)` — хост Q API |
| - `get_internal_model_id(external_model)` — конвертация имени модели |
|
|
| ### 3.3. Pydantic Модели (`kiro/models_openai.py`) |
| |
| #### Модели для `/v1/models` |
| |
| | Модель | Описание | |
| |--------|----------| |
| | `OpenAIModel` | Описание AI модели (id, object, created, owned_by) | |
| | `ModelList` | Список моделей для ответа endpoint | |
|
|
| #### Модели для `/v1/chat/completions` |
|
|
| | Модель | Описание | |
| |--------|----------| |
| | `ChatMessage` | Сообщение чата (role, content, tool_calls, tool_call_id) | |
| | `ToolFunction` | Описание функции инструмента (name, description, parameters) | |
| | `Tool` | Инструмент OpenAI формата (type, function) | |
| | `ChatCompletionRequest` | Запрос на генерацию (model, messages, stream, tools, ...) | |
| |
| #### Модели ответов |
| |
| | Модель | Описание | |
| |--------|----------| |
| | `ChatCompletionChoice` | Один вариант ответа | |
| | `ChatCompletionUsage` | Информация о токенах (prompt_tokens, completion_tokens, credits_used) | |
| | `ChatCompletionResponse` | Полный ответ (non-streaming) | |
| | `ChatCompletionChunk` | Streaming chunk | |
| | `ChatCompletionChunkDelta` | Дельта изменений в chunk | |
| | `ChatCompletionChunkChoice` | Вариант в streaming chunk | |
|
|
| ### 3.4. Управление Состоянием (State Management Layer) |
|
|
| #### KiroAuthManager (`kiro/auth.py`) |
|
|
| **Роль:** Stateful-синглтон, инкапсулирующий логику управления токенами Kiro. |
|
|
| **Возможности:** |
| - Загрузка credentials из `.env` или JSON файла |
| - Поддержка `expiresAt` для проверки времени истечения токена |
| - Автоматическое обновление токена за 10 минут до истечения |
| - Сохранение обновлённых токенов обратно в JSON файл |
| - Поддержка разных регионов AWS |
| - Генерация уникального fingerprint для User-Agent |
|
|
| **Concurrency Control:** Использует `asyncio.Lock` для защиты от состояния гонки. |
|
|
| **Основные методы:** |
| - `get_access_token()` — возвращает действительный токен, обновляя при необходимости |
| - `force_refresh()` — принудительное обновление токена (при 403) |
| - `is_token_expiring_soon()` — проверка времени истечения |
|
|
| **Properties:** |
| - `profile_arn` — ARN профиля |
| - `region` — регион AWS |
| - `api_host` — хост API для региона |
| - `q_host` — хост Q API для региона |
| - `fingerprint` — уникальный fingerprint машины |
|
|
| ```python |
| # Пример использования |
| auth_manager = KiroAuthManager( |
| refresh_token="your_token", |
| region="us-east-1", |
| creds_file="~/.aws/sso/cache/kiro-auth-token.json" |
| ) |
| token = await auth_manager.get_access_token() |
| ``` |
|
|
| #### ModelInfoCache (`kiro/cache.py`) |
|
|
| **Роль:** Потокобезопасное хранилище конфигураций моделей. |
|
|
| **Стратегия Заполнения:** |
| - Lazy Loading через `/ListAvailableModels` |
| - TTL кэша: 1 час |
| - Fallback на статический список моделей |
|
|
| **Основные методы:** |
| - `update(models_data)` — обновление кэша |
| - `get(model_id)` — получение информации о модели |
| - `get_max_input_tokens(model_id)` — получение лимита токенов |
| - `is_empty()` / `is_stale()` — проверка состояния кэша |
| - `get_all_model_ids()` — список всех ID моделей |
|
|
| ### 3.5. Вспомогательные Утилиты (`kiro/utils.py`) |
|
|
| | Функция | Описание | |
| |---------|----------| |
| | `get_machine_fingerprint()` | SHA256 хеш `{hostname}-{username}-kiro-gateway` | |
| | `get_kiro_headers(auth_manager, token)` | Формирование заголовков для Kiro API | |
| | `generate_completion_id()` | ID в формате `chatcmpl-{uuid_hex}` | |
| | `generate_conversation_id()` | UUID для разговора | |
| | `generate_tool_call_id()` | ID в формате `call_{uuid_hex[:8]}` | |
|
|
| ### 3.6. Слой Конвертации (`kiro/converters_openai.py`) |
| |
| #### Конвертация сообщений |
| |
| OpenAI messages преобразуются в Kiro conversationState: |
| |
| 1. **System prompt** — добавляется к первому user сообщению |
| 2. **История сообщений** — полностью передаётся в `history` array |
| 3. **Объединение соседних сообщений** — сообщения с одинаковой ролью мерджатся |
| 4. **Tool calls** — поддержка OpenAI tools формата |
| 5. **Tool results** — корректная передача результатов вызова инструментов |
| |
| #### Обработка длинных описаний Tools |
| |
| **Проблема:** Kiro API возвращает ошибку 400 при слишком длинных описаниях в `toolSpecification.description`. |
| |
| **Решение:** Tool Documentation Reference Pattern |
| - Если `description ≤ TOOL_DESCRIPTION_MAX_LENGTH` → оставляем как есть |
| - Если `description > TOOL_DESCRIPTION_MAX_LENGTH`: |
| * В `toolSpecification.description` → ссылка: `"[Full documentation in system prompt under '## Tool: {name}']"` |
| * В system prompt добавляется секция `"## Tool: {name}"` с полным описанием |
|
|
| **Функция:** `process_tools_with_long_descriptions(tools)` → `(processed_tools, tool_documentation)` |
|
|
| #### Основные функции |
|
|
| | Функция | Описание | |
| |---------|----------| |
| | `extract_text_content(content)` | Извлечение текста из различных форматов | |
| | `merge_adjacent_messages(messages)` | Объединение соседних сообщений с одной ролью | |
| | `build_kiro_history(messages, model_id)` | Построение массива history для Kiro | |
| | `build_kiro_payload(request_data, conversation_id, profile_arn)` | Полный payload для запроса | |
|
|
| #### Маппинг моделей |
|
|
| Внешние имена моделей преобразуются во внутренние ID Kiro: |
|
|
| | Внешнее имя | Внутренний ID Kiro | |
| |-------------|-------------------| |
| | `claude-opus-4-5` | `claude-opus-4.5` | |
| | `claude-opus-4-5-20251101` | `claude-opus-4.5` | |
| | `claude-haiku-4-5` | `claude-haiku-4.5` | |
| | `claude-haiku-4.5` | `claude-haiku-4.5` (прямой проброс) | |
| | `claude-sonnet-4-5` | `CLAUDE_SONNET_4_5_20250929_V1_0` | |
| | `claude-sonnet-4-5-20250929` | `CLAUDE_SONNET_4_5_20250929_V1_0` | |
| | `claude-sonnet-4` | `CLAUDE_SONNET_4_20250514_V1_0` | |
| | `claude-sonnet-4-20250514` | `CLAUDE_SONNET_4_20250514_V1_0` | |
| | `claude-3-7-sonnet-20250219` | `CLAUDE_3_7_SONNET_20250219_V1_0` | |
| | `auto` | `claude-sonnet-4.5` (алиас) | |
|
|
| ### 3.7. Слой Парсинга (`kiro/parsers.py`) |
|
|
| #### AwsEventStreamParser |
|
|
| Продвинутый парсер AWS SSE формата с поддержкой: |
|
|
| - **Bracket counting** — корректный парсинг вложенных JSON объектов |
| - **Дедупликация контента** — фильтрация повторяющихся событий |
| - **Tool calls** — парсинг структурированных и bracket-style tool calls |
| - **Escape-последовательности** — декодирование `\n` и других |
|
|
| #### Типы событий |
|
|
| | Событие | Описание | |
| |---------|----------| |
| | `content` | Текстовый контент ответа | |
| | `tool_start` | Начало tool call (name, toolUseId) | |
| | `tool_input` | Продолжение input для tool call | |
| | `tool_stop` | Завершение tool call | |
| | `usage` | Информация о потреблении кредитов | |
| | `context_usage` | Процент использования контекста | |
|
|
| #### Вспомогательные функции |
|
|
| | Функция | Описание | |
| |---------|----------| |
| | `find_matching_brace(text, start_pos)` | Поиск закрывающей скобки с учётом вложенности | |
| | `parse_bracket_tool_calls(response_text)` | Парсинг `[Called func with args: {...}]` | |
| | `deduplicate_tool_calls(tool_calls)` | Удаление дубликатов tool calls | |
|
|
| ### 3.8. Streaming (`kiro/streaming_openai.py`) |
| |
| #### stream_kiro_to_openai |
|
|
| Асинхронный генератор для преобразования потока Kiro в OpenAI формат. |
|
|
| **Функциональность:** |
| - Парсинг AWS SSE stream через `AwsEventStreamParser` |
| - Формирование OpenAI `chat.completion.chunk` |
| - Обработка tool calls (структурированных и bracket-style) |
| - Вычисление usage на основе `contextUsagePercentage` |
| - Отладочное логирование через `debug_logger` |
|
|
| #### collect_stream_response |
|
|
| Собирает полный ответ из streaming потока для non-streaming режима. |
|
|
| ### 3.9. HTTP Клиент (`kiro/http_client.py`) |
| |
| #### KiroHttpClient |
| |
| Автоматическая обработка ошибок с exponential backoff: |
| |
| | Код ошибки | Действие | |
| |------------|----------| |
| | `403` | Refresh токена через `force_refresh()` + повтор | |
| | `429` | Exponential backoff: `BASE_RETRY_DELAY * (2 ** attempt)` | |
| | `5xx` | Exponential backoff (до MAX_RETRIES попыток) | |
| | Timeout | Exponential backoff | |
| |
| **Формула задержки:** `1s, 2s, 4s` (при `BASE_RETRY_DELAY=1.0`) |
| |
| **Методы:** |
| - `request_with_retry(method, url, json_data, stream)` — запрос с retry |
| - `close()` — закрытие клиента |
|
|
| Поддерживает async context manager (`async with`). |
|
|
| ### 3.10. Роуты (`kiro/routes_openai.py`) |
| |
| | Endpoint | Метод | Описание | |
| |----------|-------|----------| |
| | `/` | GET | Health check (status, message, version) | |
| | `/health` | GET | Детальный health check (status, timestamp, version) | |
| | `/v1/models` | GET | Список доступных моделей (требует API key) | |
| | `/v1/chat/completions` | POST | Chat completions (требует API key) | |
| |
| **Аутентификация:** Bearer token в заголовке `Authorization` |
| |
| ### 3.11. Обработка Исключений (`kiro/exceptions.py`) |
| |
| | Функция | Описание | |
| |---------|----------| |
| | `sanitize_validation_errors(errors)` | Конвертация bytes в строки для JSON-сериализации | |
| | `validation_exception_handler(request, exc)` | Обработчик ошибок валидации Pydantic (422) | |
| |
| ### 3.12. Отладочное Логирование (`kiro/debug_logger.py`) |
|
|
| **Класс:** `DebugLogger` (синглтон) |
|
|
| **Активация:** `DEBUG_LAST_REQUEST=true` в `.env` |
|
|
| **Методы:** |
| | Метод | Описание | |
| |-------|----------| |
| | `prepare_new_request()` | Очистка директории для нового запроса | |
| | `log_request_body(body)` | Сохранение входящего запроса | |
| | `log_kiro_request_body(body)` | Сохранение запроса к Kiro API | |
| | `log_raw_chunk(chunk)` | Дописывание сырого chunk от Kiro | |
| | `log_modified_chunk(chunk)` | Дописывание преобразованного chunk | |
|
|
| **Файлы в `debug_logs/`:** |
| - `request_body.json` — входящий запрос (OpenAI формат) |
| - `kiro_request_body.json` — запрос к Kiro API |
| - `response_stream_raw.txt` — сырой поток от Kiro |
| - `response_stream_modified.txt` — преобразованный поток (OpenAI формат) |
| |
| ### 3.13. Токенизатор (`kiro/tokenizer.py`) |
| |
| **Проблема:** Kiro API не возвращает напрямую количество токенов. Вместо этого API предоставляет только `context_usage_percentage` — процент использования контекста модели. |
|
|
| **Решение:** Модуль токенизатора на базе `tiktoken` (библиотека OpenAI на Rust) для быстрого подсчёта токенов. |
|
|
| **Особенности:** |
| - Использует кодировку `cl100k_base` (GPT-4), близкую к токенизации Claude |
| - Коэффициент коррекции `CLAUDE_CORRECTION_FACTOR = 1.15` для повышения точности |
| - Ленивая инициализация для ускорения импорта |
| - Fallback на грубую оценку если tiktoken недоступен |
|
|
| **Формула расчёта токенов в ответе:** |
| ``` |
| total_tokens = context_usage_percentage × max_input_tokens (от API Kiro) |
| completion_tokens = tiktoken(ответ) (наш подсчёт) |
| prompt_tokens = total_tokens - completion_tokens (вычитание) |
| ``` |
|
|
| **Основные функции:** |
|
|
| | Функция | Описание | |
| |---------|----------| |
| | `count_tokens(text)` | Подсчёт токенов в тексте | |
| | `count_message_tokens(messages)` | Подсчёт токенов в списке сообщений | |
| | `count_tools_tokens(tools)` | Подсчёт токенов в определениях инструментов | |
| | `estimate_request_tokens(messages, tools)` | Полная оценка токенов запроса | |
|
|
| **Дебаг-лог:** |
| ``` |
| [Usage] claude-opus-4-5: prompt_tokens=142211 (subtraction), completion_tokens=769 (tiktoken), total_tokens=142980 (API Kiro) |
| ``` |
|
|
| **Точность:** ~97-99.7% по сравнению с данными от API. |
|
|
| ### 3.14. Kiro API Endpoints |
|
|
| Все URL динамически формируются на основе региона: |
|
|
| * **Token Refresh:** `POST https://prod.{region}.auth.desktop.kiro.dev/refreshToken` |
| * **List Models:** `GET https://q.{region}.amazonaws.com/ListAvailableModels` |
| * **Generate Response:** `POST https://codewhisperer.{region}.amazonaws.com/generateAssistantResponse` |
|
|
| ## 4. Детальный Поток Данных |
|
|
| ### 4.1 Общая схема (мульти-API) |
|
|
| ``` |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ КЛИЕНТЫ │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │ OpenAI Client │ │ Anthropic Client │ │ |
| │ └──────────┬──────────┘ └──────────┬──────────┘ │ |
| └─────────────┼──────────────────────────────┼───────────────────┘ |
| │ │ |
| │ POST /v1/chat/completions │ POST /v1/messages |
| ▼ ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ API LAYER │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │ routes_openai.py │ │ routes_anthropic.py │ │ |
| │ │ Security Gate │ │ Security Gate │ │ |
| │ └──────────┬──────────┘ └──────────┬──────────┘ │ |
| │ │ │ │ |
| │ ▼ ▼ │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │converters_openai.py │ │converters_anthropic │ │ |
| │ │ Извлечение system │ │ System уже отдельно │ │ |
| │ │ из messages │ │ в запросе │ │ |
| │ └──────────┬──────────┘ └──────────┬──────────┘ │ |
| └─────────────┼──────────────────────────────┼───────────────────┘ |
| │ │ |
| └──────────────┬───────────────┘ |
| │ |
| ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ CORE LAYER │ |
| │ ┌─────────────────────────────┐ │ |
| │ │ converters_core.py │ │ |
| │ │ build_kiro_payload() │ │ |
| │ │ build_kiro_history() │ │ |
| │ │ process_tools() │ │ |
| │ └──────────────┬──────────────┘ │ |
| └────────────────────────────┼────────────────────────────────────┘ |
| │ |
| ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ SHARED LAYER │ |
| │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ |
| │ │ KiroAuthManager │ │ KiroHttpClient │ │ ModelInfoCache │ │ |
| │ │ (auth.py) │ │(http_client.py) │ │ (cache.py) │ │ |
| │ └────────┬────────┘ └────────┬────────┘ └─────────────────┘ │ |
| └───────────┼────────────────────┼────────────────────────────────┘ |
| │ │ |
| │ │ POST /generateAssistantResponse |
| │ ▼ |
| │ ┌─────────────────────────────────────────┐ |
| │ │ Kiro API │ |
| │ └──────────────────┬──────────────────────┘ |
| │ │ |
| │ │ AWS SSE Stream |
| │ ▼ |
| ┌───────────┼────────────────────────────────────────────────────┐ |
| │ │ CORE LAYER │ |
| │ │ ┌─────────────────────────────┐ │ |
| │ │ │ streaming_core.py │ │ |
| │ │ │ parse_kiro_stream() │ │ |
| │ │ │ → KiroEvent objects │ │ |
| │ │ └──────────────┬──────────────┘ │ |
| └────────────────────────────┼───────────────────────────────────┘ |
| │ |
| ┌──────────────┴───────────────┐ |
| │ │ |
| ▼ ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ OUTPUT LAYER │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │streaming_openai.py │ │streaming_anthropic │ │ |
| │ │ format_openai_sse() │ │format_anthropic_sse │ │ |
| │ │ │ │ │ │ |
| │ │ data: {...} │ │ event: type │ │ |
| │ │ data: [DONE] │ │ data: {...} │ │ |
| │ └──────────┬──────────┘ └──────────┬──────────┘ │ |
| └─────────────┼──────────────────────────────┼───────────────────┘ |
| │ │ |
| ▼ ▼ |
| ┌─────────────────────────────────────────────────────────────────┐ |
| │ КЛИЕНТЫ │ |
| │ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| │ │ OpenAI Client │ │ Anthropic Client │ │ |
| │ └─────────────────────┘ └─────────────────────┘ │ |
| └─────────────────────────────────┘ |
| ``` |
|
|
| ### 4.2 Поток OpenAI API |
|
|
| ``` |
| OpenAI Client |
| │ POST /v1/chat/completions |
| ▼ |
| routes_openai.py ──► converters_openai.py ──► converters_core.py |
| │ │ |
| │ ▼ |
| │ Kiro Payload |
| │ │ |
| ▼ ▼ |
| KiroAuthManager ──────────────────────────► KiroHttpClient |
| │ |
| ▼ |
| Kiro API |
| │ |
| ▼ |
| streaming_core.py ◄─────────────────────── AWS SSE Stream |
| │ |
| ▼ |
| streaming_openai.py |
| │ |
| ▼ |
| OpenAI SSE Format ──────────────────────► OpenAI Client |
| ``` |
|
|
| ### 4.3 Поток Anthropic API |
|
|
| ``` |
| Anthropic Client |
| │ POST /v1/messages |
| ▼ |
| routes_anthropic.py ──► converters_anthropic.py ──► converters_core.py |
| │ │ |
| │ ▼ |
| │ Kiro Payload |
| │ │ |
| ▼ ▼ |
| KiroAuthManager ──────────────────────────────────► KiroHttpClient |
| │ |
| ▼ |
| Kiro API |
| │ |
| ▼ |
| streaming_core.py ◄─────────────────────────────── AWS SSE Stream |
| │ |
| ▼ |
| streaming_anthropic.py |
| │ |
| ▼ |
| Anthropic SSE Format ──────────────────────────► Anthropic Client |
| ``` |
|
|
| ## 5. Доступные Модели |
|
|
| | Модель | Описание | Credits | |
| |--------|----------|---------| |
| | `claude-opus-4-5` | Топовая модель | ~2.2 | |
| | `claude-opus-4-5-20251101` | Топовая модель (версия) | ~2.2 | |
| | `claude-sonnet-4-5` | Улучшенная модель | ~1.3 | |
| | `claude-sonnet-4-5-20250929` | Улучшенная модель (версия) | ~1.3 | |
| | `claude-sonnet-4` | Сбалансированная модель | ~1.3 | |
| | `claude-sonnet-4-20250514` | Сбалансированная (версия) | ~1.3 | |
| | `claude-haiku-4-5` | Быстрая модель | ~0.4 | |
| | `claude-3-7-sonnet-20250219` | Legacy модель | ~1.0 | |
|
|
| ## 6. Конфигурация |
|
|
| ### Переменные окружения (.env) |
|
|
| ```env |
| # Обязательные |
| REFRESH_TOKEN="your_kiro_refresh_token" |
| PROXY_API_KEY="your_proxy_secret" |
| |
| # Опциональные |
| PROFILE_ARN="arn:aws:codewhisperer:..." |
| KIRO_REGION="us-east-1" |
| KIRO_CREDS_FILE="~/.aws/sso/cache/kiro-auth-token.json" |
| |
| # Отладка |
| DEBUG_LAST_REQUEST="false" |
| DEBUG_DIR="debug_logs" |
| |
| # Лимиты |
| TOOL_DESCRIPTION_MAX_LENGTH="10000" |
| ``` |
|
|
| ### JSON файл credentials (опционально) |
|
|
| ```json |
| { |
| "accessToken": "eyJ...", |
| "refreshToken": "eyJ...", |
| "expiresAt": "2025-01-12T23:00:00.000Z", |
| "profileArn": "arn:aws:codewhisperer:us-east-1:...", |
| "region": "us-east-1" |
| } |
| ``` |
|
|
| ## 7. API Endpoints |
|
|
| ### 7.1 Общие эндпоинты |
|
|
| | Endpoint | Метод | Описание | |
| |----------|-------|----------| |
| | `/` | GET | Health check | |
| | `/health` | GET | Детальный health check | |
|
|
| ### 7.2 OpenAI-совместимые эндпоинты |
|
|
| | Endpoint | Метод | Описание | |
| |----------|-------|----------| |
| | `/v1/models` | GET | Список доступных моделей | |
| | `/v1/chat/completions` | POST | Chat completions (streaming/non-streaming) | |
|
|
| **Аутентификация:** `Authorization: Bearer {PROXY_API_KEY}` |
|
|
| ### 7.3 Anthropic-совместимые эндпоинты |
|
|
| | Endpoint | Метод | Описание | |
| |----------|-------|----------| |
| | `/v1/messages` | POST | Messages API (streaming/non-streaming) | |
|
|
| **Аутентификация:** `x-api-key: {PROXY_API_KEY}` + `anthropic-version: 2023-06-01` |
|
|
| ### 7.4 Сравнение форматов |
|
|
| | Аспект | OpenAI | Anthropic | |
| |--------|--------|-----------| |
| | System prompt | В `messages` с `role: "system"` | Отдельное поле `system` | |
| | Content | Строка или массив | Всегда массив content blocks | |
| | Stop reason | `finish_reason: "stop"` | `stop_reason: "end_turn"` | |
| | Usage | `prompt_tokens`, `completion_tokens` | `input_tokens`, `output_tokens` | |
| | Streaming | `data: {...}\n\n` + `data: [DONE]` | `event: type\ndata: {...}\n\n` | |
| | Tool format | `{type: "function", function: {...}}` | `{name: "...", input_schema: {...}}` | |
|
|
| ## 8. Особенности Реализации |
|
|
| ### Tool Calling |
|
|
| Поддержка OpenAI-совместимого формата tools: |
|
|
| ```json |
| { |
| "tools": [{ |
| "type": "function", |
| "function": { |
| "name": "get_weather", |
| "description": "Get weather for a location", |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "location": {"type": "string"} |
| } |
| } |
| } |
| }] |
| } |
| ``` |
|
|
| ### Streaming |
|
|
| Полная поддержка SSE streaming с корректным форматом OpenAI: |
|
|
| ``` |
| data: {"id":"chatcmpl-...","object":"chat.completion.chunk",...} |
| |
| data: [DONE] |
| ``` |
|
|
| ### Отладка |
|
|
| При `DEBUG_LAST_REQUEST=true` все запросы и ответы логируются в `debug_logs/`: |
| - `request_body.json` — входящий запрос |
| - `kiro_request_body.json` — запрос к Kiro API |
| - `response_stream_raw.txt` — сырой поток от Kiro |
| - `response_stream_modified.txt` — преобразованный поток |
|
|
| ## 9. Расширяемость |
|
|
| ### Добавление нового API формата |
|
|
| Модульная архитектура позволяет легко добавить поддержку других API форматов. Благодаря Core Layer, большая часть логики уже реализована. |
|
|
| #### Шаги для добавления нового формата (например, Gemini) |
|
|
| 1. **Создать модели** — `models_gemini.py` |
| ```python |
| class GeminiRequest(BaseModel): |
| """Pydantic модель запроса Gemini.""" |
| contents: List[GeminiContent] |
| ... |
| ``` |
|
|
| 2. **Создать адаптер конвертации** — `converters_gemini.py` |
| ```python |
| from kiro.converters_core import build_kiro_payload |
| |
| def gemini_to_kiro(request: GeminiRequest, ...) -> dict: |
| """Конвертирует Gemini запрос в Kiro payload.""" |
| # Извлекаем данные из Gemini формата |
| system_prompt = extract_system_instruction(request) |
| messages = convert_gemini_contents(request.contents) |
| tools = convert_gemini_tools(request.tools) |
| |
| # Используем общее ядро |
| return build_kiro_payload( |
| messages=messages, |
| system_prompt=system_prompt, |
| tools=tools, |
| ... |
| ) |
| ``` |
|
|
| 3. **Создать форматтер streaming** — `streaming_gemini.py` |
| ```python |
| from kiro.streaming_core import parse_kiro_stream |
| |
| async def stream_to_gemini(response, ...) -> AsyncGenerator[str, None]: |
| """Форматирует Kiro события в Gemini SSE.""" |
| async for event in parse_kiro_stream(response): |
| yield format_gemini_chunk(event) |
| ``` |
|
|
| 4. **Создать роуты** — `routes_gemini.py` |
| ```python |
| router = APIRouter() |
| |
| @router.post("/v1beta/models/{model}:generateContent") |
| async def generate_content(request: GeminiRequest): |
| ... |
| ``` |
|
|
| 5. **Подключить в main.py** |
| ```python |
| from kiro.routes_gemini import router as gemini_router |
| app.include_router(gemini_router) |
| ``` |
|
|
| ### Что переиспользуется автоматически |
|
|
| При добавлении нового формата следующие компоненты работают "из коробки": |
|
|
| | Компонент | Функциональность | |
| |-----------|------------------| |
| | `auth.py` | Управление токенами Kiro | |
| | `http_client.py` | HTTP с retry логикой | |
| | `cache.py` | Кэш моделей | |
| | `parsers.py` | Парсинг AWS SSE | |
| | `tokenizer.py` | Подсчёт токенов | |
| | `converters_core.py` | Построение Kiro payload | |
| | `streaming_core.py` | Парсинг Kiro stream | |
|
|
| ## 10. Зависимости |
|
|
| Основные зависимости проекта (из `requirements.txt`): |
|
|
| | Пакет | Назначение | |
| |-------|------------| |
| | `fastapi` | Асинхронный веб-фреймворк | |
| | `uvicorn` | ASGI сервер | |
| | `httpx` | Асинхронный HTTP клиент | |
| | `pydantic` | Валидация данных и модели | |
| | `python-dotenv` | Загрузка переменных окружения | |
| | `loguru` | Продвинутое логирование | |
| | `tiktoken` | Быстрый подсчёт токенов | |
|
|