jwadow commited on
Commit
f1668d0
·
1 Parent(s): 9a5fa46

refactor: update kiro_gateway naming to kiro

Browse files
docs/en/ARCHITECTURE.md CHANGED
@@ -53,7 +53,7 @@ The system acts as a "translator", allowing the use of any tools, libraries, and
53
 
54
  ## 2. Project Structure
55
 
56
- The project is organized as a modular Python package `kiro_gateway/`:
57
 
58
  ```
59
  kiro-gateway/
@@ -61,7 +61,7 @@ kiro-gateway/
61
  ├── requirements.txt # Python dependencies
62
  ├── .env.example # Environment configuration example
63
 
64
- ├── kiro_gateway/ # Main package
65
  │ ├── __init__.py # Package exports, version
66
  │ │
67
  │ │ # ═══════════════════════════════════════════════════════
@@ -140,7 +140,7 @@ The `main.py` file is responsible for:
140
  4. **Error handler registration** — `validation_exception_handler` for 422 errors
141
  5. **Route connection** — `app.include_router(router)`
142
 
143
- ### 3.2. Configuration Module (`kiro_gateway/config.py`)
144
 
145
  Centralized storage of all settings:
146
 
@@ -167,7 +167,7 @@ Centralized storage of all settings:
167
  - `get_kiro_q_host(region)` — Q API host
168
  - `get_internal_model_id(external_model)` — model name conversion
169
 
170
- ### 3.3. Pydantic Models (`kiro_gateway/models.py`)
171
 
172
  #### Models for `/v1/models`
173
 
@@ -198,7 +198,7 @@ Centralized storage of all settings:
198
 
199
  ### 3.4. State Management Layer
200
 
201
- #### KiroAuthManager (`kiro_gateway/auth.py`)
202
 
203
  **Role:** Stateful singleton encapsulating Kiro token management logic.
204
 
@@ -234,7 +234,7 @@ auth_manager = KiroAuthManager(
234
  token = await auth_manager.get_access_token()
235
  ```
236
 
237
- #### ModelInfoCache (`kiro_gateway/cache.py`)
238
 
239
  **Role:** Thread-safe storage for model configurations.
240
 
@@ -250,7 +250,7 @@ token = await auth_manager.get_access_token()
250
  - `is_empty()` / `is_stale()` — cache state check
251
  - `get_all_model_ids()` — list of all model IDs
252
 
253
- ### 3.5. Helper Utilities (`kiro_gateway/utils.py`)
254
 
255
  | Function | Description |
256
  |----------|-------------|
@@ -260,7 +260,7 @@ token = await auth_manager.get_access_token()
260
  | `generate_conversation_id()` | UUID for conversation |
261
  | `generate_tool_call_id()` | ID in format `call_{uuid_hex[:8]}` |
262
 
263
- ### 3.6. Conversion Layer (`kiro_gateway/converters.py`)
264
 
265
  #### Message Conversion
266
 
@@ -310,7 +310,7 @@ External model names are converted to internal Kiro IDs:
310
  | `claude-3-7-sonnet-20250219` | `CLAUDE_3_7_SONNET_20250219_V1_0` |
311
  | `auto` | `claude-sonnet-4.5` (alias) |
312
 
313
- ### 3.7. Parsing Layer (`kiro_gateway/parsers.py`)
314
 
315
  #### AwsEventStreamParser
316
 
@@ -340,7 +340,7 @@ Advanced AWS SSE format parser with support for:
340
  | `parse_bracket_tool_calls(response_text)` | Parse `[Called func with args: {...}]` |
341
  | `deduplicate_tool_calls(tool_calls)` | Remove duplicate tool calls |
342
 
343
- ### 3.8. Streaming (`kiro_gateway/streaming.py`)
344
 
345
  #### stream_kiro_to_openai
346
 
@@ -357,7 +357,7 @@ Async generator for transforming Kiro stream to OpenAI format.
357
 
358
  Collects full response from streaming for non-streaming mode.
359
 
360
- ### 3.9. HTTP Client (`kiro_gateway/http_client.py`)
361
 
362
  #### KiroHttpClient
363
 
@@ -378,7 +378,7 @@ Automatic error handling with exponential backoff:
378
 
379
  Supports async context manager (`async with`).
380
 
381
- ### 3.10. Routes (`kiro_gateway/routes.py`)
382
 
383
  | Endpoint | Method | Description |
384
  |----------|--------|-------------|
@@ -389,14 +389,14 @@ Supports async context manager (`async with`).
389
 
390
  **Authentication:** Bearer token in `Authorization` header
391
 
392
- ### 3.11. Exception Handling (`kiro_gateway/exceptions.py`)
393
 
394
  | Function | Description |
395
  |----------|-------------|
396
  | `sanitize_validation_errors(errors)` | Convert bytes to strings for JSON serialization |
397
  | `validation_exception_handler(request, exc)` | Pydantic validation error handler (422) |
398
 
399
- ### 3.12. Debug Logging (`kiro_gateway/debug_logger.py`)
400
 
401
  **Class:** `DebugLogger` (singleton)
402
 
@@ -417,7 +417,7 @@ Supports async context manager (`async with`).
417
  - `response_stream_raw.txt` — raw stream from Kiro
418
  - `response_stream_modified.txt` — transformed stream (OpenAI format)
419
 
420
- ### 3.13. Tokenizer (`kiro_gateway/tokenizer.py`)
421
 
422
  **Problem:** Kiro API does not return token counts directly. Instead, the API only provides `context_usage_percentage` — the percentage of model context usage.
423
 
@@ -749,7 +749,7 @@ The modular architecture allows easy addition of support for other API formats.
749
 
750
  2. **Create conversion adapter** — `converters_gemini.py`
751
  ```python
752
- from kiro_gateway.converters_core import build_kiro_payload
753
 
754
  def gemini_to_kiro(request: GeminiRequest, ...) -> dict:
755
  """Converts Gemini request to Kiro payload."""
@@ -769,7 +769,7 @@ The modular architecture allows easy addition of support for other API formats.
769
 
770
  3. **Create streaming formatter** — `streaming_gemini.py`
771
  ```python
772
- from kiro_gateway.streaming_core import parse_kiro_stream
773
 
774
  async def stream_to_gemini(response, ...) -> AsyncGenerator[str, None]:
775
  """Formats Kiro events to Gemini SSE."""
@@ -788,7 +788,7 @@ The modular architecture allows easy addition of support for other API formats.
788
 
789
  5. **Connect in main.py**
790
  ```python
791
- from kiro_gateway.routes_gemini import router as gemini_router
792
  app.include_router(gemini_router)
793
  ```
794
 
 
53
 
54
  ## 2. Project Structure
55
 
56
+ The project is organized as a modular Python package `kiro/`:
57
 
58
  ```
59
  kiro-gateway/
 
61
  ├── requirements.txt # Python dependencies
62
  ├── .env.example # Environment configuration example
63
 
64
+ ├── kiro/ # Main package
65
  │ ├── __init__.py # Package exports, version
66
  │ │
67
  │ │ # ═══════════════════════════════════════════════════════
 
140
  4. **Error handler registration** — `validation_exception_handler` for 422 errors
141
  5. **Route connection** — `app.include_router(router)`
142
 
143
+ ### 3.2. Configuration Module (`kiro/config.py`)
144
 
145
  Centralized storage of all settings:
146
 
 
167
  - `get_kiro_q_host(region)` — Q API host
168
  - `get_internal_model_id(external_model)` — model name conversion
169
 
170
+ ### 3.3. Pydantic Models (`kiro/models.py`)
171
 
172
  #### Models for `/v1/models`
173
 
 
198
 
199
  ### 3.4. State Management Layer
200
 
201
+ #### KiroAuthManager (`kiro/auth.py`)
202
 
203
  **Role:** Stateful singleton encapsulating Kiro token management logic.
204
 
 
234
  token = await auth_manager.get_access_token()
235
  ```
236
 
237
+ #### ModelInfoCache (`kiro/cache.py`)
238
 
239
  **Role:** Thread-safe storage for model configurations.
240
 
 
250
  - `is_empty()` / `is_stale()` — cache state check
251
  - `get_all_model_ids()` — list of all model IDs
252
 
253
+ ### 3.5. Helper Utilities (`kiro/utils.py`)
254
 
255
  | Function | Description |
256
  |----------|-------------|
 
260
  | `generate_conversation_id()` | UUID for conversation |
261
  | `generate_tool_call_id()` | ID in format `call_{uuid_hex[:8]}` |
262
 
263
+ ### 3.6. Conversion Layer (`kiro/converters.py`)
264
 
265
  #### Message Conversion
266
 
 
310
  | `claude-3-7-sonnet-20250219` | `CLAUDE_3_7_SONNET_20250219_V1_0` |
311
  | `auto` | `claude-sonnet-4.5` (alias) |
312
 
313
+ ### 3.7. Parsing Layer (`kiro/parsers.py`)
314
 
315
  #### AwsEventStreamParser
316
 
 
340
  | `parse_bracket_tool_calls(response_text)` | Parse `[Called func with args: {...}]` |
341
  | `deduplicate_tool_calls(tool_calls)` | Remove duplicate tool calls |
342
 
343
+ ### 3.8. Streaming (`kiro/streaming.py`)
344
 
345
  #### stream_kiro_to_openai
346
 
 
357
 
358
  Collects full response from streaming for non-streaming mode.
359
 
360
+ ### 3.9. HTTP Client (`kiro/http_client.py`)
361
 
362
  #### KiroHttpClient
363
 
 
378
 
379
  Supports async context manager (`async with`).
380
 
381
+ ### 3.10. Routes (`kiro/routes.py`)
382
 
383
  | Endpoint | Method | Description |
384
  |----------|--------|-------------|
 
389
 
390
  **Authentication:** Bearer token in `Authorization` header
391
 
392
+ ### 3.11. Exception Handling (`kiro/exceptions.py`)
393
 
394
  | Function | Description |
395
  |----------|-------------|
396
  | `sanitize_validation_errors(errors)` | Convert bytes to strings for JSON serialization |
397
  | `validation_exception_handler(request, exc)` | Pydantic validation error handler (422) |
398
 
399
+ ### 3.12. Debug Logging (`kiro/debug_logger.py`)
400
 
401
  **Class:** `DebugLogger` (singleton)
402
 
 
417
  - `response_stream_raw.txt` — raw stream from Kiro
418
  - `response_stream_modified.txt` — transformed stream (OpenAI format)
419
 
420
+ ### 3.13. Tokenizer (`kiro/tokenizer.py`)
421
 
422
  **Problem:** Kiro API does not return token counts directly. Instead, the API only provides `context_usage_percentage` — the percentage of model context usage.
423
 
 
749
 
750
  2. **Create conversion adapter** — `converters_gemini.py`
751
  ```python
752
+ from kiro.converters_core import build_kiro_payload
753
 
754
  def gemini_to_kiro(request: GeminiRequest, ...) -> dict:
755
  """Converts Gemini request to Kiro payload."""
 
769
 
770
  3. **Create streaming formatter** — `streaming_gemini.py`
771
  ```python
772
+ from kiro.streaming_core import parse_kiro_stream
773
 
774
  async def stream_to_gemini(response, ...) -> AsyncGenerator[str, None]:
775
  """Formats Kiro events to Gemini SSE."""
 
788
 
789
  5. **Connect in main.py**
790
  ```python
791
+ from kiro.routes_gemini import router as gemini_router
792
  app.include_router(gemini_router)
793
  ```
794
 
docs/ru/ARCHITECTURE.md CHANGED
@@ -53,7 +53,7 @@
53
 
54
  ## 2. Структура Проекта
55
 
56
- Проект организован в виде модульного Python-пакета `kiro_gateway/`:
57
 
58
  ```
59
  kiro-gateway/
@@ -61,7 +61,7 @@ kiro-gateway/
61
  ├── requirements.txt # Зависимости Python
62
  ├── .env.example # Пример конфигурации окружения
63
 
64
- ├── kiro_gateway/ # Основной пакет
65
  │ ├── __init__.py # Экспорты пакета, версия
66
  │ │
67
  │ │ # ═══════════════════════════════════════════════════════
@@ -140,7 +140,7 @@ kiro-gateway/
140
  4. **Регистрация обработчиков ошибок** — `validation_exception_handler` для ошибок 422
141
  5. **Подключение роутов** — `app.include_router(router)`
142
 
143
- ### 3.2. Модуль конфигурации (`kiro_gateway/config.py`)
144
 
145
  Централизованное хранение всех настроек:
146
 
@@ -167,7 +167,7 @@ kiro-gateway/
167
  - `get_kiro_q_host(region)` — хост Q API
168
  - `get_internal_model_id(external_model)` — конвертация имени модели
169
 
170
- ### 3.3. Pydantic Модели (`kiro_gateway/models.py`)
171
 
172
  #### Модели для `/v1/models`
173
 
@@ -198,7 +198,7 @@ kiro-gateway/
198
 
199
  ### 3.4. Управление Состоянием (State Management Layer)
200
 
201
- #### KiroAuthManager (`kiro_gateway/auth.py`)
202
 
203
  **Роль:** Stateful-синглтон, инкапсулирующий логику управления токенами Kiro.
204
 
@@ -234,7 +234,7 @@ auth_manager = KiroAuthManager(
234
  token = await auth_manager.get_access_token()
235
  ```
236
 
237
- #### ModelInfoCache (`kiro_gateway/cache.py`)
238
 
239
  **Роль:** Потокобезопасное хранилище конфигураций моделей.
240
 
@@ -250,7 +250,7 @@ token = await auth_manager.get_access_token()
250
  - `is_empty()` / `is_stale()` — проверка состояния кэша
251
  - `get_all_model_ids()` — список всех ID моделей
252
 
253
- ### 3.5. Вспомогательные Утилиты (`kiro_gateway/utils.py`)
254
 
255
  | Функция | Описание |
256
  |---------|----------|
@@ -260,7 +260,7 @@ token = await auth_manager.get_access_token()
260
  | `generate_conversation_id()` | UUID для разговора |
261
  | `generate_tool_call_id()` | ID в формате `call_{uuid_hex[:8]}` |
262
 
263
- ### 3.6. Слой Конвертации (`kiro_gateway/converters.py`)
264
 
265
  #### Конвертация сообщений
266
 
@@ -310,7 +310,7 @@ OpenAI messages преобразуются в Kiro conversationState:
310
  | `claude-3-7-sonnet-20250219` | `CLAUDE_3_7_SONNET_20250219_V1_0` |
311
  | `auto` | `claude-sonnet-4.5` (алиас) |
312
 
313
- ### 3.7. Слой Парсинга (`kiro_gateway/parsers.py`)
314
 
315
  #### AwsEventStreamParser
316
 
@@ -340,7 +340,7 @@ OpenAI messages преобразуются в Kiro conversationState:
340
  | `parse_bracket_tool_calls(response_text)` | Парсинг `[Called func with args: {...}]` |
341
  | `deduplicate_tool_calls(tool_calls)` | Удаление дубликатов tool calls |
342
 
343
- ### 3.8. Streaming (`kiro_gateway/streaming.py`)
344
 
345
  #### stream_kiro_to_openai
346
 
@@ -357,7 +357,7 @@ OpenAI messages преобразуются в Kiro conversationState:
357
 
358
  Собирает полный ответ из streaming потока для non-streaming режима.
359
 
360
- ### 3.9. HTTP Клиент (`kiro_gateway/http_client.py`)
361
 
362
  #### KiroHttpClient
363
 
@@ -378,7 +378,7 @@ OpenAI messages преобразуются в Kiro conversationState:
378
 
379
  Поддерживает async context manager (`async with`).
380
 
381
- ### 3.10. Роуты (`kiro_gateway/routes.py`)
382
 
383
  | Endpoint | Метод | Описание |
384
  |----------|-------|----------|
@@ -389,14 +389,14 @@ OpenAI messages преобразуются в Kiro conversationState:
389
 
390
  **Аутентификация:** Bearer token в заголовке `Authorization`
391
 
392
- ### 3.11. Обработка Исключений (`kiro_gateway/exceptions.py`)
393
 
394
  | Функция | Описание |
395
  |---------|----------|
396
  | `sanitize_validation_errors(errors)` | Конвертация bytes в строки для JSON-сериализации |
397
  | `validation_exception_handler(request, exc)` | Обработчик ошибок валидации Pydantic (422) |
398
 
399
- ### 3.12. Отладочное Логирование (`kiro_gateway/debug_logger.py`)
400
 
401
  **Класс:** `DebugLogger` (синглтон)
402
 
@@ -417,7 +417,7 @@ OpenAI messages преобразуются в Kiro conversationState:
417
  - `response_stream_raw.txt` — сырой поток от Kiro
418
  - `response_stream_modified.txt` — преобразованный поток (OpenAI формат)
419
 
420
- ### 3.13. Токенизатор (`kiro_gateway/tokenizer.py`)
421
 
422
  **Проблема:** Kiro API не возвращает напрямую количество токенов. Вместо этого API предоставляет только `context_usage_percentage` — процент использования контекста модели.
423
 
@@ -749,7 +749,7 @@ data: [DONE]
749
 
750
  2. **Создать адаптер конвертации** — `converters_gemini.py`
751
  ```python
752
- from kiro_gateway.converters_core import build_kiro_payload
753
 
754
  def gemini_to_kiro(request: GeminiRequest, ...) -> dict:
755
  """Конвертирует Gemini запрос в Kiro payload."""
@@ -769,7 +769,7 @@ data: [DONE]
769
 
770
  3. **Создать форматтер streaming** — `streaming_gemini.py`
771
  ```python
772
- from kiro_gateway.streaming_core import parse_kiro_stream
773
 
774
  async def stream_to_gemini(response, ...) -> AsyncGenerator[str, None]:
775
  """Форматирует Kiro события в Gemini SSE."""
@@ -788,7 +788,7 @@ data: [DONE]
788
 
789
  5. **Подключить в main.py**
790
  ```python
791
- from kiro_gateway.routes_gemini import router as gemini_router
792
  app.include_router(gemini_router)
793
  ```
794
 
 
53
 
54
  ## 2. Структура Проекта
55
 
56
+ Проект организован в виде модульного Python-пакета `kiro/`:
57
 
58
  ```
59
  kiro-gateway/
 
61
  ├── requirements.txt # Зависимости Python
62
  ├── .env.example # Пример конфигурации окружения
63
 
64
+ ├── kiro/ # Основной пакет
65
  │ ├── __init__.py # Экспорты пакета, версия
66
  │ │
67
  │ │ # ═══════════════════════════════════════════════════════
 
140
  4. **Регистрация обработчиков ошибок** — `validation_exception_handler` для ошибок 422
141
  5. **Подключение роутов** — `app.include_router(router)`
142
 
143
+ ### 3.2. Модуль конфигурации (`kiro/config.py`)
144
 
145
  Централизованное хранение всех настроек:
146
 
 
167
  - `get_kiro_q_host(region)` — хост Q API
168
  - `get_internal_model_id(external_model)` — конвертация имени модели
169
 
170
+ ### 3.3. Pydantic Модели (`kiro/models.py`)
171
 
172
  #### Модели для `/v1/models`
173
 
 
198
 
199
  ### 3.4. Управление Состоянием (State Management Layer)
200
 
201
+ #### KiroAuthManager (`kiro/auth.py`)
202
 
203
  **Роль:** Stateful-синглтон, инкапсулирующий логику управления токенами Kiro.
204
 
 
234
  token = await auth_manager.get_access_token()
235
  ```
236
 
237
+ #### ModelInfoCache (`kiro/cache.py`)
238
 
239
  **Роль:** Потокобезопасное хранилище конфигураций моделей.
240
 
 
250
  - `is_empty()` / `is_stale()` — проверка состояния кэша
251
  - `get_all_model_ids()` — список всех ID моделей
252
 
253
+ ### 3.5. Вспомогательные Утилиты (`kiro/utils.py`)
254
 
255
  | Функция | Описание |
256
  |---------|----------|
 
260
  | `generate_conversation_id()` | UUID для разговора |
261
  | `generate_tool_call_id()` | ID в формате `call_{uuid_hex[:8]}` |
262
 
263
+ ### 3.6. Слой Конвертации (`kiro/converters.py`)
264
 
265
  #### Конвертация сообщений
266
 
 
310
  | `claude-3-7-sonnet-20250219` | `CLAUDE_3_7_SONNET_20250219_V1_0` |
311
  | `auto` | `claude-sonnet-4.5` (алиас) |
312
 
313
+ ### 3.7. Слой Парсинга (`kiro/parsers.py`)
314
 
315
  #### AwsEventStreamParser
316
 
 
340
  | `parse_bracket_tool_calls(response_text)` | Парсинг `[Called func with args: {...}]` |
341
  | `deduplicate_tool_calls(tool_calls)` | Удаление дубликатов tool calls |
342
 
343
+ ### 3.8. Streaming (`kiro/streaming.py`)
344
 
345
  #### stream_kiro_to_openai
346
 
 
357
 
358
  Собирает полный ответ из streaming потока для non-streaming режима.
359
 
360
+ ### 3.9. HTTP Клиент (`kiro/http_client.py`)
361
 
362
  #### KiroHttpClient
363
 
 
378
 
379
  Поддерживает async context manager (`async with`).
380
 
381
+ ### 3.10. Роуты (`kiro/routes.py`)
382
 
383
  | Endpoint | Метод | Описание |
384
  |----------|-------|----------|
 
389
 
390
  **Аутентификация:** Bearer token в заголовке `Authorization`
391
 
392
+ ### 3.11. Обработка Исключений (`kiro/exceptions.py`)
393
 
394
  | Функция | Описание |
395
  |---------|----------|
396
  | `sanitize_validation_errors(errors)` | Конвертация bytes в строки для JSON-сериализации |
397
  | `validation_exception_handler(request, exc)` | Обработчик ошибок валидации Pydantic (422) |
398
 
399
+ ### 3.12. Отладочное Логирование (`kiro/debug_logger.py`)
400
 
401
  **Класс:** `DebugLogger` (синглтон)
402
 
 
417
  - `response_stream_raw.txt` — сырой поток от Kiro
418
  - `response_stream_modified.txt` — преобразованный поток (OpenAI формат)
419
 
420
+ ### 3.13. Токенизатор (`kiro/tokenizer.py`)
421
 
422
  **Проблема:** Kiro API не возвращает напрямую количество токенов. Вместо этого API предоставляет только `context_usage_percentage` — процент использования контекста модели.
423
 
 
749
 
750
  2. **Создать адаптер конвертации** — `converters_gemini.py`
751
  ```python
752
+ from kiro.converters_core import build_kiro_payload
753
 
754
  def gemini_to_kiro(request: GeminiRequest, ...) -> dict:
755
  """Конвертирует Gemini запрос в Kiro payload."""
 
769
 
770
  3. **Создать форматтер streaming** — `streaming_gemini.py`
771
  ```python
772
+ from kiro.streaming_core import parse_kiro_stream
773
 
774
  async def stream_to_gemini(response, ...) -> AsyncGenerator[str, None]:
775
  """Форматирует Kiro события в Gemini SSE."""
 
788
 
789
  5. **Подключить в main.py**
790
  ```python
791
+ from kiro.routes_gemini import router as gemini_router
792
  app.include_router(gemini_router)
793
  ```
794
 
kiro/__init__.py CHANGED
@@ -39,18 +39,18 @@ Modules:
39
 
40
  # Version is imported from config.py — the single source of truth
41
  # This allows changing the version in only one place
42
- from kiro_gateway.config import APP_VERSION as __version__
43
 
44
  __author__ = "Jwadow"
45
 
46
  # Main components for convenient import
47
- from kiro_gateway.auth import KiroAuthManager
48
- from kiro_gateway.cache import ModelInfoCache
49
- from kiro_gateway.http_client import KiroHttpClient
50
- from kiro_gateway.routes import router
51
 
52
  # Configuration
53
- from kiro_gateway.config import (
54
  PROXY_API_KEY,
55
  REGION,
56
  MODEL_MAPPING,
@@ -59,7 +59,7 @@ from kiro_gateway.config import (
59
  )
60
 
61
  # Models
62
- from kiro_gateway.models import (
63
  ChatCompletionRequest,
64
  ChatMessage,
65
  OpenAIModel,
@@ -67,26 +67,26 @@ from kiro_gateway.models import (
67
  )
68
 
69
  # Converters
70
- from kiro_gateway.converters import (
71
  build_kiro_payload,
72
  extract_text_content,
73
  merge_adjacent_messages,
74
  )
75
 
76
  # Parsers
77
- from kiro_gateway.parsers import (
78
  AwsEventStreamParser,
79
  parse_bracket_tool_calls,
80
  )
81
 
82
  # Streaming
83
- from kiro_gateway.streaming import (
84
  stream_kiro_to_openai,
85
  collect_stream_response,
86
  )
87
 
88
  # Exceptions
89
- from kiro_gateway.exceptions import (
90
  validation_exception_handler,
91
  sanitize_validation_errors,
92
  )
 
39
 
40
  # Version is imported from config.py — the single source of truth
41
  # This allows changing the version in only one place
42
+ from kiro.config import APP_VERSION as __version__
43
 
44
  __author__ = "Jwadow"
45
 
46
  # Main components for convenient import
47
+ from kiro.auth import KiroAuthManager
48
+ from kiro.cache import ModelInfoCache
49
+ from kiro.http_client import KiroHttpClient
50
+ from kiro.routes import router
51
 
52
  # Configuration
53
+ from kiro.config import (
54
  PROXY_API_KEY,
55
  REGION,
56
  MODEL_MAPPING,
 
59
  )
60
 
61
  # Models
62
+ from kiro.models import (
63
  ChatCompletionRequest,
64
  ChatMessage,
65
  OpenAIModel,
 
67
  )
68
 
69
  # Converters
70
+ from kiro.converters import (
71
  build_kiro_payload,
72
  extract_text_content,
73
  merge_adjacent_messages,
74
  )
75
 
76
  # Parsers
77
+ from kiro.parsers import (
78
  AwsEventStreamParser,
79
  parse_bracket_tool_calls,
80
  )
81
 
82
  # Streaming
83
+ from kiro.streaming import (
84
  stream_kiro_to_openai,
85
  collect_stream_response,
86
  )
87
 
88
  # Exceptions
89
+ from kiro.exceptions import (
90
  validation_exception_handler,
91
  sanitize_validation_errors,
92
  )
kiro/auth.py CHANGED
@@ -38,14 +38,14 @@ from typing import Optional
38
  import httpx
39
  from loguru import logger
40
 
41
- from kiro_gateway.config import (
42
  TOKEN_REFRESH_THRESHOLD,
43
  get_kiro_refresh_url,
44
  get_kiro_api_host,
45
  get_kiro_q_host,
46
  get_aws_sso_oidc_url,
47
  )
48
- from kiro_gateway.utils import get_machine_fingerprint
49
 
50
 
51
  class AuthType(Enum):
 
38
  import httpx
39
  from loguru import logger
40
 
41
+ from kiro.config import (
42
  TOKEN_REFRESH_THRESHOLD,
43
  get_kiro_refresh_url,
44
  get_kiro_api_host,
45
  get_kiro_q_host,
46
  get_aws_sso_oidc_url,
47
  )
48
+ from kiro.utils import get_machine_fingerprint
49
 
50
 
51
  class AuthType(Enum):
kiro/cache.py CHANGED
@@ -30,7 +30,7 @@ from typing import Any, Dict, List, Optional
30
 
31
  from loguru import logger
32
 
33
- from kiro_gateway.config import MODEL_CACHE_TTL, DEFAULT_MAX_INPUT_TOKENS
34
 
35
 
36
  class ModelInfoCache:
 
30
 
31
  from loguru import logger
32
 
33
+ from kiro.config import MODEL_CACHE_TTL, DEFAULT_MAX_INPUT_TOKENS
34
 
35
 
36
  class ModelInfoCache:
kiro/converters.py CHANGED
@@ -32,13 +32,13 @@ from typing import Any, Dict, List, Optional, Tuple
32
 
33
  from loguru import logger
34
 
35
- from kiro_gateway.config import (
36
  get_internal_model_id,
37
  TOOL_DESCRIPTION_MAX_LENGTH,
38
  FAKE_REASONING_ENABLED,
39
  FAKE_REASONING_MAX_TOKENS,
40
  )
41
- from kiro_gateway.models import ChatMessage, ChatCompletionRequest, Tool
42
 
43
 
44
  def extract_text_content(content: Any) -> str:
@@ -408,7 +408,7 @@ def process_tools_with_long_descriptions(
408
 
409
  # Create copy of tool with reference description
410
  # Use Tool model to create new copy
411
- from kiro_gateway.models import ToolFunction
412
 
413
  reference_description = f"[Full documentation in system prompt under '## Tool: {tool_name}']"
414
 
 
32
 
33
  from loguru import logger
34
 
35
+ from kiro.config import (
36
  get_internal_model_id,
37
  TOOL_DESCRIPTION_MAX_LENGTH,
38
  FAKE_REASONING_ENABLED,
39
  FAKE_REASONING_MAX_TOKENS,
40
  )
41
+ from kiro.models import ChatMessage, ChatCompletionRequest, Tool
42
 
43
 
44
  def extract_text_content(content: Any) -> str:
 
408
 
409
  # Create copy of tool with reference description
410
  # Use Tool model to create new copy
411
+ from kiro.models import ToolFunction
412
 
413
  reference_description = f"[Full documentation in system prompt under '## Tool: {tool_name}']"
414
 
kiro/debug_logger.py CHANGED
@@ -39,7 +39,7 @@ from pathlib import Path
39
  from typing import Optional
40
  from loguru import logger
41
 
42
- from kiro_gateway.config import DEBUG_MODE, DEBUG_DIR
43
 
44
 
45
  class DebugLogger:
 
39
  from typing import Optional
40
  from loguru import logger
41
 
42
+ from kiro.config import DEBUG_MODE, DEBUG_DIR
43
 
44
 
45
  class DebugLogger:
kiro/http_client.py CHANGED
@@ -34,9 +34,9 @@ import httpx
34
  from fastapi import HTTPException
35
  from loguru import logger
36
 
37
- from kiro_gateway.config import MAX_RETRIES, BASE_RETRY_DELAY, FIRST_TOKEN_MAX_RETRIES, STREAMING_READ_TIMEOUT
38
- from kiro_gateway.auth import KiroAuthManager
39
- from kiro_gateway.utils import get_kiro_headers
40
 
41
 
42
  class KiroHttpClient:
 
34
  from fastapi import HTTPException
35
  from loguru import logger
36
 
37
+ from kiro.config import MAX_RETRIES, BASE_RETRY_DELAY, FIRST_TOKEN_MAX_RETRIES, STREAMING_READ_TIMEOUT
38
+ from kiro.auth import KiroAuthManager
39
+ from kiro.utils import get_kiro_headers
40
 
41
 
42
  class KiroHttpClient:
kiro/parsers.py CHANGED
@@ -33,7 +33,7 @@ from typing import Any, Dict, List, Optional
33
 
34
  from loguru import logger
35
 
36
- from kiro_gateway.utils import generate_tool_call_id
37
 
38
 
39
  def find_matching_brace(text: str, start_pos: int) -> int:
 
33
 
34
  from loguru import logger
35
 
36
+ from kiro.utils import generate_tool_call_id
37
 
38
 
39
  def find_matching_brace(text: str, start_pos: int) -> int:
kiro/routes.py CHANGED
@@ -35,26 +35,26 @@ from fastapi.responses import JSONResponse, StreamingResponse
35
  from fastapi.security import APIKeyHeader
36
  from loguru import logger
37
 
38
- from kiro_gateway.config import (
39
  PROXY_API_KEY,
40
  AVAILABLE_MODELS,
41
  APP_VERSION,
42
  )
43
- from kiro_gateway.models import (
44
  OpenAIModel,
45
  ModelList,
46
  ChatCompletionRequest,
47
  )
48
- from kiro_gateway.auth import KiroAuthManager, AuthType
49
- from kiro_gateway.cache import ModelInfoCache
50
- from kiro_gateway.converters import build_kiro_payload
51
- from kiro_gateway.streaming import stream_kiro_to_openai, collect_stream_response, stream_with_first_token_retry
52
- from kiro_gateway.http_client import KiroHttpClient
53
- from kiro_gateway.utils import get_kiro_headers, generate_conversation_id
54
 
55
  # Import debug_logger
56
  try:
57
- from kiro_gateway.debug_logger import debug_logger
58
  except ImportError:
59
  debug_logger = None
60
 
 
35
  from fastapi.security import APIKeyHeader
36
  from loguru import logger
37
 
38
+ from kiro.config import (
39
  PROXY_API_KEY,
40
  AVAILABLE_MODELS,
41
  APP_VERSION,
42
  )
43
+ from kiro.models import (
44
  OpenAIModel,
45
  ModelList,
46
  ChatCompletionRequest,
47
  )
48
+ from kiro.auth import KiroAuthManager, AuthType
49
+ from kiro.cache import ModelInfoCache
50
+ from kiro.converters import build_kiro_payload
51
+ from kiro.streaming import stream_kiro_to_openai, collect_stream_response, stream_with_first_token_retry
52
+ from kiro.http_client import KiroHttpClient
53
+ from kiro.utils import get_kiro_headers, generate_conversation_id
54
 
55
  # Import debug_logger
56
  try:
57
+ from kiro.debug_logger import debug_logger
58
  except ImportError:
59
  debug_logger = None
60
 
kiro/streaming.py CHANGED
@@ -35,24 +35,24 @@ import httpx
35
  from fastapi import HTTPException
36
  from loguru import logger
37
 
38
- from kiro_gateway.parsers import AwsEventStreamParser, parse_bracket_tool_calls, deduplicate_tool_calls
39
- from kiro_gateway.utils import generate_completion_id
40
- from kiro_gateway.config import (
41
  FIRST_TOKEN_TIMEOUT,
42
  FIRST_TOKEN_MAX_RETRIES,
43
  FAKE_REASONING_ENABLED,
44
  FAKE_REASONING_HANDLING,
45
  )
46
- from kiro_gateway.tokenizer import count_tokens, count_message_tokens, count_tools_tokens
47
- from kiro_gateway.thinking_parser import ThinkingParser
48
 
49
  if TYPE_CHECKING:
50
- from kiro_gateway.auth import KiroAuthManager
51
- from kiro_gateway.cache import ModelInfoCache
52
 
53
  # Import debug_logger for logging
54
  try:
55
- from kiro_gateway.debug_logger import debug_logger
56
  except ImportError:
57
  debug_logger = None
58
 
 
35
  from fastapi import HTTPException
36
  from loguru import logger
37
 
38
+ from kiro.parsers import AwsEventStreamParser, parse_bracket_tool_calls, deduplicate_tool_calls
39
+ from kiro.utils import generate_completion_id
40
+ from kiro.config import (
41
  FIRST_TOKEN_TIMEOUT,
42
  FIRST_TOKEN_MAX_RETRIES,
43
  FAKE_REASONING_ENABLED,
44
  FAKE_REASONING_HANDLING,
45
  )
46
+ from kiro.tokenizer import count_tokens, count_message_tokens, count_tools_tokens
47
+ from kiro.thinking_parser import ThinkingParser
48
 
49
  if TYPE_CHECKING:
50
+ from kiro.auth import KiroAuthManager
51
+ from kiro.cache import ModelInfoCache
52
 
53
  # Import debug_logger for logging
54
  try:
55
+ from kiro.debug_logger import debug_logger
56
  except ImportError:
57
  debug_logger = None
58
 
kiro/thinking_parser.py CHANGED
@@ -37,7 +37,7 @@ from dataclasses import dataclass, field
37
 
38
  from loguru import logger
39
 
40
- from kiro_gateway.config import (
41
  FAKE_REASONING_HANDLING,
42
  FAKE_REASONING_OPEN_TAGS,
43
  FAKE_REASONING_INITIAL_BUFFER_SIZE,
 
37
 
38
  from loguru import logger
39
 
40
+ from kiro.config import (
41
  FAKE_REASONING_HANDLING,
42
  FAKE_REASONING_OPEN_TAGS,
43
  FAKE_REASONING_INITIAL_BUFFER_SIZE,
kiro/utils.py CHANGED
@@ -31,7 +31,7 @@ from typing import TYPE_CHECKING
31
  from loguru import logger
32
 
33
  if TYPE_CHECKING:
34
- from kiro_gateway.auth import KiroAuthManager
35
 
36
 
37
  def get_machine_fingerprint() -> str:
 
31
  from loguru import logger
32
 
33
  if TYPE_CHECKING:
34
+ from kiro.auth import KiroAuthManager
35
 
36
 
37
  def get_machine_fingerprint() -> str:
main.py CHANGED
@@ -50,7 +50,7 @@ from fastapi.exceptions import RequestValidationError
50
  from fastapi.middleware.cors import CORSMiddleware
51
  from loguru import logger
52
 
53
- from kiro_gateway.config import (
54
  APP_TITLE,
55
  APP_DESCRIPTION,
56
  APP_VERSION,
@@ -68,10 +68,10 @@ from kiro_gateway.config import (
68
  _warn_deprecated_debug_setting,
69
  _warn_timeout_configuration,
70
  )
71
- from kiro_gateway.auth import KiroAuthManager
72
- from kiro_gateway.cache import ModelInfoCache
73
- from kiro_gateway.routes import router
74
- from kiro_gateway.exceptions import validation_exception_handler
75
 
76
 
77
  # --- Loguru Configuration ---
 
50
  from fastapi.middleware.cors import CORSMiddleware
51
  from loguru import logger
52
 
53
+ from kiro.config import (
54
  APP_TITLE,
55
  APP_DESCRIPTION,
56
  APP_VERSION,
 
68
  _warn_deprecated_debug_setting,
69
  _warn_timeout_configuration,
70
  )
71
+ from kiro.auth import KiroAuthManager
72
+ from kiro.cache import ModelInfoCache
73
+ from kiro.routes import router
74
+ from kiro.exceptions import validation_exception_handler
75
 
76
 
77
  # --- Loguru Configuration ---
tests/README.md CHANGED
@@ -2037,7 +2037,7 @@ To check code coverage:
2037
  pip install pytest-cov
2038
 
2039
  # Run with coverage report
2040
- pytest --cov=kiro_gateway --cov-report=html
2041
 
2042
  # View report
2043
  open htmlcov/index.html # macOS/Linux
 
2037
  pip install pytest-cov
2038
 
2039
  # Run with coverage report
2040
+ pytest --cov=kiro --cov-report=html
2041
 
2042
  # View report
2043
  open htmlcov/index.html # macOS/Linux
tests/conftest.py CHANGED
@@ -355,10 +355,10 @@ def block_all_network_calls():
355
 
356
  # Patch AsyncClient in modules where it's used
357
  patchers = [
358
- patch('kiro_gateway.auth.httpx.AsyncClient', return_value=mock_async_client),
359
- patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_async_client),
360
- patch('kiro_gateway.routes.httpx.AsyncClient', return_value=mock_async_client),
361
- patch('kiro_gateway.streaming.httpx.AsyncClient', return_value=mock_async_client),
362
  ]
363
 
364
  # Start patchers
@@ -428,7 +428,7 @@ def mock_auth_manager():
428
  """
429
  Creates a mocked KiroAuthManager for tests.
430
  """
431
- from kiro_gateway.auth import KiroAuthManager
432
 
433
  manager = KiroAuthManager(
434
  refresh_token="test_refresh_token",
@@ -450,7 +450,7 @@ def expired_auth_manager():
450
  """
451
  Creates a KiroAuthManager with an expired token.
452
  """
453
- from kiro_gateway.auth import KiroAuthManager
454
 
455
  manager = KiroAuthManager(
456
  refresh_token="test_refresh_token",
@@ -509,7 +509,7 @@ def empty_model_cache():
509
  """
510
  Creates an empty ModelInfoCache.
511
  """
512
- from kiro_gateway.cache import ModelInfoCache
513
  return ModelInfoCache()
514
 
515
 
@@ -518,7 +518,7 @@ async def populated_model_cache(mock_kiro_models_response):
518
  """
519
  Creates a ModelInfoCache with pre-populated data.
520
  """
521
- from kiro_gateway.cache import ModelInfoCache
522
 
523
  cache = ModelInfoCache()
524
  await cache.update(mock_kiro_models_response["models"])
@@ -547,7 +547,7 @@ def mock_datetime():
547
  """
548
  fixed_time = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
549
 
550
- with patch('kiro_gateway.auth.datetime') as mock_dt:
551
  mock_dt.now.return_value = fixed_time
552
  mock_dt.fromisoformat = datetime.fromisoformat
553
  mock_dt.fromtimestamp = datetime.fromtimestamp
@@ -750,7 +750,7 @@ def aws_event_parser():
750
  """
751
  Creates an AwsEventStreamParser instance for tests.
752
  """
753
- from kiro_gateway.parsers import AwsEventStreamParser
754
  return AwsEventStreamParser()
755
 
756
 
 
355
 
356
  # Patch AsyncClient in modules where it's used
357
  patchers = [
358
+ patch('kiro.auth.httpx.AsyncClient', return_value=mock_async_client),
359
+ patch('kiro.http_client.httpx.AsyncClient', return_value=mock_async_client),
360
+ patch('kiro.routes.httpx.AsyncClient', return_value=mock_async_client),
361
+ patch('kiro.streaming.httpx.AsyncClient', return_value=mock_async_client),
362
  ]
363
 
364
  # Start patchers
 
428
  """
429
  Creates a mocked KiroAuthManager for tests.
430
  """
431
+ from kiro.auth import KiroAuthManager
432
 
433
  manager = KiroAuthManager(
434
  refresh_token="test_refresh_token",
 
450
  """
451
  Creates a KiroAuthManager with an expired token.
452
  """
453
+ from kiro.auth import KiroAuthManager
454
 
455
  manager = KiroAuthManager(
456
  refresh_token="test_refresh_token",
 
509
  """
510
  Creates an empty ModelInfoCache.
511
  """
512
+ from kiro.cache import ModelInfoCache
513
  return ModelInfoCache()
514
 
515
 
 
518
  """
519
  Creates a ModelInfoCache with pre-populated data.
520
  """
521
+ from kiro.cache import ModelInfoCache
522
 
523
  cache = ModelInfoCache()
524
  await cache.update(mock_kiro_models_response["models"])
 
547
  """
548
  fixed_time = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
549
 
550
+ with patch('kiro.auth.datetime') as mock_dt:
551
  mock_dt.now.return_value = fixed_time
552
  mock_dt.fromisoformat = datetime.fromisoformat
553
  mock_dt.fromtimestamp = datetime.fromtimestamp
 
750
  """
751
  Creates an AwsEventStreamParser instance for tests.
752
  """
753
+ from kiro.parsers import AwsEventStreamParser
754
  return AwsEventStreamParser()
755
 
756
 
tests/integration/test_full_flow.py CHANGED
@@ -13,7 +13,7 @@ from datetime import datetime, timezone, timedelta
13
  from fastapi.testclient import TestClient
14
  import httpx
15
 
16
- from kiro_gateway.config import PROXY_API_KEY, AVAILABLE_MODELS
17
 
18
 
19
  class TestFullChatCompletionFlow:
@@ -329,7 +329,7 @@ class TestStreamingFlagHandling:
329
  mock_response.aclose = AsyncMock()
330
 
331
  # Мокируем request_with_retry чтобы вернуть наш мок response
332
- with patch('kiro_gateway.routes.KiroHttpClient') as MockHttpClient:
333
  mock_client_instance = AsyncMock()
334
  mock_client_instance.request_with_retry = AsyncMock(return_value=mock_response)
335
  mock_client_instance.client = AsyncMock()
 
13
  from fastapi.testclient import TestClient
14
  import httpx
15
 
16
+ from kiro.config import PROXY_API_KEY, AVAILABLE_MODELS
17
 
18
 
19
  class TestFullChatCompletionFlow:
 
329
  mock_response.aclose = AsyncMock()
330
 
331
  # Мокируем request_with_retry чтобы вернуть наш мок response
332
+ with patch('kiro.routes.KiroHttpClient') as MockHttpClient:
333
  mock_client_instance = AsyncMock()
334
  mock_client_instance.request_with_retry = AsyncMock(return_value=mock_response)
335
  mock_client_instance.client = AsyncMock()
tests/unit/test_auth_manager.py CHANGED
@@ -11,8 +11,8 @@ from datetime import datetime, timezone, timedelta
11
  from unittest.mock import AsyncMock, Mock, patch
12
  import httpx
13
 
14
- from kiro_gateway.auth import KiroAuthManager, AuthType
15
- from kiro_gateway.config import TOKEN_REFRESH_THRESHOLD, get_aws_sso_oidc_url
16
 
17
 
18
  class TestKiroAuthManagerInitialization:
@@ -204,7 +204,7 @@ class TestKiroAuthManagerTokenRefresh:
204
  mock_response.json = Mock(return_value=mock_kiro_token_response())
205
  mock_response.raise_for_status = Mock()
206
 
207
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
208
  mock_client = AsyncMock()
209
  mock_client.post = AsyncMock(return_value=mock_response)
210
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -239,7 +239,7 @@ class TestKiroAuthManagerTokenRefresh:
239
  mock_response.json = Mock(return_value=mock_kiro_token_response())
240
  mock_response.raise_for_status = Mock()
241
 
242
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
243
  mock_client = AsyncMock()
244
  mock_client.post = AsyncMock(return_value=mock_response)
245
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -268,7 +268,7 @@ class TestKiroAuthManagerTokenRefresh:
268
  mock_response.json = Mock(return_value={"expiresIn": 3600}) # No accessToken!
269
  mock_response.raise_for_status = Mock()
270
 
271
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
272
  mock_client = AsyncMock()
273
  mock_client.post = AsyncMock(return_value=mock_response)
274
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -320,7 +320,7 @@ class TestKiroAuthManagerGetAccessToken:
320
  mock_response.json = Mock(return_value=mock_kiro_token_response())
321
  mock_response.raise_for_status = Mock()
322
 
323
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
324
  mock_client = AsyncMock()
325
  mock_client.post = AsyncMock(return_value=mock_response)
326
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -350,7 +350,7 @@ class TestKiroAuthManagerGetAccessToken:
350
  manager._expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
351
 
352
  print("Setup: Mocking httpx to track calls...")
353
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
354
  mock_client = AsyncMock()
355
  mock_client.post = AsyncMock()
356
  mock_client_class.return_value = mock_client
@@ -420,7 +420,7 @@ class TestKiroAuthManagerForceRefresh:
420
  mock_response.json = Mock(return_value=mock_kiro_token_response())
421
  mock_response.raise_for_status = Mock()
422
 
423
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
424
  mock_client = AsyncMock()
425
  mock_client.post = AsyncMock(return_value=mock_response)
426
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -848,7 +848,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
848
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
849
  mock_response.raise_for_status = Mock()
850
 
851
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
852
  mock_client = AsyncMock()
853
  mock_client.post = AsyncMock(return_value=mock_response)
854
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -947,7 +947,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
947
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
948
  mock_response.raise_for_status = Mock()
949
 
950
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
951
  mock_client = AsyncMock()
952
  mock_client.post = AsyncMock(return_value=mock_response)
953
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -982,7 +982,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
982
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
983
  mock_response.raise_for_status = Mock()
984
 
985
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
986
  mock_client = AsyncMock()
987
  mock_client.post = AsyncMock(return_value=mock_response)
988
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1016,7 +1016,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
1016
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1017
  mock_response.raise_for_status = Mock()
1018
 
1019
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1020
  mock_client = AsyncMock()
1021
  mock_client.post = AsyncMock(return_value=mock_response)
1022
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1050,7 +1050,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
1050
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1051
  mock_response.raise_for_status = Mock()
1052
 
1053
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1054
  mock_client = AsyncMock()
1055
  mock_client.post = AsyncMock(return_value=mock_response)
1056
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1084,7 +1084,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
1084
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response(expires_in=7200))
1085
  mock_response.raise_for_status = Mock()
1086
 
1087
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1088
  mock_client = AsyncMock()
1089
  mock_client.post = AsyncMock(return_value=mock_response)
1090
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1123,7 +1123,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
1123
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1124
  mock_response.raise_for_status = Mock()
1125
 
1126
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1127
  mock_client = AsyncMock()
1128
  mock_client.post = AsyncMock(return_value=mock_response)
1129
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1164,7 +1164,7 @@ class TestKiroAuthManagerAwsSsoOidcRefresh:
1164
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1165
  mock_response.raise_for_status = Mock()
1166
 
1167
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1168
  mock_client = AsyncMock()
1169
  mock_client.post = AsyncMock(return_value=mock_response)
1170
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1340,7 +1340,7 @@ class TestKiroAuthManagerSsoRegionSeparation:
1340
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1341
  mock_response.raise_for_status = Mock()
1342
 
1343
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1344
  mock_client = AsyncMock()
1345
  mock_client.post = AsyncMock(return_value=mock_response)
1346
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1380,7 +1380,7 @@ class TestKiroAuthManagerSsoRegionSeparation:
1380
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1381
  mock_response.raise_for_status = Mock()
1382
 
1383
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1384
  mock_client = AsyncMock()
1385
  mock_client.post = AsyncMock(return_value=mock_response)
1386
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1439,7 +1439,7 @@ class TestKiroAuthManagerSsoRegionSeparation:
1439
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1440
  mock_response.raise_for_status = Mock()
1441
 
1442
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1443
  mock_client = AsyncMock()
1444
  mock_client.post = AsyncMock(return_value=mock_response)
1445
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1568,7 +1568,7 @@ class TestKiroAuthManagerSsoRegionSeparation:
1568
  return mock_error_response
1569
  return mock_success_response
1570
 
1571
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1572
  mock_client = AsyncMock()
1573
  mock_client.post = mock_post
1574
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1619,7 +1619,7 @@ class TestKiroAuthManagerSsoRegionSeparation:
1619
  )
1620
  )
1621
 
1622
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1623
  mock_client = AsyncMock()
1624
  mock_client.post = AsyncMock(return_value=mock_error_response)
1625
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
@@ -1667,7 +1667,7 @@ class TestKiroAuthManagerSsoRegionSeparation:
1667
  )
1668
  )
1669
 
1670
- with patch('kiro_gateway.auth.httpx.AsyncClient') as mock_client_class:
1671
  mock_client = AsyncMock()
1672
  mock_client.post = AsyncMock(return_value=mock_error_response)
1673
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
11
  from unittest.mock import AsyncMock, Mock, patch
12
  import httpx
13
 
14
+ from kiro.auth import KiroAuthManager, AuthType
15
+ from kiro.config import TOKEN_REFRESH_THRESHOLD, get_aws_sso_oidc_url
16
 
17
 
18
  class TestKiroAuthManagerInitialization:
 
204
  mock_response.json = Mock(return_value=mock_kiro_token_response())
205
  mock_response.raise_for_status = Mock()
206
 
207
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
208
  mock_client = AsyncMock()
209
  mock_client.post = AsyncMock(return_value=mock_response)
210
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
239
  mock_response.json = Mock(return_value=mock_kiro_token_response())
240
  mock_response.raise_for_status = Mock()
241
 
242
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
243
  mock_client = AsyncMock()
244
  mock_client.post = AsyncMock(return_value=mock_response)
245
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
268
  mock_response.json = Mock(return_value={"expiresIn": 3600}) # No accessToken!
269
  mock_response.raise_for_status = Mock()
270
 
271
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
272
  mock_client = AsyncMock()
273
  mock_client.post = AsyncMock(return_value=mock_response)
274
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
320
  mock_response.json = Mock(return_value=mock_kiro_token_response())
321
  mock_response.raise_for_status = Mock()
322
 
323
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
324
  mock_client = AsyncMock()
325
  mock_client.post = AsyncMock(return_value=mock_response)
326
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
350
  manager._expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
351
 
352
  print("Setup: Mocking httpx to track calls...")
353
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
354
  mock_client = AsyncMock()
355
  mock_client.post = AsyncMock()
356
  mock_client_class.return_value = mock_client
 
420
  mock_response.json = Mock(return_value=mock_kiro_token_response())
421
  mock_response.raise_for_status = Mock()
422
 
423
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
424
  mock_client = AsyncMock()
425
  mock_client.post = AsyncMock(return_value=mock_response)
426
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
848
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
849
  mock_response.raise_for_status = Mock()
850
 
851
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
852
  mock_client = AsyncMock()
853
  mock_client.post = AsyncMock(return_value=mock_response)
854
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
947
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
948
  mock_response.raise_for_status = Mock()
949
 
950
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
951
  mock_client = AsyncMock()
952
  mock_client.post = AsyncMock(return_value=mock_response)
953
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
982
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
983
  mock_response.raise_for_status = Mock()
984
 
985
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
986
  mock_client = AsyncMock()
987
  mock_client.post = AsyncMock(return_value=mock_response)
988
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1016
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1017
  mock_response.raise_for_status = Mock()
1018
 
1019
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1020
  mock_client = AsyncMock()
1021
  mock_client.post = AsyncMock(return_value=mock_response)
1022
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1050
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1051
  mock_response.raise_for_status = Mock()
1052
 
1053
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1054
  mock_client = AsyncMock()
1055
  mock_client.post = AsyncMock(return_value=mock_response)
1056
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1084
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response(expires_in=7200))
1085
  mock_response.raise_for_status = Mock()
1086
 
1087
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1088
  mock_client = AsyncMock()
1089
  mock_client.post = AsyncMock(return_value=mock_response)
1090
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1123
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1124
  mock_response.raise_for_status = Mock()
1125
 
1126
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1127
  mock_client = AsyncMock()
1128
  mock_client.post = AsyncMock(return_value=mock_response)
1129
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1164
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1165
  mock_response.raise_for_status = Mock()
1166
 
1167
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1168
  mock_client = AsyncMock()
1169
  mock_client.post = AsyncMock(return_value=mock_response)
1170
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1340
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1341
  mock_response.raise_for_status = Mock()
1342
 
1343
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1344
  mock_client = AsyncMock()
1345
  mock_client.post = AsyncMock(return_value=mock_response)
1346
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1380
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1381
  mock_response.raise_for_status = Mock()
1382
 
1383
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1384
  mock_client = AsyncMock()
1385
  mock_client.post = AsyncMock(return_value=mock_response)
1386
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1439
  mock_response.json = Mock(return_value=mock_aws_sso_oidc_token_response())
1440
  mock_response.raise_for_status = Mock()
1441
 
1442
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1443
  mock_client = AsyncMock()
1444
  mock_client.post = AsyncMock(return_value=mock_response)
1445
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1568
  return mock_error_response
1569
  return mock_success_response
1570
 
1571
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1572
  mock_client = AsyncMock()
1573
  mock_client.post = mock_post
1574
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1619
  )
1620
  )
1621
 
1622
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1623
  mock_client = AsyncMock()
1624
  mock_client.post = AsyncMock(return_value=mock_error_response)
1625
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
 
1667
  )
1668
  )
1669
 
1670
+ with patch('kiro.auth.httpx.AsyncClient') as mock_client_class:
1671
  mock_client = AsyncMock()
1672
  mock_client.post = AsyncMock(return_value=mock_error_response)
1673
  mock_client.__aenter__ = AsyncMock(return_value=mock_client)
tests/unit/test_cache.py CHANGED
@@ -9,8 +9,8 @@ import asyncio
9
  import time
10
  import pytest
11
 
12
- from kiro_gateway.cache import ModelInfoCache
13
- from kiro_gateway.config import DEFAULT_MAX_INPUT_TOKENS
14
 
15
 
16
  class TestModelInfoCacheInitialization:
 
9
  import time
10
  import pytest
11
 
12
+ from kiro.cache import ModelInfoCache
13
+ from kiro.config import DEFAULT_MAX_INPUT_TOKENS
14
 
15
 
16
  class TestModelInfoCacheInitialization:
tests/unit/test_config.py CHANGED
@@ -36,7 +36,7 @@ class TestLogLevelConfig:
36
  with patch.object(os, 'getenv', side_effect=mock_getenv):
37
  # Reload config module with mocked getenv
38
  import importlib
39
- import kiro_gateway.config as config_module
40
  importlib.reload(config_module)
41
 
42
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
@@ -45,7 +45,7 @@ class TestLogLevelConfig:
45
 
46
  # Restore module with real values
47
  import importlib
48
- import kiro_gateway.config as config_module
49
  importlib.reload(config_module)
50
 
51
  def test_log_level_from_environment(self):
@@ -57,7 +57,7 @@ class TestLogLevelConfig:
57
 
58
  with patch.dict(os.environ, {"LOG_LEVEL": "DEBUG"}):
59
  import importlib
60
- import kiro_gateway.config as config_module
61
  importlib.reload(config_module)
62
 
63
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
@@ -73,7 +73,7 @@ class TestLogLevelConfig:
73
 
74
  with patch.dict(os.environ, {"LOG_LEVEL": "warning"}):
75
  import importlib
76
- import kiro_gateway.config as config_module
77
  importlib.reload(config_module)
78
 
79
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
@@ -89,7 +89,7 @@ class TestLogLevelConfig:
89
 
90
  with patch.dict(os.environ, {"LOG_LEVEL": "TRACE"}):
91
  import importlib
92
- import kiro_gateway.config as config_module
93
  importlib.reload(config_module)
94
 
95
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
@@ -104,7 +104,7 @@ class TestLogLevelConfig:
104
 
105
  with patch.dict(os.environ, {"LOG_LEVEL": "ERROR"}):
106
  import importlib
107
- import kiro_gateway.config as config_module
108
  importlib.reload(config_module)
109
 
110
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
@@ -119,7 +119,7 @@ class TestLogLevelConfig:
119
 
120
  with patch.dict(os.environ, {"LOG_LEVEL": "CRITICAL"}):
121
  import importlib
122
- import kiro_gateway.config as config_module
123
  importlib.reload(config_module)
124
 
125
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
@@ -141,7 +141,7 @@ class TestToolDescriptionMaxLengthConfig:
141
  del os.environ["TOOL_DESCRIPTION_MAX_LENGTH"]
142
 
143
  import importlib
144
- import kiro_gateway.config as config_module
145
  importlib.reload(config_module)
146
 
147
  print(f"TOOL_DESCRIPTION_MAX_LENGTH: {config_module.TOOL_DESCRIPTION_MAX_LENGTH}")
@@ -156,7 +156,7 @@ class TestToolDescriptionMaxLengthConfig:
156
 
157
  with patch.dict(os.environ, {"TOOL_DESCRIPTION_MAX_LENGTH": "5000"}):
158
  import importlib
159
- import kiro_gateway.config as config_module
160
  importlib.reload(config_module)
161
 
162
  print(f"TOOL_DESCRIPTION_MAX_LENGTH: {config_module.TOOL_DESCRIPTION_MAX_LENGTH}")
@@ -171,7 +171,7 @@ class TestToolDescriptionMaxLengthConfig:
171
 
172
  with patch.dict(os.environ, {"TOOL_DESCRIPTION_MAX_LENGTH": "0"}):
173
  import importlib
174
- import kiro_gateway.config as config_module
175
  importlib.reload(config_module)
176
 
177
  print(f"TOOL_DESCRIPTION_MAX_LENGTH: {config_module.TOOL_DESCRIPTION_MAX_LENGTH}")
@@ -193,7 +193,7 @@ class TestTimeoutConfigurationWarning:
193
  "STREAMING_READ_TIMEOUT": "300"
194
  }):
195
  import importlib
196
- import kiro_gateway.config as config_module
197
  importlib.reload(config_module)
198
 
199
  # Call the warning function
@@ -218,7 +218,7 @@ class TestTimeoutConfigurationWarning:
218
  "STREAMING_READ_TIMEOUT": "300"
219
  }):
220
  import importlib
221
- import kiro_gateway.config as config_module
222
  importlib.reload(config_module)
223
 
224
  # Call the warning function
@@ -242,7 +242,7 @@ class TestTimeoutConfigurationWarning:
242
  "STREAMING_READ_TIMEOUT": "300"
243
  }):
244
  import importlib
245
- import kiro_gateway.config as config_module
246
  importlib.reload(config_module)
247
 
248
  # Call the warning function
@@ -269,7 +269,7 @@ class TestTimeoutConfigurationWarning:
269
  "STREAMING_READ_TIMEOUT": "300"
270
  }):
271
  import importlib
272
- import kiro_gateway.config as config_module
273
  importlib.reload(config_module)
274
 
275
  # Call the warning function
@@ -292,7 +292,7 @@ class TestAwsSsoOidcUrlConfig:
292
  """
293
  print("Setup: Importing config module...")
294
  import importlib
295
- import kiro_gateway.config as config_module
296
  importlib.reload(config_module)
297
 
298
  print("Verification: AWS_SSO_OIDC_URL_TEMPLATE exists...")
@@ -309,7 +309,7 @@ class TestAwsSsoOidcUrlConfig:
309
  Purpose: Ensure the function formats URL correctly.
310
  """
311
  print("Setup: Importing get_aws_sso_oidc_url...")
312
- from kiro_gateway.config import get_aws_sso_oidc_url
313
 
314
  print("Action: Calling get_aws_sso_oidc_url('us-east-1')...")
315
  url = get_aws_sso_oidc_url("us-east-1")
@@ -325,7 +325,7 @@ class TestAwsSsoOidcUrlConfig:
325
  Purpose: Ensure the function works with various AWS regions.
326
  """
327
  print("Setup: Importing get_aws_sso_oidc_url...")
328
- from kiro_gateway.config import get_aws_sso_oidc_url
329
 
330
  test_cases = [
331
  ("us-east-1", "https://oidc.us-east-1.amazonaws.com/token"),
@@ -356,7 +356,7 @@ class TestServerHostConfig:
356
  del os.environ["SERVER_HOST"]
357
 
358
  import importlib
359
- import kiro_gateway.config as config_module
360
  importlib.reload(config_module)
361
 
362
  print(f"SERVER_HOST: {config_module.SERVER_HOST}")
@@ -374,7 +374,7 @@ class TestServerHostConfig:
374
 
375
  with patch.dict(os.environ, {"SERVER_HOST": "127.0.0.1"}):
376
  import importlib
377
- import kiro_gateway.config as config_module
378
  importlib.reload(config_module)
379
 
380
  print(f"SERVER_HOST: {config_module.SERVER_HOST}")
@@ -390,7 +390,7 @@ class TestServerHostConfig:
390
 
391
  with patch.dict(os.environ, {"SERVER_HOST": "192.168.1.100"}):
392
  import importlib
393
- import kiro_gateway.config as config_module
394
  importlib.reload(config_module)
395
 
396
  print(f"SERVER_HOST: {config_module.SERVER_HOST}")
@@ -412,7 +412,7 @@ class TestServerPortConfig:
412
  del os.environ["SERVER_PORT"]
413
 
414
  import importlib
415
- import kiro_gateway.config as config_module
416
  importlib.reload(config_module)
417
 
418
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
@@ -430,7 +430,7 @@ class TestServerPortConfig:
430
 
431
  with patch.dict(os.environ, {"SERVER_PORT": "9000"}):
432
  import importlib
433
- import kiro_gateway.config as config_module
434
  importlib.reload(config_module)
435
 
436
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
@@ -446,7 +446,7 @@ class TestServerPortConfig:
446
 
447
  with patch.dict(os.environ, {"SERVER_PORT": "3000"}):
448
  import importlib
449
- import kiro_gateway.config as config_module
450
  importlib.reload(config_module)
451
 
452
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
@@ -461,7 +461,7 @@ class TestServerPortConfig:
461
 
462
  with patch.dict(os.environ, {"SERVER_PORT": "8080"}):
463
  import importlib
464
- import kiro_gateway.config as config_module
465
  importlib.reload(config_module)
466
 
467
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
@@ -480,7 +480,7 @@ class TestKiroCliDbFileConfig:
480
  """
481
  print("Setup: Importing config module...")
482
  import importlib
483
- import kiro_gateway.config as config_module
484
  importlib.reload(config_module)
485
 
486
  print("Verification: KIRO_CLI_DB_FILE exists...")
@@ -499,7 +499,7 @@ class TestKiroCliDbFileConfig:
499
 
500
  with patch.dict(os.environ, {"KIRO_CLI_DB_FILE": "~/.local/share/kiro-cli/data.sqlite3"}):
501
  import importlib
502
- import kiro_gateway.config as config_module
503
  importlib.reload(config_module)
504
 
505
  print(f"KIRO_CLI_DB_FILE: {config_module.KIRO_CLI_DB_FILE}")
 
36
  with patch.object(os, 'getenv', side_effect=mock_getenv):
37
  # Reload config module with mocked getenv
38
  import importlib
39
+ import kiro.config as config_module
40
  importlib.reload(config_module)
41
 
42
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
 
45
 
46
  # Restore module with real values
47
  import importlib
48
+ import kiro.config as config_module
49
  importlib.reload(config_module)
50
 
51
  def test_log_level_from_environment(self):
 
57
 
58
  with patch.dict(os.environ, {"LOG_LEVEL": "DEBUG"}):
59
  import importlib
60
+ import kiro.config as config_module
61
  importlib.reload(config_module)
62
 
63
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
 
73
 
74
  with patch.dict(os.environ, {"LOG_LEVEL": "warning"}):
75
  import importlib
76
+ import kiro.config as config_module
77
  importlib.reload(config_module)
78
 
79
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
 
89
 
90
  with patch.dict(os.environ, {"LOG_LEVEL": "TRACE"}):
91
  import importlib
92
+ import kiro.config as config_module
93
  importlib.reload(config_module)
94
 
95
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
 
104
 
105
  with patch.dict(os.environ, {"LOG_LEVEL": "ERROR"}):
106
  import importlib
107
+ import kiro.config as config_module
108
  importlib.reload(config_module)
109
 
110
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
 
119
 
120
  with patch.dict(os.environ, {"LOG_LEVEL": "CRITICAL"}):
121
  import importlib
122
+ import kiro.config as config_module
123
  importlib.reload(config_module)
124
 
125
  print(f"LOG_LEVEL: {config_module.LOG_LEVEL}")
 
141
  del os.environ["TOOL_DESCRIPTION_MAX_LENGTH"]
142
 
143
  import importlib
144
+ import kiro.config as config_module
145
  importlib.reload(config_module)
146
 
147
  print(f"TOOL_DESCRIPTION_MAX_LENGTH: {config_module.TOOL_DESCRIPTION_MAX_LENGTH}")
 
156
 
157
  with patch.dict(os.environ, {"TOOL_DESCRIPTION_MAX_LENGTH": "5000"}):
158
  import importlib
159
+ import kiro.config as config_module
160
  importlib.reload(config_module)
161
 
162
  print(f"TOOL_DESCRIPTION_MAX_LENGTH: {config_module.TOOL_DESCRIPTION_MAX_LENGTH}")
 
171
 
172
  with patch.dict(os.environ, {"TOOL_DESCRIPTION_MAX_LENGTH": "0"}):
173
  import importlib
174
+ import kiro.config as config_module
175
  importlib.reload(config_module)
176
 
177
  print(f"TOOL_DESCRIPTION_MAX_LENGTH: {config_module.TOOL_DESCRIPTION_MAX_LENGTH}")
 
193
  "STREAMING_READ_TIMEOUT": "300"
194
  }):
195
  import importlib
196
+ import kiro.config as config_module
197
  importlib.reload(config_module)
198
 
199
  # Call the warning function
 
218
  "STREAMING_READ_TIMEOUT": "300"
219
  }):
220
  import importlib
221
+ import kiro.config as config_module
222
  importlib.reload(config_module)
223
 
224
  # Call the warning function
 
242
  "STREAMING_READ_TIMEOUT": "300"
243
  }):
244
  import importlib
245
+ import kiro.config as config_module
246
  importlib.reload(config_module)
247
 
248
  # Call the warning function
 
269
  "STREAMING_READ_TIMEOUT": "300"
270
  }):
271
  import importlib
272
+ import kiro.config as config_module
273
  importlib.reload(config_module)
274
 
275
  # Call the warning function
 
292
  """
293
  print("Setup: Importing config module...")
294
  import importlib
295
+ import kiro.config as config_module
296
  importlib.reload(config_module)
297
 
298
  print("Verification: AWS_SSO_OIDC_URL_TEMPLATE exists...")
 
309
  Purpose: Ensure the function formats URL correctly.
310
  """
311
  print("Setup: Importing get_aws_sso_oidc_url...")
312
+ from kiro.config import get_aws_sso_oidc_url
313
 
314
  print("Action: Calling get_aws_sso_oidc_url('us-east-1')...")
315
  url = get_aws_sso_oidc_url("us-east-1")
 
325
  Purpose: Ensure the function works with various AWS regions.
326
  """
327
  print("Setup: Importing get_aws_sso_oidc_url...")
328
+ from kiro.config import get_aws_sso_oidc_url
329
 
330
  test_cases = [
331
  ("us-east-1", "https://oidc.us-east-1.amazonaws.com/token"),
 
356
  del os.environ["SERVER_HOST"]
357
 
358
  import importlib
359
+ import kiro.config as config_module
360
  importlib.reload(config_module)
361
 
362
  print(f"SERVER_HOST: {config_module.SERVER_HOST}")
 
374
 
375
  with patch.dict(os.environ, {"SERVER_HOST": "127.0.0.1"}):
376
  import importlib
377
+ import kiro.config as config_module
378
  importlib.reload(config_module)
379
 
380
  print(f"SERVER_HOST: {config_module.SERVER_HOST}")
 
390
 
391
  with patch.dict(os.environ, {"SERVER_HOST": "192.168.1.100"}):
392
  import importlib
393
+ import kiro.config as config_module
394
  importlib.reload(config_module)
395
 
396
  print(f"SERVER_HOST: {config_module.SERVER_HOST}")
 
412
  del os.environ["SERVER_PORT"]
413
 
414
  import importlib
415
+ import kiro.config as config_module
416
  importlib.reload(config_module)
417
 
418
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
 
430
 
431
  with patch.dict(os.environ, {"SERVER_PORT": "9000"}):
432
  import importlib
433
+ import kiro.config as config_module
434
  importlib.reload(config_module)
435
 
436
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
 
446
 
447
  with patch.dict(os.environ, {"SERVER_PORT": "3000"}):
448
  import importlib
449
+ import kiro.config as config_module
450
  importlib.reload(config_module)
451
 
452
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
 
461
 
462
  with patch.dict(os.environ, {"SERVER_PORT": "8080"}):
463
  import importlib
464
+ import kiro.config as config_module
465
  importlib.reload(config_module)
466
 
467
  print(f"SERVER_PORT: {config_module.SERVER_PORT}")
 
480
  """
481
  print("Setup: Importing config module...")
482
  import importlib
483
+ import kiro.config as config_module
484
  importlib.reload(config_module)
485
 
486
  print("Verification: KIRO_CLI_DB_FILE exists...")
 
499
 
500
  with patch.dict(os.environ, {"KIRO_CLI_DB_FILE": "~/.local/share/kiro-cli/data.sqlite3"}):
501
  import importlib
502
+ import kiro.config as config_module
503
  importlib.reload(config_module)
504
 
505
  print(f"KIRO_CLI_DB_FILE: {config_module.KIRO_CLI_DB_FILE}")
tests/unit/test_converters.py CHANGED
@@ -9,7 +9,7 @@ import pytest
9
 
10
  from unittest.mock import patch
11
 
12
- from kiro_gateway.converters import (
13
  extract_text_content,
14
  merge_adjacent_messages,
15
  build_kiro_history,
@@ -21,7 +21,7 @@ from kiro_gateway.converters import (
21
  _build_user_input_context,
22
  _sanitize_json_schema
23
  )
24
- from kiro_gateway.models import ChatMessage, ChatCompletionRequest, Tool, ToolFunction
25
 
26
 
27
  class TestExtractTextContent:
@@ -751,7 +751,7 @@ class TestProcessToolsWithLongDescriptions:
751
  )]
752
 
753
  print("Action: Processing tools...")
754
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
755
  processed, doc = process_tools_with_long_descriptions(tools)
756
 
757
  print(f"Comparing description: Expected 'Get weather for a location', Got '{processed[0].function.description}'")
@@ -776,7 +776,7 @@ class TestProcessToolsWithLongDescriptions:
776
  )]
777
 
778
  print("Action: Processing tools with limit 10000...")
779
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
780
  processed, doc = process_tools_with_long_descriptions(tools)
781
 
782
  print(f"Checking reference in description...")
@@ -816,7 +816,7 @@ class TestProcessToolsWithLongDescriptions:
816
  ]
817
 
818
  print("Action: Processing tools...")
819
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
820
  processed, doc = process_tools_with_long_descriptions(tools)
821
 
822
  print(f"Checking tools count: Expected 2, Got {len(processed)}")
@@ -854,7 +854,7 @@ class TestProcessToolsWithLongDescriptions:
854
  )]
855
 
856
  print("Action: Processing tools...")
857
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
858
  processed, doc = process_tools_with_long_descriptions(tools)
859
 
860
  print(f"Checking parameters preservation...")
@@ -877,7 +877,7 @@ class TestProcessToolsWithLongDescriptions:
877
  )]
878
 
879
  print("Action: Processing tools with limit 0...")
880
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 0):
881
  processed, doc = process_tools_with_long_descriptions(tools)
882
 
883
  print(f"Checking that description is unchanged...")
@@ -901,7 +901,7 @@ class TestProcessToolsWithLongDescriptions:
901
  )]
902
 
903
  print("Action: Processing tools...")
904
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
905
  processed, doc = process_tools_with_long_descriptions(tools)
906
 
907
  print(f"Checking that tool is unchanged...")
@@ -922,7 +922,7 @@ class TestProcessToolsWithLongDescriptions:
922
  ]
923
 
924
  print("Action: Processing tools...")
925
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
926
  processed, doc = process_tools_with_long_descriptions(tools)
927
 
928
  print(f"Checking all three tools...")
@@ -951,7 +951,7 @@ class TestProcessToolsWithLongDescriptions:
951
  )]
952
 
953
  print("Action: Processing tools...")
954
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
955
  processed, doc = process_tools_with_long_descriptions(tools)
956
 
957
  print(f"Checking that empty description remains empty...")
@@ -974,7 +974,7 @@ class TestProcessToolsWithLongDescriptions:
974
  )]
975
 
976
  print("Action: Processing tools...")
977
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
978
  processed, doc = process_tools_with_long_descriptions(tools)
979
 
980
  print(f"Checking that None description is handled correctly...")
@@ -1497,7 +1497,7 @@ class TestInjectThinkingTags:
1497
  content = "Hello, world!"
1498
 
1499
  print("Action: Inject thinking tags with FAKE_REASONING_ENABLED=False...")
1500
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', False):
1501
  result = inject_thinking_tags(content)
1502
 
1503
  print(f"Comparing result: Expected 'Hello, world!', Got '{result}'")
@@ -1512,8 +1512,8 @@ class TestInjectThinkingTags:
1512
  content = "What is 2+2?"
1513
 
1514
  print("Action: Inject thinking tags with FAKE_REASONING_ENABLED=True...")
1515
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1516
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1517
  result = inject_thinking_tags(content)
1518
 
1519
  print(f"Result: {result[:200]}...")
@@ -1535,8 +1535,8 @@ class TestInjectThinkingTags:
1535
  content = "Analyze this code"
1536
 
1537
  print("Action: Inject thinking tags...")
1538
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1539
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 8000):
1540
  result = inject_thinking_tags(content)
1541
 
1542
  print(f"Result length: {len(result)} chars")
@@ -1553,8 +1553,8 @@ class TestInjectThinkingTags:
1553
  content = "Test"
1554
 
1555
  print("Action: Inject thinking tags...")
1556
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1557
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1558
  result = inject_thinking_tags(content)
1559
 
1560
  print("Checking for English directive...")
@@ -1569,8 +1569,8 @@ class TestInjectThinkingTags:
1569
  content = "Test"
1570
 
1571
  print("Action: Inject thinking tags...")
1572
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1573
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1574
  result = inject_thinking_tags(content)
1575
 
1576
  print("Checking for systematic approach keywords...")
@@ -1585,8 +1585,8 @@ class TestInjectThinkingTags:
1585
  content = "Test"
1586
 
1587
  print("Action: Inject thinking tags...")
1588
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1589
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1590
  result = inject_thinking_tags(content)
1591
 
1592
  print("Checking for understanding step...")
@@ -1601,8 +1601,8 @@ class TestInjectThinkingTags:
1601
  content = "Test"
1602
 
1603
  print("Action: Inject thinking tags...")
1604
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1605
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1606
  result = inject_thinking_tags(content)
1607
 
1608
  print("Checking for alternatives consideration...")
@@ -1617,8 +1617,8 @@ class TestInjectThinkingTags:
1617
  content = "Test"
1618
 
1619
  print("Action: Inject thinking tags...")
1620
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1621
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1622
  result = inject_thinking_tags(content)
1623
 
1624
  print("Checking for edge cases consideration...")
@@ -1633,8 +1633,8 @@ class TestInjectThinkingTags:
1633
  content = "Test"
1634
 
1635
  print("Action: Inject thinking tags...")
1636
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1637
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1638
  result = inject_thinking_tags(content)
1639
 
1640
  print("Checking for verification step...")
@@ -1649,8 +1649,8 @@ class TestInjectThinkingTags:
1649
  content = "Test"
1650
 
1651
  print("Action: Inject thinking tags...")
1652
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1653
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1654
  result = inject_thinking_tags(content)
1655
 
1656
  print("Checking for assumptions challenge...")
@@ -1665,8 +1665,8 @@ class TestInjectThinkingTags:
1665
  content = "Test"
1666
 
1667
  print("Action: Inject thinking tags...")
1668
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1669
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1670
  result = inject_thinking_tags(content)
1671
 
1672
  print("Checking for quality over speed emphasis...")
@@ -1681,8 +1681,8 @@ class TestInjectThinkingTags:
1681
  content = "Test"
1682
 
1683
  print("Action: Inject thinking tags with FAKE_REASONING_MAX_TOKENS=16000...")
1684
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1685
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 16000):
1686
  result = inject_thinking_tags(content)
1687
 
1688
  print(f"Result: {result[:300]}...")
@@ -1698,8 +1698,8 @@ class TestInjectThinkingTags:
1698
  content = ""
1699
 
1700
  print("Action: Inject thinking tags...")
1701
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1702
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1703
  result = inject_thinking_tags(content)
1704
 
1705
  print(f"Result length: {len(result)} chars")
@@ -1716,8 +1716,8 @@ class TestInjectThinkingTags:
1716
  content = "Line 1\nLine 2\nLine 3"
1717
 
1718
  print("Action: Inject thinking tags...")
1719
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1720
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1721
  result = inject_thinking_tags(content)
1722
 
1723
  print("Checking that multiline content is preserved...")
@@ -1732,8 +1732,8 @@ class TestInjectThinkingTags:
1732
  content = "Check this <code>example</code> and {json: 'value'}"
1733
 
1734
  print("Action: Inject thinking tags...")
1735
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1736
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1737
  result = inject_thinking_tags(content)
1738
 
1739
  print("Checking that special characters are preserved...")
@@ -1749,8 +1749,8 @@ class TestInjectThinkingTags:
1749
  content = "USER_CONTENT_HERE"
1750
 
1751
  print("Action: Inject thinking tags...")
1752
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
1753
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1754
  result = inject_thinking_tags(content)
1755
 
1756
  print("Checking tag order...")
@@ -1982,7 +1982,7 @@ class TestBuildKiroPayload:
1982
  )
1983
 
1984
  print("Action: Building payload (with fake reasoning disabled)...")
1985
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', False):
1986
  result = build_kiro_payload(request, "conv-123", "")
1987
 
1988
  print(f"Result: {result}")
@@ -2032,7 +2032,7 @@ class TestBuildKiroPayload:
2032
  )
2033
 
2034
  print("Action: Building payload...")
2035
- with patch('kiro_gateway.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
2036
  result = build_kiro_payload(request, "conv-123", "")
2037
 
2038
  print(f"Checking that system prompt contains tool documentation...")
@@ -2074,8 +2074,8 @@ class TestBuildKiroPayload:
2074
  )
2075
 
2076
  print("Action: Building payload with FAKE_REASONING_ENABLED=True...")
2077
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
2078
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
2079
  result = build_kiro_payload(request, "conv-123", "")
2080
 
2081
  current_msg = result["conversationState"]["currentMessage"]["userInputMessage"]
@@ -2101,8 +2101,8 @@ class TestBuildKiroPayload:
2101
  )
2102
 
2103
  print("Action: Building payload with FAKE_REASONING_ENABLED=True...")
2104
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
2105
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
2106
  result = build_kiro_payload(request, "conv-123", "")
2107
 
2108
  current_msg = result["conversationState"]["currentMessage"]["userInputMessage"]
 
9
 
10
  from unittest.mock import patch
11
 
12
+ from kiro.converters import (
13
  extract_text_content,
14
  merge_adjacent_messages,
15
  build_kiro_history,
 
21
  _build_user_input_context,
22
  _sanitize_json_schema
23
  )
24
+ from kiro.models import ChatMessage, ChatCompletionRequest, Tool, ToolFunction
25
 
26
 
27
  class TestExtractTextContent:
 
751
  )]
752
 
753
  print("Action: Processing tools...")
754
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
755
  processed, doc = process_tools_with_long_descriptions(tools)
756
 
757
  print(f"Comparing description: Expected 'Get weather for a location', Got '{processed[0].function.description}'")
 
776
  )]
777
 
778
  print("Action: Processing tools with limit 10000...")
779
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
780
  processed, doc = process_tools_with_long_descriptions(tools)
781
 
782
  print(f"Checking reference in description...")
 
816
  ]
817
 
818
  print("Action: Processing tools...")
819
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
820
  processed, doc = process_tools_with_long_descriptions(tools)
821
 
822
  print(f"Checking tools count: Expected 2, Got {len(processed)}")
 
854
  )]
855
 
856
  print("Action: Processing tools...")
857
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
858
  processed, doc = process_tools_with_long_descriptions(tools)
859
 
860
  print(f"Checking parameters preservation...")
 
877
  )]
878
 
879
  print("Action: Processing tools with limit 0...")
880
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 0):
881
  processed, doc = process_tools_with_long_descriptions(tools)
882
 
883
  print(f"Checking that description is unchanged...")
 
901
  )]
902
 
903
  print("Action: Processing tools...")
904
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
905
  processed, doc = process_tools_with_long_descriptions(tools)
906
 
907
  print(f"Checking that tool is unchanged...")
 
922
  ]
923
 
924
  print("Action: Processing tools...")
925
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
926
  processed, doc = process_tools_with_long_descriptions(tools)
927
 
928
  print(f"Checking all three tools...")
 
951
  )]
952
 
953
  print("Action: Processing tools...")
954
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
955
  processed, doc = process_tools_with_long_descriptions(tools)
956
 
957
  print(f"Checking that empty description remains empty...")
 
974
  )]
975
 
976
  print("Action: Processing tools...")
977
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
978
  processed, doc = process_tools_with_long_descriptions(tools)
979
 
980
  print(f"Checking that None description is handled correctly...")
 
1497
  content = "Hello, world!"
1498
 
1499
  print("Action: Inject thinking tags with FAKE_REASONING_ENABLED=False...")
1500
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', False):
1501
  result = inject_thinking_tags(content)
1502
 
1503
  print(f"Comparing result: Expected 'Hello, world!', Got '{result}'")
 
1512
  content = "What is 2+2?"
1513
 
1514
  print("Action: Inject thinking tags with FAKE_REASONING_ENABLED=True...")
1515
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1516
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1517
  result = inject_thinking_tags(content)
1518
 
1519
  print(f"Result: {result[:200]}...")
 
1535
  content = "Analyze this code"
1536
 
1537
  print("Action: Inject thinking tags...")
1538
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1539
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 8000):
1540
  result = inject_thinking_tags(content)
1541
 
1542
  print(f"Result length: {len(result)} chars")
 
1553
  content = "Test"
1554
 
1555
  print("Action: Inject thinking tags...")
1556
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1557
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1558
  result = inject_thinking_tags(content)
1559
 
1560
  print("Checking for English directive...")
 
1569
  content = "Test"
1570
 
1571
  print("Action: Inject thinking tags...")
1572
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1573
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1574
  result = inject_thinking_tags(content)
1575
 
1576
  print("Checking for systematic approach keywords...")
 
1585
  content = "Test"
1586
 
1587
  print("Action: Inject thinking tags...")
1588
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1589
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1590
  result = inject_thinking_tags(content)
1591
 
1592
  print("Checking for understanding step...")
 
1601
  content = "Test"
1602
 
1603
  print("Action: Inject thinking tags...")
1604
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1605
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1606
  result = inject_thinking_tags(content)
1607
 
1608
  print("Checking for alternatives consideration...")
 
1617
  content = "Test"
1618
 
1619
  print("Action: Inject thinking tags...")
1620
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1621
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1622
  result = inject_thinking_tags(content)
1623
 
1624
  print("Checking for edge cases consideration...")
 
1633
  content = "Test"
1634
 
1635
  print("Action: Inject thinking tags...")
1636
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1637
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1638
  result = inject_thinking_tags(content)
1639
 
1640
  print("Checking for verification step...")
 
1649
  content = "Test"
1650
 
1651
  print("Action: Inject thinking tags...")
1652
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1653
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1654
  result = inject_thinking_tags(content)
1655
 
1656
  print("Checking for assumptions challenge...")
 
1665
  content = "Test"
1666
 
1667
  print("Action: Inject thinking tags...")
1668
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1669
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1670
  result = inject_thinking_tags(content)
1671
 
1672
  print("Checking for quality over speed emphasis...")
 
1681
  content = "Test"
1682
 
1683
  print("Action: Inject thinking tags with FAKE_REASONING_MAX_TOKENS=16000...")
1684
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1685
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 16000):
1686
  result = inject_thinking_tags(content)
1687
 
1688
  print(f"Result: {result[:300]}...")
 
1698
  content = ""
1699
 
1700
  print("Action: Inject thinking tags...")
1701
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1702
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1703
  result = inject_thinking_tags(content)
1704
 
1705
  print(f"Result length: {len(result)} chars")
 
1716
  content = "Line 1\nLine 2\nLine 3"
1717
 
1718
  print("Action: Inject thinking tags...")
1719
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1720
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1721
  result = inject_thinking_tags(content)
1722
 
1723
  print("Checking that multiline content is preserved...")
 
1732
  content = "Check this <code>example</code> and {json: 'value'}"
1733
 
1734
  print("Action: Inject thinking tags...")
1735
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1736
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1737
  result = inject_thinking_tags(content)
1738
 
1739
  print("Checking that special characters are preserved...")
 
1749
  content = "USER_CONTENT_HERE"
1750
 
1751
  print("Action: Inject thinking tags...")
1752
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
1753
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
1754
  result = inject_thinking_tags(content)
1755
 
1756
  print("Checking tag order...")
 
1982
  )
1983
 
1984
  print("Action: Building payload (with fake reasoning disabled)...")
1985
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', False):
1986
  result = build_kiro_payload(request, "conv-123", "")
1987
 
1988
  print(f"Result: {result}")
 
2032
  )
2033
 
2034
  print("Action: Building payload...")
2035
+ with patch('kiro.converters.TOOL_DESCRIPTION_MAX_LENGTH', 10000):
2036
  result = build_kiro_payload(request, "conv-123", "")
2037
 
2038
  print(f"Checking that system prompt contains tool documentation...")
 
2074
  )
2075
 
2076
  print("Action: Building payload with FAKE_REASONING_ENABLED=True...")
2077
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
2078
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
2079
  result = build_kiro_payload(request, "conv-123", "")
2080
 
2081
  current_msg = result["conversationState"]["currentMessage"]["userInputMessage"]
 
2101
  )
2102
 
2103
  print("Action: Building payload with FAKE_REASONING_ENABLED=True...")
2104
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
2105
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
2106
  result = build_kiro_payload(request, "conv-123", "")
2107
 
2108
  current_msg = result["conversationState"]["currentMessage"]["userInputMessage"]
tests/unit/test_debug_logger.py CHANGED
@@ -20,10 +20,10 @@ class TestDebugLoggerModeOff:
20
  Цель: Убедиться, что в режиме off директория не создаётся.
21
  """
22
  print("Настройка: Режим off...")
23
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'off'):
24
- with patch('kiro_gateway.debug_logger.DEBUG_DIR', str(tmp_path / "debug_logs")):
25
  # Пересоздаём экземпляр с новыми настройками
26
- from kiro_gateway.debug_logger import DebugLogger
27
  logger = DebugLogger.__new__(DebugLogger)
28
  logger._initialized = False
29
  logger.__init__()
@@ -41,8 +41,8 @@ class TestDebugLoggerModeOff:
41
  Цель: Убедиться, что данные не записываются.
42
  """
43
  print("Настройка: Режим off...")
44
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'off'):
45
- from kiro_gateway.debug_logger import DebugLogger
46
  logger = DebugLogger.__new__(DebugLogger)
47
  logger._initialized = False
48
  logger.__init__()
@@ -69,8 +69,8 @@ class TestDebugLoggerModeAll:
69
  old_file = debug_dir / "old_file.txt"
70
  old_file.write_text("old content")
71
 
72
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
73
- from kiro_gateway.debug_logger import DebugLogger
74
  logger = DebugLogger.__new__(DebugLogger)
75
  logger._initialized = False
76
  logger.__init__()
@@ -93,8 +93,8 @@ class TestDebugLoggerModeAll:
93
  debug_dir = tmp_path / "debug_logs"
94
  debug_dir.mkdir()
95
 
96
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
97
- from kiro_gateway.debug_logger import DebugLogger
98
  logger = DebugLogger.__new__(DebugLogger)
99
  logger._initialized = False
100
  logger.__init__()
@@ -121,8 +121,8 @@ class TestDebugLoggerModeAll:
121
  debug_dir = tmp_path / "debug_logs"
122
  debug_dir.mkdir()
123
 
124
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
125
- from kiro_gateway.debug_logger import DebugLogger
126
  logger = DebugLogger.__new__(DebugLogger)
127
  logger._initialized = False
128
  logger.__init__()
@@ -145,8 +145,8 @@ class TestDebugLoggerModeAll:
145
  debug_dir = tmp_path / "debug_logs"
146
  debug_dir.mkdir()
147
 
148
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
149
- from kiro_gateway.debug_logger import DebugLogger
150
  logger = DebugLogger.__new__(DebugLogger)
151
  logger._initialized = False
152
  logger.__init__()
@@ -173,8 +173,8 @@ class TestDebugLoggerModeErrors:
173
  print("Настройка: Режим errors...")
174
  debug_dir = tmp_path / "debug_logs"
175
 
176
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
177
- from kiro_gateway.debug_logger import DebugLogger
178
  logger = DebugLogger.__new__(DebugLogger)
179
  logger._initialized = False
180
  logger.__init__()
@@ -198,8 +198,8 @@ class TestDebugLoggerModeErrors:
198
  print("Настройка: Режим errors, заполняем буферы...")
199
  debug_dir = tmp_path / "debug_logs"
200
 
201
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
202
- from kiro_gateway.debug_logger import DebugLogger
203
  logger = DebugLogger.__new__(DebugLogger)
204
  logger._initialized = False
205
  logger.__init__()
@@ -234,8 +234,8 @@ class TestDebugLoggerModeErrors:
234
  print("Настройка: Режим errors...")
235
  debug_dir = tmp_path / "debug_logs"
236
 
237
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
238
- from kiro_gateway.debug_logger import DebugLogger
239
  logger = DebugLogger.__new__(DebugLogger)
240
  logger._initialized = False
241
  logger.__init__()
@@ -260,8 +260,8 @@ class TestDebugLoggerModeErrors:
260
  print("Настройка: Режим errors, заполняем буферы...")
261
  debug_dir = tmp_path / "debug_logs"
262
 
263
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
264
- from kiro_gateway.debug_logger import DebugLogger
265
  logger = DebugLogger.__new__(DebugLogger)
266
  logger._initialized = False
267
  logger.__init__()
@@ -288,8 +288,8 @@ class TestDebugLoggerModeErrors:
288
  print("Настройка: Режим all...")
289
  debug_dir = tmp_path / "debug_logs"
290
 
291
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
292
- from kiro_gateway.debug_logger import DebugLogger
293
  logger = DebugLogger.__new__(DebugLogger)
294
  logger._initialized = False
295
  logger.__init__()
@@ -318,8 +318,8 @@ class TestDebugLoggerLogErrorInfo:
318
  print("Настройка: Режим all...")
319
  debug_dir = tmp_path / "debug_logs"
320
 
321
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
322
- from kiro_gateway.debug_logger import DebugLogger
323
  logger = DebugLogger.__new__(DebugLogger)
324
  logger._initialized = False
325
  logger.__init__()
@@ -345,8 +345,8 @@ class TestDebugLoggerLogErrorInfo:
345
  print("Настройка: Режим errors...")
346
  debug_dir = tmp_path / "debug_logs"
347
 
348
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
349
- from kiro_gateway.debug_logger import DebugLogger
350
  logger = DebugLogger.__new__(DebugLogger)
351
  logger._initialized = False
352
  logger.__init__()
@@ -367,8 +367,8 @@ class TestDebugLoggerLogErrorInfo:
367
  print("Настройка: Режим off...")
368
  debug_dir = tmp_path / "debug_logs"
369
 
370
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'off'):
371
- from kiro_gateway.debug_logger import DebugLogger
372
  logger = DebugLogger.__new__(DebugLogger)
373
  logger._initialized = False
374
  logger.__init__()
@@ -390,8 +390,8 @@ class TestDebugLoggerHelperMethods:
390
  Цель: Убедиться, что режим errors считается включённым.
391
  """
392
  print("Настройка: Режим errors...")
393
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
394
- from kiro_gateway.debug_logger import DebugLogger
395
  logger = DebugLogger.__new__(DebugLogger)
396
  logger._initialized = False
397
  logger.__init__()
@@ -405,8 +405,8 @@ class TestDebugLoggerHelperMethods:
405
  Цель: Убедиться, что режим all считается включённым.
406
  """
407
  print("Настройка: Режим all...")
408
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
409
- from kiro_gateway.debug_logger import DebugLogger
410
  logger = DebugLogger.__new__(DebugLogger)
411
  logger._initialized = False
412
  logger.__init__()
@@ -420,8 +420,8 @@ class TestDebugLoggerHelperMethods:
420
  Цель: Убедиться, что режим off считается выключенным.
421
  """
422
  print("Настройка: Режим off...")
423
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'off'):
424
- from kiro_gateway.debug_logger import DebugLogger
425
  logger = DebugLogger.__new__(DebugLogger)
426
  logger._initialized = False
427
  logger.__init__()
@@ -435,8 +435,8 @@ class TestDebugLoggerHelperMethods:
435
  Цель: Убедиться, что режим all пишет сразу.
436
  """
437
  print("Настройка: Режим all...")
438
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
439
- from kiro_gateway.debug_logger import DebugLogger
440
  logger = DebugLogger.__new__(DebugLogger)
441
  logger._initialized = False
442
  logger.__init__()
@@ -450,8 +450,8 @@ class TestDebugLoggerHelperMethods:
450
  Цель: Убедиться, что режим errors буферизует.
451
  """
452
  print("Настройка: Режим errors...")
453
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
454
- from kiro_gateway.debug_logger import DebugLogger
455
  logger = DebugLogger.__new__(DebugLogger)
456
  logger._initialized = False
457
  logger.__init__()
@@ -472,8 +472,8 @@ class TestDebugLoggerJsonHandling:
472
  debug_dir = tmp_path / "debug_logs"
473
  debug_dir.mkdir()
474
 
475
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
476
- from kiro_gateway.debug_logger import DebugLogger
477
  logger = DebugLogger.__new__(DebugLogger)
478
  logger._initialized = False
479
  logger.__init__()
@@ -496,8 +496,8 @@ class TestDebugLoggerJsonHandling:
496
  debug_dir = tmp_path / "debug_logs"
497
  debug_dir.mkdir()
498
 
499
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
500
- from kiro_gateway.debug_logger import DebugLogger
501
  logger = DebugLogger.__new__(DebugLogger)
502
  logger._initialized = False
503
  logger.__init__()
@@ -523,8 +523,8 @@ class TestDebugLoggerAppLogsCapture:
523
  print("Настройка: Режим all...")
524
  debug_dir = tmp_path / "debug_logs"
525
 
526
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
527
- from kiro_gateway.debug_logger import DebugLogger
528
  dbg_logger = DebugLogger.__new__(DebugLogger)
529
  dbg_logger._initialized = False
530
  dbg_logger.__init__()
@@ -547,8 +547,8 @@ class TestDebugLoggerAppLogsCapture:
547
  print("Настройка: Режим errors...")
548
  debug_dir = tmp_path / "debug_logs"
549
 
550
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
551
- from kiro_gateway.debug_logger import DebugLogger
552
  from loguru import logger as loguru_logger
553
 
554
  dbg_logger = DebugLogger.__new__(DebugLogger)
@@ -585,8 +585,8 @@ class TestDebugLoggerAppLogsCapture:
585
  debug_dir = tmp_path / "debug_logs"
586
  debug_dir.mkdir()
587
 
588
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
589
- from kiro_gateway.debug_logger import DebugLogger
590
 
591
  dbg_logger = DebugLogger.__new__(DebugLogger)
592
  dbg_logger._initialized = False
@@ -618,8 +618,8 @@ class TestDebugLoggerAppLogsCapture:
618
  print("Настройка: Режим errors...")
619
  debug_dir = tmp_path / "debug_logs"
620
 
621
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'errors'):
622
- from kiro_gateway.debug_logger import DebugLogger
623
 
624
  dbg_logger = DebugLogger.__new__(DebugLogger)
625
  dbg_logger._initialized = False
@@ -644,8 +644,8 @@ class TestDebugLoggerAppLogsCapture:
644
  Цель: Убедиться, что sink корректно удаляется.
645
  """
646
  print("Настройка: Режим all...")
647
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
648
- from kiro_gateway.debug_logger import DebugLogger
649
 
650
  dbg_logger = DebugLogger.__new__(DebugLogger)
651
  dbg_logger._initialized = False
@@ -672,8 +672,8 @@ class TestDebugLoggerAppLogsCapture:
672
  debug_dir = tmp_path / "debug_logs"
673
  debug_dir.mkdir()
674
 
675
- with patch('kiro_gateway.debug_logger.DEBUG_MODE', 'all'):
676
- from kiro_gateway.debug_logger import DebugLogger
677
 
678
  dbg_logger = DebugLogger.__new__(DebugLogger)
679
  dbg_logger._initialized = False
 
20
  Цель: Убедиться, что в режиме off директория не создаётся.
21
  """
22
  print("Настройка: Режим off...")
23
+ with patch('kiro.debug_logger.DEBUG_MODE', 'off'):
24
+ with patch('kiro.debug_logger.DEBUG_DIR', str(tmp_path / "debug_logs")):
25
  # Пересоздаём экземпляр с новыми настройками
26
+ from kiro.debug_logger import DebugLogger
27
  logger = DebugLogger.__new__(DebugLogger)
28
  logger._initialized = False
29
  logger.__init__()
 
41
  Цель: Убедиться, что данные не записываются.
42
  """
43
  print("Настройка: Режим off...")
44
+ with patch('kiro.debug_logger.DEBUG_MODE', 'off'):
45
+ from kiro.debug_logger import DebugLogger
46
  logger = DebugLogger.__new__(DebugLogger)
47
  logger._initialized = False
48
  logger.__init__()
 
69
  old_file = debug_dir / "old_file.txt"
70
  old_file.write_text("old content")
71
 
72
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
73
+ from kiro.debug_logger import DebugLogger
74
  logger = DebugLogger.__new__(DebugLogger)
75
  logger._initialized = False
76
  logger.__init__()
 
93
  debug_dir = tmp_path / "debug_logs"
94
  debug_dir.mkdir()
95
 
96
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
97
+ from kiro.debug_logger import DebugLogger
98
  logger = DebugLogger.__new__(DebugLogger)
99
  logger._initialized = False
100
  logger.__init__()
 
121
  debug_dir = tmp_path / "debug_logs"
122
  debug_dir.mkdir()
123
 
124
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
125
+ from kiro.debug_logger import DebugLogger
126
  logger = DebugLogger.__new__(DebugLogger)
127
  logger._initialized = False
128
  logger.__init__()
 
145
  debug_dir = tmp_path / "debug_logs"
146
  debug_dir.mkdir()
147
 
148
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
149
+ from kiro.debug_logger import DebugLogger
150
  logger = DebugLogger.__new__(DebugLogger)
151
  logger._initialized = False
152
  logger.__init__()
 
173
  print("Настройка: Режим errors...")
174
  debug_dir = tmp_path / "debug_logs"
175
 
176
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
177
+ from kiro.debug_logger import DebugLogger
178
  logger = DebugLogger.__new__(DebugLogger)
179
  logger._initialized = False
180
  logger.__init__()
 
198
  print("Настройка: Режим errors, заполняем буферы...")
199
  debug_dir = tmp_path / "debug_logs"
200
 
201
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
202
+ from kiro.debug_logger import DebugLogger
203
  logger = DebugLogger.__new__(DebugLogger)
204
  logger._initialized = False
205
  logger.__init__()
 
234
  print("Настройка: Режим errors...")
235
  debug_dir = tmp_path / "debug_logs"
236
 
237
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
238
+ from kiro.debug_logger import DebugLogger
239
  logger = DebugLogger.__new__(DebugLogger)
240
  logger._initialized = False
241
  logger.__init__()
 
260
  print("Настройка: Режим errors, заполняем буферы...")
261
  debug_dir = tmp_path / "debug_logs"
262
 
263
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
264
+ from kiro.debug_logger import DebugLogger
265
  logger = DebugLogger.__new__(DebugLogger)
266
  logger._initialized = False
267
  logger.__init__()
 
288
  print("Настройка: Режим all...")
289
  debug_dir = tmp_path / "debug_logs"
290
 
291
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
292
+ from kiro.debug_logger import DebugLogger
293
  logger = DebugLogger.__new__(DebugLogger)
294
  logger._initialized = False
295
  logger.__init__()
 
318
  print("Настройка: Режим all...")
319
  debug_dir = tmp_path / "debug_logs"
320
 
321
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
322
+ from kiro.debug_logger import DebugLogger
323
  logger = DebugLogger.__new__(DebugLogger)
324
  logger._initialized = False
325
  logger.__init__()
 
345
  print("Настройка: Режим errors...")
346
  debug_dir = tmp_path / "debug_logs"
347
 
348
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
349
+ from kiro.debug_logger import DebugLogger
350
  logger = DebugLogger.__new__(DebugLogger)
351
  logger._initialized = False
352
  logger.__init__()
 
367
  print("Настройка: Режим off...")
368
  debug_dir = tmp_path / "debug_logs"
369
 
370
+ with patch('kiro.debug_logger.DEBUG_MODE', 'off'):
371
+ from kiro.debug_logger import DebugLogger
372
  logger = DebugLogger.__new__(DebugLogger)
373
  logger._initialized = False
374
  logger.__init__()
 
390
  Цель: Убедиться, что режим errors считается включённым.
391
  """
392
  print("Настройка: Режим errors...")
393
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
394
+ from kiro.debug_logger import DebugLogger
395
  logger = DebugLogger.__new__(DebugLogger)
396
  logger._initialized = False
397
  logger.__init__()
 
405
  Цель: Убедиться, что режим all считается включённым.
406
  """
407
  print("Настройка: Режим all...")
408
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
409
+ from kiro.debug_logger import DebugLogger
410
  logger = DebugLogger.__new__(DebugLogger)
411
  logger._initialized = False
412
  logger.__init__()
 
420
  Цель: Убедиться, что режим off считается выключенным.
421
  """
422
  print("Настройка: Режим off...")
423
+ with patch('kiro.debug_logger.DEBUG_MODE', 'off'):
424
+ from kiro.debug_logger import DebugLogger
425
  logger = DebugLogger.__new__(DebugLogger)
426
  logger._initialized = False
427
  logger.__init__()
 
435
  Цель: Убедиться, что режим all пишет сразу.
436
  """
437
  print("Настройка: Режим all...")
438
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
439
+ from kiro.debug_logger import DebugLogger
440
  logger = DebugLogger.__new__(DebugLogger)
441
  logger._initialized = False
442
  logger.__init__()
 
450
  Цель: Убедиться, что режим errors буферизует.
451
  """
452
  print("Настройка: Режим errors...")
453
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
454
+ from kiro.debug_logger import DebugLogger
455
  logger = DebugLogger.__new__(DebugLogger)
456
  logger._initialized = False
457
  logger.__init__()
 
472
  debug_dir = tmp_path / "debug_logs"
473
  debug_dir.mkdir()
474
 
475
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
476
+ from kiro.debug_logger import DebugLogger
477
  logger = DebugLogger.__new__(DebugLogger)
478
  logger._initialized = False
479
  logger.__init__()
 
496
  debug_dir = tmp_path / "debug_logs"
497
  debug_dir.mkdir()
498
 
499
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
500
+ from kiro.debug_logger import DebugLogger
501
  logger = DebugLogger.__new__(DebugLogger)
502
  logger._initialized = False
503
  logger.__init__()
 
523
  print("Настройка: Режим all...")
524
  debug_dir = tmp_path / "debug_logs"
525
 
526
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
527
+ from kiro.debug_logger import DebugLogger
528
  dbg_logger = DebugLogger.__new__(DebugLogger)
529
  dbg_logger._initialized = False
530
  dbg_logger.__init__()
 
547
  print("Настройка: Режим errors...")
548
  debug_dir = tmp_path / "debug_logs"
549
 
550
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
551
+ from kiro.debug_logger import DebugLogger
552
  from loguru import logger as loguru_logger
553
 
554
  dbg_logger = DebugLogger.__new__(DebugLogger)
 
585
  debug_dir = tmp_path / "debug_logs"
586
  debug_dir.mkdir()
587
 
588
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
589
+ from kiro.debug_logger import DebugLogger
590
 
591
  dbg_logger = DebugLogger.__new__(DebugLogger)
592
  dbg_logger._initialized = False
 
618
  print("Настройка: Режим errors...")
619
  debug_dir = tmp_path / "debug_logs"
620
 
621
+ with patch('kiro.debug_logger.DEBUG_MODE', 'errors'):
622
+ from kiro.debug_logger import DebugLogger
623
 
624
  dbg_logger = DebugLogger.__new__(DebugLogger)
625
  dbg_logger._initialized = False
 
644
  Цель: Убедиться, что sink корректно удаляется.
645
  """
646
  print("Настройка: Режим all...")
647
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
648
+ from kiro.debug_logger import DebugLogger
649
 
650
  dbg_logger = DebugLogger.__new__(DebugLogger)
651
  dbg_logger._initialized = False
 
672
  debug_dir = tmp_path / "debug_logs"
673
  debug_dir.mkdir()
674
 
675
+ with patch('kiro.debug_logger.DEBUG_MODE', 'all'):
676
+ from kiro.debug_logger import DebugLogger
677
 
678
  dbg_logger = DebugLogger.__new__(DebugLogger)
679
  dbg_logger._initialized = False
tests/unit/test_http_client.py CHANGED
@@ -13,9 +13,9 @@ from datetime import datetime, timezone, timedelta
13
  import httpx
14
  from fastapi import HTTPException
15
 
16
- from kiro_gateway.http_client import KiroHttpClient
17
- from kiro_gateway.auth import KiroAuthManager
18
- from kiro_gateway.config import MAX_RETRIES, BASE_RETRY_DELAY, FIRST_TOKEN_MAX_RETRIES, STREAMING_READ_TIMEOUT
19
 
20
 
21
  @pytest.fixture
@@ -68,7 +68,7 @@ class TestKiroHttpClientGetClient:
68
  http_client = KiroHttpClient(mock_auth_manager_for_http)
69
 
70
  print("Action: Getting client...")
71
- with patch('kiro_gateway.http_client.httpx.AsyncClient') as mock_async_client:
72
  mock_instance = AsyncMock()
73
  mock_instance.is_closed = False
74
  mock_async_client.return_value = mock_instance
@@ -112,7 +112,7 @@ class TestKiroHttpClientGetClient:
112
  http_client.client = mock_closed
113
 
114
  print("Action: Getting client...")
115
- with patch('kiro_gateway.http_client.httpx.AsyncClient') as mock_async_client:
116
  mock_new = AsyncMock()
117
  mock_new.is_closed = False
118
  mock_async_client.return_value = mock_new
@@ -202,7 +202,7 @@ class TestKiroHttpClientRequestWithRetry:
202
 
203
  print("Action: Executing request...")
204
  with patch.object(http_client, '_get_client', return_value=mock_client):
205
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
206
  response = await http_client.request_with_retry(
207
  "POST",
208
  "https://api.example.com/test",
@@ -234,7 +234,7 @@ class TestKiroHttpClientRequestWithRetry:
234
 
235
  print("Action: Executing request...")
236
  with patch.object(http_client, '_get_client', return_value=mock_client):
237
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
238
  response = await http_client.request_with_retry(
239
  "POST",
240
  "https://api.example.com/test",
@@ -266,8 +266,8 @@ class TestKiroHttpClientRequestWithRetry:
266
 
267
  print("Action: Executing request...")
268
  with patch.object(http_client, '_get_client', return_value=mock_client):
269
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
270
- with patch('kiro_gateway.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
271
  response = await http_client.request_with_retry(
272
  "POST",
273
  "https://api.example.com/test",
@@ -299,8 +299,8 @@ class TestKiroHttpClientRequestWithRetry:
299
 
300
  print("Action: Executing request...")
301
  with patch.object(http_client, '_get_client', return_value=mock_client):
302
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
303
- with patch('kiro_gateway.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
304
  response = await http_client.request_with_retry(
305
  "POST",
306
  "https://api.example.com/test",
@@ -332,8 +332,8 @@ class TestKiroHttpClientRequestWithRetry:
332
 
333
  print("Action: Executing request...")
334
  with patch.object(http_client, '_get_client', return_value=mock_client):
335
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
336
- with patch('kiro_gateway.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
337
  response = await http_client.request_with_retry(
338
  "POST",
339
  "https://api.example.com/test",
@@ -365,8 +365,8 @@ class TestKiroHttpClientRequestWithRetry:
365
 
366
  print("Action: Executing request...")
367
  with patch.object(http_client, '_get_client', return_value=mock_client):
368
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
369
- with patch('kiro_gateway.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
370
  response = await http_client.request_with_retry(
371
  "POST",
372
  "https://api.example.com/test",
@@ -392,8 +392,8 @@ class TestKiroHttpClientRequestWithRetry:
392
 
393
  print("Action: Executing request...")
394
  with patch.object(http_client, '_get_client', return_value=mock_client):
395
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
396
- with patch('kiro_gateway.http_client.asyncio.sleep', new_callable=AsyncMock):
397
  with pytest.raises(HTTPException) as exc_info:
398
  await http_client.request_with_retry(
399
  "POST",
@@ -423,7 +423,7 @@ class TestKiroHttpClientRequestWithRetry:
423
 
424
  print("Action: Executing request...")
425
  with patch.object(http_client, '_get_client', return_value=mock_client):
426
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
427
  response = await http_client.request_with_retry(
428
  "POST",
429
  "https://api.example.com/test",
@@ -455,7 +455,7 @@ class TestKiroHttpClientRequestWithRetry:
455
 
456
  print("Action: Executing streaming request...")
457
  with patch.object(http_client, '_get_client', return_value=mock_client):
458
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
459
  response = await http_client.request_with_retry(
460
  "POST",
461
  "https://api.example.com/test",
@@ -542,8 +542,8 @@ class TestKiroHttpClientExponentialBackoff:
542
 
543
  print("Action: Executing request with multiple retries...")
544
  with patch.object(http_client, '_get_client', return_value=mock_client):
545
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
546
- with patch('kiro_gateway.http_client.asyncio.sleep', side_effect=capture_sleep):
547
  response = await http_client.request_with_retry(
548
  "POST",
549
  "https://api.example.com/test",
@@ -580,10 +580,10 @@ class TestKiroHttpClientStreamingTimeout:
580
  mock_client.send = AsyncMock(return_value=mock_response)
581
 
582
  print("Action: Executing streaming request...")
583
- with patch('kiro_gateway.http_client.httpx.AsyncClient') as mock_async_client:
584
  mock_async_client.return_value = mock_client
585
 
586
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
587
  response = await http_client.request_with_retry(
588
  "POST",
589
  "https://api.example.com/test",
@@ -619,8 +619,8 @@ class TestKiroHttpClientStreamingTimeout:
619
  mock_client.send = AsyncMock(side_effect=httpx.TimeoutException("Timeout"))
620
 
621
  print("Action: Executing streaming request with timeouts...")
622
- with patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_client):
623
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
624
  with pytest.raises(HTTPException) as exc_info:
625
  await http_client.request_with_retry(
626
  "POST",
@@ -666,9 +666,9 @@ class TestKiroHttpClientStreamingTimeout:
666
  sleep_called = True
667
 
668
  print("Action: Executing streaming request with one timeout...")
669
- with patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_client):
670
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
671
- with patch('kiro_gateway.http_client.asyncio.sleep', side_effect=capture_sleep):
672
  response = await http_client.request_with_retry(
673
  "POST",
674
  "https://api.example.com/test",
@@ -697,10 +697,10 @@ class TestKiroHttpClientStreamingTimeout:
697
  mock_client.request = AsyncMock(return_value=mock_response)
698
 
699
  print("Action: Executing non-streaming request...")
700
- with patch('kiro_gateway.http_client.httpx.AsyncClient') as mock_async_client:
701
  mock_async_client.return_value = mock_client
702
 
703
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
704
  response = await http_client.request_with_retry(
705
  "POST",
706
  "https://api.example.com/test",
@@ -742,9 +742,9 @@ class TestKiroHttpClientStreamingTimeout:
742
  ])
743
 
744
  print("Action: Executing streaming request with ConnectTimeout...")
745
- with patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_client):
746
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
747
- with patch('kiro_gateway.http_client.logger') as mock_logger:
748
  response = await http_client.request_with_retry(
749
  "POST",
750
  "https://api.example.com/test",
@@ -781,9 +781,9 @@ class TestKiroHttpClientStreamingTimeout:
781
  ])
782
 
783
  print("Action: Executing streaming request with ReadTimeout...")
784
- with patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_client):
785
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
786
- with patch('kiro_gateway.http_client.logger') as mock_logger:
787
  response = await http_client.request_with_retry(
788
  "POST",
789
  "https://api.example.com/test",
@@ -814,8 +814,8 @@ class TestKiroHttpClientStreamingTimeout:
814
  mock_client.send = AsyncMock(side_effect=httpx.ReadTimeout("Timeout"))
815
 
816
  print("Action: Executing streaming request with persistent timeouts...")
817
- with patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_client):
818
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
819
  with pytest.raises(HTTPException) as exc_info:
820
  await http_client.request_with_retry(
821
  "POST",
@@ -845,9 +845,9 @@ class TestKiroHttpClientStreamingTimeout:
845
  mock_client.request = AsyncMock(side_effect=httpx.TimeoutException("Timeout"))
846
 
847
  print("Action: Executing non-streaming request with persistent timeouts...")
848
- with patch('kiro_gateway.http_client.httpx.AsyncClient', return_value=mock_client):
849
- with patch('kiro_gateway.http_client.get_kiro_headers', return_value={}):
850
- with patch('kiro_gateway.http_client.asyncio.sleep', new_callable=AsyncMock):
851
  with pytest.raises(HTTPException) as exc_info:
852
  await http_client.request_with_retry(
853
  "POST",
 
13
  import httpx
14
  from fastapi import HTTPException
15
 
16
+ from kiro.http_client import KiroHttpClient
17
+ from kiro.auth import KiroAuthManager
18
+ from kiro.config import MAX_RETRIES, BASE_RETRY_DELAY, FIRST_TOKEN_MAX_RETRIES, STREAMING_READ_TIMEOUT
19
 
20
 
21
  @pytest.fixture
 
68
  http_client = KiroHttpClient(mock_auth_manager_for_http)
69
 
70
  print("Action: Getting client...")
71
+ with patch('kiro.http_client.httpx.AsyncClient') as mock_async_client:
72
  mock_instance = AsyncMock()
73
  mock_instance.is_closed = False
74
  mock_async_client.return_value = mock_instance
 
112
  http_client.client = mock_closed
113
 
114
  print("Action: Getting client...")
115
+ with patch('kiro.http_client.httpx.AsyncClient') as mock_async_client:
116
  mock_new = AsyncMock()
117
  mock_new.is_closed = False
118
  mock_async_client.return_value = mock_new
 
202
 
203
  print("Action: Executing request...")
204
  with patch.object(http_client, '_get_client', return_value=mock_client):
205
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
206
  response = await http_client.request_with_retry(
207
  "POST",
208
  "https://api.example.com/test",
 
234
 
235
  print("Action: Executing request...")
236
  with patch.object(http_client, '_get_client', return_value=mock_client):
237
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
238
  response = await http_client.request_with_retry(
239
  "POST",
240
  "https://api.example.com/test",
 
266
 
267
  print("Action: Executing request...")
268
  with patch.object(http_client, '_get_client', return_value=mock_client):
269
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
270
+ with patch('kiro.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
271
  response = await http_client.request_with_retry(
272
  "POST",
273
  "https://api.example.com/test",
 
299
 
300
  print("Action: Executing request...")
301
  with patch.object(http_client, '_get_client', return_value=mock_client):
302
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
303
+ with patch('kiro.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
304
  response = await http_client.request_with_retry(
305
  "POST",
306
  "https://api.example.com/test",
 
332
 
333
  print("Action: Executing request...")
334
  with patch.object(http_client, '_get_client', return_value=mock_client):
335
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
336
+ with patch('kiro.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
337
  response = await http_client.request_with_retry(
338
  "POST",
339
  "https://api.example.com/test",
 
365
 
366
  print("Action: Executing request...")
367
  with patch.object(http_client, '_get_client', return_value=mock_client):
368
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
369
+ with patch('kiro.http_client.asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
370
  response = await http_client.request_with_retry(
371
  "POST",
372
  "https://api.example.com/test",
 
392
 
393
  print("Action: Executing request...")
394
  with patch.object(http_client, '_get_client', return_value=mock_client):
395
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
396
+ with patch('kiro.http_client.asyncio.sleep', new_callable=AsyncMock):
397
  with pytest.raises(HTTPException) as exc_info:
398
  await http_client.request_with_retry(
399
  "POST",
 
423
 
424
  print("Action: Executing request...")
425
  with patch.object(http_client, '_get_client', return_value=mock_client):
426
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
427
  response = await http_client.request_with_retry(
428
  "POST",
429
  "https://api.example.com/test",
 
455
 
456
  print("Action: Executing streaming request...")
457
  with patch.object(http_client, '_get_client', return_value=mock_client):
458
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
459
  response = await http_client.request_with_retry(
460
  "POST",
461
  "https://api.example.com/test",
 
542
 
543
  print("Action: Executing request with multiple retries...")
544
  with patch.object(http_client, '_get_client', return_value=mock_client):
545
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
546
+ with patch('kiro.http_client.asyncio.sleep', side_effect=capture_sleep):
547
  response = await http_client.request_with_retry(
548
  "POST",
549
  "https://api.example.com/test",
 
580
  mock_client.send = AsyncMock(return_value=mock_response)
581
 
582
  print("Action: Executing streaming request...")
583
+ with patch('kiro.http_client.httpx.AsyncClient') as mock_async_client:
584
  mock_async_client.return_value = mock_client
585
 
586
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
587
  response = await http_client.request_with_retry(
588
  "POST",
589
  "https://api.example.com/test",
 
619
  mock_client.send = AsyncMock(side_effect=httpx.TimeoutException("Timeout"))
620
 
621
  print("Action: Executing streaming request with timeouts...")
622
+ with patch('kiro.http_client.httpx.AsyncClient', return_value=mock_client):
623
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
624
  with pytest.raises(HTTPException) as exc_info:
625
  await http_client.request_with_retry(
626
  "POST",
 
666
  sleep_called = True
667
 
668
  print("Action: Executing streaming request with one timeout...")
669
+ with patch('kiro.http_client.httpx.AsyncClient', return_value=mock_client):
670
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
671
+ with patch('kiro.http_client.asyncio.sleep', side_effect=capture_sleep):
672
  response = await http_client.request_with_retry(
673
  "POST",
674
  "https://api.example.com/test",
 
697
  mock_client.request = AsyncMock(return_value=mock_response)
698
 
699
  print("Action: Executing non-streaming request...")
700
+ with patch('kiro.http_client.httpx.AsyncClient') as mock_async_client:
701
  mock_async_client.return_value = mock_client
702
 
703
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
704
  response = await http_client.request_with_retry(
705
  "POST",
706
  "https://api.example.com/test",
 
742
  ])
743
 
744
  print("Action: Executing streaming request with ConnectTimeout...")
745
+ with patch('kiro.http_client.httpx.AsyncClient', return_value=mock_client):
746
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
747
+ with patch('kiro.http_client.logger') as mock_logger:
748
  response = await http_client.request_with_retry(
749
  "POST",
750
  "https://api.example.com/test",
 
781
  ])
782
 
783
  print("Action: Executing streaming request with ReadTimeout...")
784
+ with patch('kiro.http_client.httpx.AsyncClient', return_value=mock_client):
785
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
786
+ with patch('kiro.http_client.logger') as mock_logger:
787
  response = await http_client.request_with_retry(
788
  "POST",
789
  "https://api.example.com/test",
 
814
  mock_client.send = AsyncMock(side_effect=httpx.ReadTimeout("Timeout"))
815
 
816
  print("Action: Executing streaming request with persistent timeouts...")
817
+ with patch('kiro.http_client.httpx.AsyncClient', return_value=mock_client):
818
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
819
  with pytest.raises(HTTPException) as exc_info:
820
  await http_client.request_with_retry(
821
  "POST",
 
845
  mock_client.request = AsyncMock(side_effect=httpx.TimeoutException("Timeout"))
846
 
847
  print("Action: Executing non-streaming request with persistent timeouts...")
848
+ with patch('kiro.http_client.httpx.AsyncClient', return_value=mock_client):
849
+ with patch('kiro.http_client.get_kiro_headers', return_value={}):
850
+ with patch('kiro.http_client.asyncio.sleep', new_callable=AsyncMock):
851
  with pytest.raises(HTTPException) as exc_info:
852
  await http_client.request_with_retry(
853
  "POST",
tests/unit/test_main_cli.py CHANGED
@@ -395,7 +395,7 @@ class TestCliVersion:
395
  """
396
  print("Setup: Importing parse_cli_args and APP_VERSION...")
397
  from main import parse_cli_args
398
- from kiro_gateway.config import APP_VERSION
399
 
400
  print("Action: Calling parse_cli_args with --version...")
401
  with patch.object(sys, 'argv', ['main.py', '--version']):
 
395
  """
396
  print("Setup: Importing parse_cli_args and APP_VERSION...")
397
  from main import parse_cli_args
398
+ from kiro.config import APP_VERSION
399
 
400
  print("Action: Calling parse_cli_args with --version...")
401
  with patch.object(sys, 'argv', ['main.py', '--version']):
tests/unit/test_parsers.py CHANGED
@@ -7,7 +7,7 @@ Unit-тесты для AwsEventStreamParser и вспомогательных ф
7
 
8
  import pytest
9
 
10
- from kiro_gateway.parsers import (
11
  AwsEventStreamParser,
12
  find_matching_brace,
13
  parse_bracket_tool_calls,
 
7
 
8
  import pytest
9
 
10
+ from kiro.parsers import (
11
  AwsEventStreamParser,
12
  find_matching_brace,
13
  parse_bracket_tool_calls,
tests/unit/test_routes.py CHANGED
@@ -12,8 +12,8 @@ from datetime import datetime, timezone
12
  from fastapi import HTTPException
13
  from fastapi.testclient import TestClient
14
 
15
- from kiro_gateway.routes import verify_api_key, router
16
- from kiro_gateway.config import PROXY_API_KEY, APP_VERSION, AVAILABLE_MODELS
17
 
18
 
19
  class TestVerifyApiKey:
 
12
  from fastapi import HTTPException
13
  from fastapi.testclient import TestClient
14
 
15
+ from kiro.routes import verify_api_key, router
16
+ from kiro.config import PROXY_API_KEY, APP_VERSION, AVAILABLE_MODELS
17
 
18
 
19
  class TestVerifyApiKey:
tests/unit/test_streaming.py CHANGED
@@ -10,7 +10,7 @@ import pytest
10
  import json
11
  from unittest.mock import AsyncMock, MagicMock, patch
12
 
13
- from kiro_gateway.streaming import (
14
  stream_kiro_to_openai,
15
  collect_stream_response
16
  )
@@ -77,8 +77,8 @@ class TestStreamingToolCallsIndex:
77
  print("Action: Collecting streaming chunks...")
78
  chunks = []
79
 
80
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
81
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
82
  async for chunk in stream_kiro_to_openai(
83
  mock_http_client, mock_response, "test-model",
84
  mock_model_cache, mock_auth_manager
@@ -137,8 +137,8 @@ class TestStreamingToolCallsIndex:
137
  print("Action: Collecting streaming chunks...")
138
  chunks = []
139
 
140
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
141
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
142
  async for chunk in stream_kiro_to_openai(
143
  mock_http_client, mock_response, "test-model",
144
  mock_model_cache, mock_auth_manager
@@ -197,8 +197,8 @@ class TestStreamingToolCallsNoneProtection:
197
  print("Action: Collecting streaming chunks...")
198
  chunks = []
199
 
200
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
201
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
202
  async for chunk in stream_kiro_to_openai(
203
  mock_http_client, mock_response, "test-model",
204
  mock_model_cache, mock_auth_manager
@@ -256,8 +256,8 @@ class TestStreamingToolCallsNoneProtection:
256
  print("Action: Collecting streaming chunks...")
257
  chunks = []
258
 
259
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
260
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
261
  async for chunk in stream_kiro_to_openai(
262
  mock_http_client, mock_response, "test-model",
263
  mock_model_cache, mock_auth_manager
@@ -312,8 +312,8 @@ class TestStreamingToolCallsNoneProtection:
312
  print("Action: Collecting streaming chunks...")
313
  chunks = []
314
 
315
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
316
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
317
  async for chunk in stream_kiro_to_openai(
318
  mock_http_client, mock_response, "test-model",
319
  mock_model_cache, mock_auth_manager
@@ -357,8 +357,8 @@ class TestCollectStreamResponseToolCalls:
357
 
358
  print("Action: Collecting full response...")
359
 
360
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
361
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
362
  result = await collect_stream_response(
363
  mock_http_client, mock_response, "test-model",
364
  mock_model_cache, mock_auth_manager
@@ -403,8 +403,8 @@ class TestCollectStreamResponseToolCalls:
403
 
404
  print("Action: Collecting full response...")
405
 
406
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
407
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
408
  result = await collect_stream_response(
409
  mock_http_client, mock_response, "test-model",
410
  mock_model_cache, mock_auth_manager
@@ -453,8 +453,8 @@ class TestCollectStreamResponseToolCalls:
453
 
454
  print("Action: Collecting full response...")
455
 
456
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
457
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
458
  result = await collect_stream_response(
459
  mock_http_client, mock_response, "test-model",
460
  mock_model_cache, mock_auth_manager
@@ -497,8 +497,8 @@ class TestStreamingErrorHandling:
497
  chunks_received = []
498
  generator_exit_caught = False
499
 
500
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
501
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
502
  try:
503
  async for chunk in stream_kiro_to_openai(
504
  mock_http_client, mock_response, "test-model",
@@ -546,9 +546,9 @@ class TestStreamingErrorHandling:
546
 
547
  print("Action: Running streaming with EmptyMessageError...")
548
 
549
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
550
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
551
- with patch('kiro_gateway.streaming.logger') as mock_logger:
552
  exception_raised = False
553
  try:
554
  async for chunk in stream_kiro_to_openai(
@@ -599,8 +599,8 @@ class TestStreamingErrorHandling:
599
 
600
  print("Action: Running streaming with RuntimeError...")
601
 
602
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
603
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
604
  with pytest.raises(RuntimeError) as exc_info:
605
  async for chunk in stream_kiro_to_openai(
606
  mock_http_client, mock_response, "test-model",
@@ -636,8 +636,8 @@ class TestStreamingErrorHandling:
636
 
637
  print("Action: Running streaming with ValueError...")
638
 
639
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
640
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
641
  try:
642
  async for chunk in stream_kiro_to_openai(
643
  mock_http_client, mock_response, "test-model",
@@ -675,8 +675,8 @@ class TestStreamingErrorHandling:
675
  print("Action: Running successful streaming...")
676
  chunks = []
677
 
678
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
679
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
680
  async for chunk in stream_kiro_to_openai(
681
  mock_http_client, mock_response, "test-model",
682
  mock_model_cache, mock_auth_manager
@@ -712,8 +712,8 @@ class TestStreamingErrorHandling:
712
 
713
  print("Action: Running streaming with error and error in aclose()...")
714
 
715
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
716
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
717
  with pytest.raises(RuntimeError) as exc_info:
718
  async for chunk in stream_kiro_to_openai(
719
  mock_http_client, mock_response, "test-model",
@@ -737,7 +737,7 @@ class TestFirstTokenTimeoutError:
737
  Goal: Ensure first token timeout is not handled as regular error.
738
  """
739
  import asyncio
740
- from kiro_gateway.streaming import FirstTokenTimeoutError, stream_kiro_to_openai_internal
741
 
742
  print("Setup: Mock response with timeout...")
743
 
@@ -757,7 +757,7 @@ class TestFirstTokenTimeoutError:
757
  async def mock_wait_for_timeout(*args, **kwargs):
758
  raise asyncio.TimeoutError()
759
 
760
- with patch('kiro_gateway.streaming.asyncio.wait_for', side_effect=mock_wait_for_timeout):
761
  with pytest.raises(FirstTokenTimeoutError) as exc_info:
762
  async for chunk in stream_kiro_to_openai_internal(
763
  mock_http_client, mock_response, "test-model",
@@ -780,7 +780,7 @@ class TestFirstTokenTimeoutError:
780
  Goal: Ensure consistent logging format for first token timeout.
781
  """
782
  import asyncio
783
- from kiro_gateway.streaming import FirstTokenTimeoutError, stream_kiro_to_openai_internal
784
 
785
  print("Setup: Mock response with timeout...")
786
 
@@ -798,8 +798,8 @@ class TestFirstTokenTimeoutError:
798
 
799
  print("Action: Running streaming with timeout and checking logs...")
800
 
801
- with patch('kiro_gateway.streaming.asyncio.wait_for', side_effect=mock_wait_for_timeout):
802
- with patch('kiro_gateway.streaming.logger') as mock_logger:
803
  try:
804
  async for chunk in stream_kiro_to_openai_internal(
805
  mock_http_client, mock_response, "test-model",
@@ -825,7 +825,7 @@ class TestFirstTokenTimeoutError:
825
  Goal: Ensure timeout value is visible in logs for debugging.
826
  """
827
  import asyncio
828
- from kiro_gateway.streaming import FirstTokenTimeoutError, stream_kiro_to_openai_internal
829
 
830
  print("Setup: Mock response with timeout...")
831
 
@@ -845,8 +845,8 @@ class TestFirstTokenTimeoutError:
845
 
846
  print(f"Action: Running streaming with custom timeout={custom_timeout}...")
847
 
848
- with patch('kiro_gateway.streaming.asyncio.wait_for', side_effect=mock_wait_for_timeout):
849
- with patch('kiro_gateway.streaming.logger') as mock_logger:
850
  try:
851
  async for chunk in stream_kiro_to_openai_internal(
852
  mock_http_client, mock_response, "test-model",
@@ -871,7 +871,7 @@ class TestFirstTokenTimeoutError:
871
  What it does: Verifies that successful first token receipt is logged.
872
  Goal: Ensure debug log shows when first token is received.
873
  """
874
- from kiro_gateway.streaming import stream_kiro_to_openai_internal
875
 
876
  print("Setup: Mock response with successful first token...")
877
 
@@ -890,9 +890,9 @@ class TestFirstTokenTimeoutError:
890
 
891
  print("Action: Running streaming and checking debug logs...")
892
 
893
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
894
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
895
- with patch('kiro_gateway.streaming.logger') as mock_logger:
896
  chunks = []
897
  async for chunk in stream_kiro_to_openai_internal(
898
  mock_http_client, mock_response, "test-model",
@@ -921,7 +921,7 @@ class TestStreamWithFirstTokenRetry:
921
  Goal: Ensure retry logic works for first token timeout.
922
  """
923
  import asyncio
924
- from kiro_gateway.streaming import stream_with_first_token_retry, FirstTokenTimeoutError
925
 
926
  print("Setup: Mock make_request that succeeds on second attempt...")
927
 
@@ -958,9 +958,9 @@ class TestStreamWithFirstTokenRetry:
958
 
959
  print("Action: Running stream_with_first_token_retry...")
960
 
961
- with patch('kiro_gateway.streaming.AwsEventStreamParser', return_value=mock_parser):
962
- with patch('kiro_gateway.streaming.parse_bracket_tool_calls', return_value=[]):
963
- with patch('kiro_gateway.streaming.asyncio.wait_for', side_effect=mock_wait_for_with_retry):
964
  chunks = []
965
  async for chunk in stream_with_first_token_retry(
966
  mock_make_request,
@@ -988,7 +988,7 @@ class TestStreamWithFirstTokenRetry:
988
  """
989
  import asyncio
990
  from fastapi import HTTPException
991
- from kiro_gateway.streaming import stream_with_first_token_retry
992
 
993
  print("Setup: Mock make_request that always times out...")
994
 
@@ -1016,7 +1016,7 @@ class TestStreamWithFirstTokenRetry:
1016
 
1017
  print(f"Action: Running stream_with_first_token_retry with max_retries={max_retries}...")
1018
 
1019
- with patch('kiro_gateway.streaming.asyncio.wait_for', side_effect=mock_wait_for_always_timeout):
1020
  with pytest.raises(HTTPException) as exc_info:
1021
  async for chunk in stream_with_first_token_retry(
1022
  mock_make_request,
@@ -1047,7 +1047,7 @@ class TestStreamWithFirstTokenRetry:
1047
  """
1048
  import asyncio
1049
  from fastapi import HTTPException
1050
- from kiro_gateway.streaming import stream_with_first_token_retry
1051
 
1052
  print("Setup: Mock make_request that always times out...")
1053
 
@@ -1068,8 +1068,8 @@ class TestStreamWithFirstTokenRetry:
1068
 
1069
  print("Action: Running stream_with_first_token_retry and checking logs...")
1070
 
1071
- with patch('kiro_gateway.streaming.asyncio.wait_for', side_effect=mock_wait_for_always_timeout):
1072
- with patch('kiro_gateway.streaming.logger') as mock_logger:
1073
  try:
1074
  async for chunk in stream_with_first_token_retry(
1075
  mock_make_request,
 
10
  import json
11
  from unittest.mock import AsyncMock, MagicMock, patch
12
 
13
+ from kiro.streaming import (
14
  stream_kiro_to_openai,
15
  collect_stream_response
16
  )
 
77
  print("Action: Collecting streaming chunks...")
78
  chunks = []
79
 
80
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
81
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
82
  async for chunk in stream_kiro_to_openai(
83
  mock_http_client, mock_response, "test-model",
84
  mock_model_cache, mock_auth_manager
 
137
  print("Action: Collecting streaming chunks...")
138
  chunks = []
139
 
140
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
141
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
142
  async for chunk in stream_kiro_to_openai(
143
  mock_http_client, mock_response, "test-model",
144
  mock_model_cache, mock_auth_manager
 
197
  print("Action: Collecting streaming chunks...")
198
  chunks = []
199
 
200
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
201
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
202
  async for chunk in stream_kiro_to_openai(
203
  mock_http_client, mock_response, "test-model",
204
  mock_model_cache, mock_auth_manager
 
256
  print("Action: Collecting streaming chunks...")
257
  chunks = []
258
 
259
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
260
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
261
  async for chunk in stream_kiro_to_openai(
262
  mock_http_client, mock_response, "test-model",
263
  mock_model_cache, mock_auth_manager
 
312
  print("Action: Collecting streaming chunks...")
313
  chunks = []
314
 
315
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
316
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
317
  async for chunk in stream_kiro_to_openai(
318
  mock_http_client, mock_response, "test-model",
319
  mock_model_cache, mock_auth_manager
 
357
 
358
  print("Action: Collecting full response...")
359
 
360
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
361
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
362
  result = await collect_stream_response(
363
  mock_http_client, mock_response, "test-model",
364
  mock_model_cache, mock_auth_manager
 
403
 
404
  print("Action: Collecting full response...")
405
 
406
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
407
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
408
  result = await collect_stream_response(
409
  mock_http_client, mock_response, "test-model",
410
  mock_model_cache, mock_auth_manager
 
453
 
454
  print("Action: Collecting full response...")
455
 
456
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
457
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
458
  result = await collect_stream_response(
459
  mock_http_client, mock_response, "test-model",
460
  mock_model_cache, mock_auth_manager
 
497
  chunks_received = []
498
  generator_exit_caught = False
499
 
500
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
501
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
502
  try:
503
  async for chunk in stream_kiro_to_openai(
504
  mock_http_client, mock_response, "test-model",
 
546
 
547
  print("Action: Running streaming with EmptyMessageError...")
548
 
549
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
550
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
551
+ with patch('kiro.streaming.logger') as mock_logger:
552
  exception_raised = False
553
  try:
554
  async for chunk in stream_kiro_to_openai(
 
599
 
600
  print("Action: Running streaming with RuntimeError...")
601
 
602
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
603
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
604
  with pytest.raises(RuntimeError) as exc_info:
605
  async for chunk in stream_kiro_to_openai(
606
  mock_http_client, mock_response, "test-model",
 
636
 
637
  print("Action: Running streaming with ValueError...")
638
 
639
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
640
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
641
  try:
642
  async for chunk in stream_kiro_to_openai(
643
  mock_http_client, mock_response, "test-model",
 
675
  print("Action: Running successful streaming...")
676
  chunks = []
677
 
678
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
679
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
680
  async for chunk in stream_kiro_to_openai(
681
  mock_http_client, mock_response, "test-model",
682
  mock_model_cache, mock_auth_manager
 
712
 
713
  print("Action: Running streaming with error and error in aclose()...")
714
 
715
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
716
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
717
  with pytest.raises(RuntimeError) as exc_info:
718
  async for chunk in stream_kiro_to_openai(
719
  mock_http_client, mock_response, "test-model",
 
737
  Goal: Ensure first token timeout is not handled as regular error.
738
  """
739
  import asyncio
740
+ from kiro.streaming import FirstTokenTimeoutError, stream_kiro_to_openai_internal
741
 
742
  print("Setup: Mock response with timeout...")
743
 
 
757
  async def mock_wait_for_timeout(*args, **kwargs):
758
  raise asyncio.TimeoutError()
759
 
760
+ with patch('kiro.streaming.asyncio.wait_for', side_effect=mock_wait_for_timeout):
761
  with pytest.raises(FirstTokenTimeoutError) as exc_info:
762
  async for chunk in stream_kiro_to_openai_internal(
763
  mock_http_client, mock_response, "test-model",
 
780
  Goal: Ensure consistent logging format for first token timeout.
781
  """
782
  import asyncio
783
+ from kiro.streaming import FirstTokenTimeoutError, stream_kiro_to_openai_internal
784
 
785
  print("Setup: Mock response with timeout...")
786
 
 
798
 
799
  print("Action: Running streaming with timeout and checking logs...")
800
 
801
+ with patch('kiro.streaming.asyncio.wait_for', side_effect=mock_wait_for_timeout):
802
+ with patch('kiro.streaming.logger') as mock_logger:
803
  try:
804
  async for chunk in stream_kiro_to_openai_internal(
805
  mock_http_client, mock_response, "test-model",
 
825
  Goal: Ensure timeout value is visible in logs for debugging.
826
  """
827
  import asyncio
828
+ from kiro.streaming import FirstTokenTimeoutError, stream_kiro_to_openai_internal
829
 
830
  print("Setup: Mock response with timeout...")
831
 
 
845
 
846
  print(f"Action: Running streaming with custom timeout={custom_timeout}...")
847
 
848
+ with patch('kiro.streaming.asyncio.wait_for', side_effect=mock_wait_for_timeout):
849
+ with patch('kiro.streaming.logger') as mock_logger:
850
  try:
851
  async for chunk in stream_kiro_to_openai_internal(
852
  mock_http_client, mock_response, "test-model",
 
871
  What it does: Verifies that successful first token receipt is logged.
872
  Goal: Ensure debug log shows when first token is received.
873
  """
874
+ from kiro.streaming import stream_kiro_to_openai_internal
875
 
876
  print("Setup: Mock response with successful first token...")
877
 
 
890
 
891
  print("Action: Running streaming and checking debug logs...")
892
 
893
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
894
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
895
+ with patch('kiro.streaming.logger') as mock_logger:
896
  chunks = []
897
  async for chunk in stream_kiro_to_openai_internal(
898
  mock_http_client, mock_response, "test-model",
 
921
  Goal: Ensure retry logic works for first token timeout.
922
  """
923
  import asyncio
924
+ from kiro.streaming import stream_with_first_token_retry, FirstTokenTimeoutError
925
 
926
  print("Setup: Mock make_request that succeeds on second attempt...")
927
 
 
958
 
959
  print("Action: Running stream_with_first_token_retry...")
960
 
961
+ with patch('kiro.streaming.AwsEventStreamParser', return_value=mock_parser):
962
+ with patch('kiro.streaming.parse_bracket_tool_calls', return_value=[]):
963
+ with patch('kiro.streaming.asyncio.wait_for', side_effect=mock_wait_for_with_retry):
964
  chunks = []
965
  async for chunk in stream_with_first_token_retry(
966
  mock_make_request,
 
988
  """
989
  import asyncio
990
  from fastapi import HTTPException
991
+ from kiro.streaming import stream_with_first_token_retry
992
 
993
  print("Setup: Mock make_request that always times out...")
994
 
 
1016
 
1017
  print(f"Action: Running stream_with_first_token_retry with max_retries={max_retries}...")
1018
 
1019
+ with patch('kiro.streaming.asyncio.wait_for', side_effect=mock_wait_for_always_timeout):
1020
  with pytest.raises(HTTPException) as exc_info:
1021
  async for chunk in stream_with_first_token_retry(
1022
  mock_make_request,
 
1047
  """
1048
  import asyncio
1049
  from fastapi import HTTPException
1050
+ from kiro.streaming import stream_with_first_token_retry
1051
 
1052
  print("Setup: Mock make_request that always times out...")
1053
 
 
1068
 
1069
  print("Action: Running stream_with_first_token_retry and checking logs...")
1070
 
1071
+ with patch('kiro.streaming.asyncio.wait_for', side_effect=mock_wait_for_always_timeout):
1072
+ with patch('kiro.streaming.logger') as mock_logger:
1073
  try:
1074
  async for chunk in stream_with_first_token_retry(
1075
  mock_make_request,
tests/unit/test_thinking_parser.py CHANGED
@@ -14,7 +14,7 @@ Tests cover:
14
  import pytest
15
  from unittest.mock import patch
16
 
17
- from kiro_gateway.thinking_parser import (
18
  ThinkingParser,
19
  ThinkingParseResult,
20
  ParserState,
@@ -900,7 +900,7 @@ class TestThinkingParserConfigIntegration:
900
  Purpose: Ensure config integration works.
901
  """
902
  print("Testing config handling mode...")
903
- with patch('kiro_gateway.thinking_parser.FAKE_REASONING_HANDLING', 'remove'):
904
  parser = ThinkingParser()
905
 
906
  print(f"Handling mode: {parser.handling_mode}")
@@ -913,7 +913,7 @@ class TestThinkingParserConfigIntegration:
913
  """
914
  print("Testing config open tags...")
915
  custom_tags = ["<custom>"]
916
- with patch('kiro_gateway.thinking_parser.FAKE_REASONING_OPEN_TAGS', custom_tags):
917
  parser = ThinkingParser()
918
 
919
  print(f"Open tags: {parser.open_tags}")
@@ -929,7 +929,7 @@ class TestThinkingParserConfigIntegration:
929
  TestThinkingParserInitialization.test_custom_initial_buffer_size.
930
  """
931
  print("Testing default initial buffer size from config...")
932
- from kiro_gateway.config import FAKE_REASONING_INITIAL_BUFFER_SIZE
933
 
934
  parser = ThinkingParser()
935
 
@@ -947,10 +947,10 @@ class TestInjectThinkingTags:
947
  Purpose: Ensure tags are added to content.
948
  """
949
  print("Testing tag injection when enabled...")
950
- from kiro_gateway.converters import inject_thinking_tags
951
 
952
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
953
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
954
  result = inject_thinking_tags("Hello")
955
 
956
  print(f"Result: '{result}'")
@@ -964,9 +964,9 @@ class TestInjectThinkingTags:
964
  Purpose: Ensure tags are not added when disabled.
965
  """
966
  print("Testing no tag injection when disabled...")
967
- from kiro_gateway.converters import inject_thinking_tags
968
 
969
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', False):
970
  result = inject_thinking_tags("Hello")
971
 
972
  print(f"Result: '{result}'")
@@ -979,12 +979,12 @@ class TestInjectThinkingTags:
979
  Purpose: Ensure content is not modified.
980
  """
981
  print("Testing content preservation...")
982
- from kiro_gateway.converters import inject_thinking_tags
983
 
984
  original = "This is my original content with special chars: <>&"
985
 
986
- with patch('kiro_gateway.converters.FAKE_REASONING_ENABLED', True):
987
- with patch('kiro_gateway.converters.FAKE_REASONING_MAX_TOKENS', 4000):
988
  result = inject_thinking_tags(original)
989
 
990
  print(f"Result ends with original: {result.endswith(original)}")
 
14
  import pytest
15
  from unittest.mock import patch
16
 
17
+ from kiro.thinking_parser import (
18
  ThinkingParser,
19
  ThinkingParseResult,
20
  ParserState,
 
900
  Purpose: Ensure config integration works.
901
  """
902
  print("Testing config handling mode...")
903
+ with patch('kiro.thinking_parser.FAKE_REASONING_HANDLING', 'remove'):
904
  parser = ThinkingParser()
905
 
906
  print(f"Handling mode: {parser.handling_mode}")
 
913
  """
914
  print("Testing config open tags...")
915
  custom_tags = ["<custom>"]
916
+ with patch('kiro.thinking_parser.FAKE_REASONING_OPEN_TAGS', custom_tags):
917
  parser = ThinkingParser()
918
 
919
  print(f"Open tags: {parser.open_tags}")
 
929
  TestThinkingParserInitialization.test_custom_initial_buffer_size.
930
  """
931
  print("Testing default initial buffer size from config...")
932
+ from kiro.config import FAKE_REASONING_INITIAL_BUFFER_SIZE
933
 
934
  parser = ThinkingParser()
935
 
 
947
  Purpose: Ensure tags are added to content.
948
  """
949
  print("Testing tag injection when enabled...")
950
+ from kiro.converters import inject_thinking_tags
951
 
952
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
953
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
954
  result = inject_thinking_tags("Hello")
955
 
956
  print(f"Result: '{result}'")
 
964
  Purpose: Ensure tags are not added when disabled.
965
  """
966
  print("Testing no tag injection when disabled...")
967
+ from kiro.converters import inject_thinking_tags
968
 
969
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', False):
970
  result = inject_thinking_tags("Hello")
971
 
972
  print(f"Result: '{result}'")
 
979
  Purpose: Ensure content is not modified.
980
  """
981
  print("Testing content preservation...")
982
+ from kiro.converters import inject_thinking_tags
983
 
984
  original = "This is my original content with special chars: <>&"
985
 
986
+ with patch('kiro.converters.FAKE_REASONING_ENABLED', True):
987
+ with patch('kiro.converters.FAKE_REASONING_MAX_TOKENS', 4000):
988
  result = inject_thinking_tags(original)
989
 
990
  print(f"Result ends with original: {result.endswith(original)}")
tests/unit/test_tokenizer.py CHANGED
@@ -1,7 +1,7 @@
1
  # -*- coding: utf-8 -*-
2
 
3
  """
4
- Unit-тесты для модуля токенизатора (kiro_gateway/tokenizer.py).
5
 
6
  Проверяет:
7
  - Подсчёт токенов в тексте (count_tokens)
@@ -15,7 +15,7 @@ Unit-тесты для модуля токенизатора (kiro_gateway/token
15
  import pytest
16
  from unittest.mock import patch, MagicMock
17
 
18
- from kiro_gateway.tokenizer import (
19
  count_tokens,
20
  count_message_tokens,
21
  count_tools_tokens,
@@ -163,7 +163,7 @@ class TestCountTokensFallback:
163
  print("Тест: Fallback без tiktoken...")
164
 
165
  # Мокируем _get_encoding чтобы вернуть None
166
- with patch('kiro_gateway.tokenizer._get_encoding', return_value=None):
167
  result = count_tokens("Hello world test")
168
  print(f"Результат: {result}")
169
 
@@ -180,7 +180,7 @@ class TestCountTokensFallback:
180
  """
181
  print("Тест: Fallback без коррекции...")
182
 
183
- with patch('kiro_gateway.tokenizer._get_encoding', return_value=None):
184
  result = count_tokens("Test", apply_claude_correction=False)
185
  print(f"Результат: {result}")
186
 
@@ -724,7 +724,7 @@ class TestGetEncoding:
724
  print("Тест: tiktoken доступен...")
725
 
726
  # Сбрасываем глобальную переменную для чистого теста
727
- import kiro_gateway.tokenizer as tokenizer_module
728
  original_encoding = tokenizer_module._encoding
729
  tokenizer_module._encoding = None
730
 
@@ -762,7 +762,7 @@ class TestGetEncoding:
762
  """
763
  print("Тест: ImportError...")
764
 
765
- import kiro_gateway.tokenizer as tokenizer_module
766
  original_encoding = tokenizer_module._encoding
767
  tokenizer_module._encoding = None
768
 
 
1
  # -*- coding: utf-8 -*-
2
 
3
  """
4
+ Unit-тесты для модуля токенизатора (kiro/tokenizer.py).
5
 
6
  Проверяет:
7
  - Подсчёт токенов в тексте (count_tokens)
 
15
  import pytest
16
  from unittest.mock import patch, MagicMock
17
 
18
+ from kiro.tokenizer import (
19
  count_tokens,
20
  count_message_tokens,
21
  count_tools_tokens,
 
163
  print("Тест: Fallback без tiktoken...")
164
 
165
  # Мокируем _get_encoding чтобы вернуть None
166
+ with patch('kiro.tokenizer._get_encoding', return_value=None):
167
  result = count_tokens("Hello world test")
168
  print(f"Результат: {result}")
169
 
 
180
  """
181
  print("Тест: Fallback без коррекции...")
182
 
183
+ with patch('kiro.tokenizer._get_encoding', return_value=None):
184
  result = count_tokens("Test", apply_claude_correction=False)
185
  print(f"Результат: {result}")
186
 
 
724
  print("Тест: tiktoken доступен...")
725
 
726
  # Сбрасываем глобальную переменную для чистого теста
727
+ import kiro.tokenizer as tokenizer_module
728
  original_encoding = tokenizer_module._encoding
729
  tokenizer_module._encoding = None
730
 
 
762
  """
763
  print("Тест: ImportError...")
764
 
765
+ import kiro.tokenizer as tokenizer_module
766
  original_encoding = tokenizer_module._encoding
767
  tokenizer_module._encoding = None
768