Skip to content

Commit 90d0509

Browse files
committed
fix(endpoint): improve runtime.kiro.dev migration
1 parent 07d24fc commit 90d0509

6 files changed

Lines changed: 98 additions & 54 deletions

File tree

CONTRIBUTORS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Thank you to all the contributors who have helped improve this project!
66

77
These contributors have made significant, sustained contributions to the project:
88

9-
- [@bhaskoro-muthohar](https://github.com/bhaskoro-muthohar) — MCP tool results analysis (#46, #50), message structure validation (#60), payload size guard (#73), tool_reference support (#89, #90), and ongoing project support
9+
- [@bhaskoro-muthohar](https://github.com/bhaskoro-muthohar) — MCP tool results analysis (#46, #50), message structure validation (#60), payload size guard (#73), tool_reference support (#89, #90), runtime.kiro.dev endpoint migration (#155), and ongoing project support
1010

1111
## Contributors
1212

kiro/account_manager.py

Lines changed: 81 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,35 @@
6464
from kiro.http_client import KiroHttpClient
6565

6666

67+
def _is_runtime_endpoint(auth_manager: KiroAuthManager) -> bool:
68+
"""
69+
Check if auth manager uses runtime endpoint that doesn't provide /ListAvailableModels.
70+
71+
Runtime endpoint pattern: https://runtime.{region}.kiro.dev
72+
Old endpoint pattern: https://q.{region}.amazonaws.com
73+
74+
Runtime endpoint does not provide /ListAvailableModels API (AWS limitation).
75+
76+
Args:
77+
auth_manager: KiroAuthManager instance
78+
79+
Returns:
80+
True if using runtime endpoint, False otherwise
81+
82+
Examples:
83+
>>> auth_manager.api_host = "https://runtime.us-east-1.kiro.dev"
84+
>>> _is_runtime_endpoint(auth_manager)
85+
True
86+
>>> auth_manager.api_host = "https://runtime.eu-central-1.kiro.dev"
87+
>>> _is_runtime_endpoint(auth_manager)
88+
True
89+
>>> auth_manager.api_host = "https://q.us-east-1.amazonaws.com"
90+
>>> _is_runtime_endpoint(auth_manager)
91+
False
92+
"""
93+
return "://runtime." in auth_manager.api_host
94+
95+
6796
def _format_duration(seconds: float) -> str:
6897
"""
6998
Format duration in human-readable format.
@@ -468,40 +497,48 @@ async def _initialize_account(self, account_id: str) -> bool:
468497
# Get token to verify credentials
469498
token = await auth_manager.get_access_token()
470499

471-
# Fetch models list with retry + fallback
472-
params = {"origin": "AI_EDITOR"}
473-
if auth_manager.auth_type == AuthType.KIRO_DESKTOP and auth_manager.profile_arn:
474-
params["profileArn"] = auth_manager.profile_arn
475-
476-
list_models_url = f"{auth_manager.q_host}/ListAvailableModels"
477-
478-
# Use KiroHttpClient for retry logic (3 attempts with exponential backoff)
479-
http_client = KiroHttpClient(auth_manager, shared_client=None)
480-
481-
try:
482-
response = await http_client.request_with_retry(
483-
method="GET",
484-
url=list_models_url,
485-
json_data=None,
486-
params=params,
487-
stream=False
488-
)
489-
490-
if response.status_code == 200:
491-
data = response.json()
492-
models_list = data.get("models", [])
493-
else:
494-
# Shouldn't happen (retry handles non-200), but keep for safety
495-
raise Exception(f"HTTP {response.status_code}")
496-
497-
except Exception as e:
498-
# All retries exhausted - use fallback
499-
logger.error(f"Failed to fetch models for {account_id} after retries: {e}")
500-
logger.warning("Using pre-configured fallback models. Models will be refreshed on next TTL cycle when network recovers.")
500+
# Determine if we should fetch models or use static list
501+
if _is_runtime_endpoint(auth_manager):
502+
# New runtime endpoint does not provide /ListAvailableModels (AWS limitation)
503+
# Use static list without attempting request
504+
logger.debug(f"Account {account_id}: Using static model list for runtime.kiro.dev endpoint")
501505
models_list = FALLBACK_MODELS
502-
503-
finally:
504-
await http_client.close()
506+
else:
507+
# Old endpoint - attempt to fetch dynamic model list
508+
# Fetch models list with retry + fallback
509+
params = {"origin": "AI_EDITOR"}
510+
if auth_manager.auth_type == AuthType.KIRO_DESKTOP and auth_manager.profile_arn:
511+
params["profileArn"] = auth_manager.profile_arn
512+
513+
list_models_url = f"{auth_manager.q_host}/ListAvailableModels"
514+
515+
# Use KiroHttpClient for retry logic (3 attempts with exponential backoff)
516+
http_client = KiroHttpClient(auth_manager, shared_client=None)
517+
518+
try:
519+
response = await http_client.request_with_retry(
520+
method="GET",
521+
url=list_models_url,
522+
json_data=None,
523+
params=params,
524+
stream=False
525+
)
526+
527+
if response.status_code == 200:
528+
data = response.json()
529+
models_list = data.get("models", [])
530+
else:
531+
# Shouldn't happen (retry handles non-200), but keep for safety
532+
raise Exception(f"HTTP {response.status_code}")
533+
534+
except Exception as e:
535+
# All retries exhausted - use fallback
536+
logger.error(f"Failed to fetch models for {account_id} after retries: {e}")
537+
logger.warning("Using pre-configured fallback models. Models will be refreshed on next TTL cycle when network recovers.")
538+
models_list = FALLBACK_MODELS
539+
540+
finally:
541+
await http_client.close()
505542

506543
# Create model cache and update
507544
model_cache = ModelInfoCache()
@@ -552,6 +589,17 @@ async def _refresh_account_models(self, account_id: str) -> None:
552589
if not account or not account.auth_manager:
553590
return
554591

592+
# Check if using runtime endpoint (no dynamic model list available)
593+
if _is_runtime_endpoint(account.auth_manager):
594+
# Runtime endpoint does not provide /ListAvailableModels
595+
# Use static list and update cache timestamp
596+
logger.debug(f"Account {account_id}: Skipping model refresh for runtime.kiro.dev endpoint (using static list)")
597+
await account.model_cache.update(FALLBACK_MODELS)
598+
account.models_cached_at = time.time()
599+
self._dirty = True
600+
return
601+
602+
# Old endpoint - attempt to fetch dynamic model list
555603
# Use KiroHttpClient for retry logic
556604
http_client = KiroHttpClient(account.auth_manager, shared_client=None)
557605

kiro/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,12 @@ def _get_raw_env_value(var_name: str, env_file: str = ".env") -> Optional[str]:
276276
FALLBACK_MODELS: List[Dict[str, str]] = [
277277
{"modelId": "auto"},
278278
{"modelId": "claude-sonnet-4"},
279-
{"modelId": "claude-haiku-4.5"},
280279
{"modelId": "claude-sonnet-4.5"},
280+
{"modelId": "claude-sonnet-4.6"},
281+
{"modelId": "claude-haiku-4.5"},
281282
{"modelId": "claude-opus-4.5"},
283+
{"modelId": "claude-opus-4.6"},
284+
{"modelId": "claude-opus-4.7"},
282285
]
283286

284287
# ==================================================================================================

kiro/model_resolver.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,10 @@
4242

4343

4444
# Valid model IDs accepted by runtime.{region}.kiro.dev
45-
VALID_RUNTIME_MODEL_IDS: set = {
46-
"auto",
47-
"claude-sonnet-4",
48-
"claude-sonnet-4.5",
49-
"claude-sonnet-4.6",
50-
"claude-opus-4.5",
51-
"claude-opus-4.6",
52-
"claude-opus-4.7",
53-
"claude-haiku-4.5",
54-
}
45+
# Generated from FALLBACK_MODELS to maintain single source of truth
46+
from kiro.config import FALLBACK_MODELS
47+
48+
VALID_RUNTIME_MODEL_IDS: set = {model["modelId"] for model in FALLBACK_MODELS}
5549

5650

5751
def to_runtime_model_id(normalized: str) -> str:

kiro/routes_anthropic.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from fastapi.security import APIKeyHeader
3535
from loguru import logger
3636

37-
from kiro.config import PROXY_API_KEY
37+
from kiro.config import PROXY_API_KEY, PROFILE_ARN
3838
from kiro.models_anthropic import (
3939
AnthropicMessagesRequest,
4040
AnthropicCountTokensRequest,
@@ -376,9 +376,8 @@ async def messages(
376376
conversation_id = generate_conversation_id()
377377

378378
# Build payload for Kiro
379-
profile_arn_for_payload = ""
380-
if auth_manager.auth_type == AuthType.KIRO_DESKTOP and auth_manager.profile_arn:
381-
profile_arn_for_payload = auth_manager.profile_arn
379+
# profileArn is required by runtime.kiro.dev for all auth types
380+
profile_arn_for_payload = auth_manager.profile_arn or PROFILE_ARN or ""
382381

383382
try:
384383
kiro_payload = anthropic_to_kiro(
@@ -686,7 +685,7 @@ async def make_retry_request():
686685

687686
# Build payload for Kiro
688687
# profileArn is required by runtime.kiro.dev for all auth types
689-
profile_arn_for_payload = auth_manager.profile_arn or ""
688+
profile_arn_for_payload = auth_manager.profile_arn or PROFILE_ARN or ""
690689

691690
try:
692691
kiro_payload = anthropic_to_kiro(

kiro/routes_openai.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from kiro.config import (
3838
PROXY_API_KEY,
3939
APP_VERSION,
40+
PROFILE_ARN,
4041
)
4142
from kiro.models_openai import (
4243
OpenAIModel,
@@ -322,9 +323,8 @@ async def chat_completions(request: Request, request_data: ChatCompletionRequest
322323
conversation_id = generate_conversation_id()
323324

324325
# Build payload for Kiro
325-
profile_arn_for_payload = ""
326-
if auth_manager.auth_type == AuthType.KIRO_DESKTOP and auth_manager.profile_arn:
327-
profile_arn_for_payload = auth_manager.profile_arn
326+
# profileArn is required by runtime.kiro.dev for all auth types
327+
profile_arn_for_payload = auth_manager.profile_arn or PROFILE_ARN or ""
328328

329329
try:
330330
kiro_payload = build_kiro_payload(
@@ -572,7 +572,7 @@ async def make_retry_request():
572572

573573
# Build payload for Kiro
574574
# profileArn is required by runtime.kiro.dev for all auth types
575-
profile_arn_for_payload = auth_manager.profile_arn or ""
575+
profile_arn_for_payload = auth_manager.profile_arn or PROFILE_ARN or ""
576576

577577
try:
578578
kiro_payload = build_kiro_payload(

0 commit comments

Comments
 (0)