feat(claude-kiro): 支持AWS企业用户idcRegion字段并优化模型配置
- 在AWS凭据导入说明中增加idcRegion字段要求 - 移除不再使用的Amazon Q相关URL和旧模型映射 - 为Builder ID认证流程添加region选择和idcRegion支持 - 优化凭据加载逻辑,支持独立配置idcRegion - 在UI中添加region输入框和刷新按钮
This commit is contained in:
parent
37dab55d49
commit
785ac7890d
4 changed files with 56 additions and 32 deletions
|
|
@ -16,7 +16,7 @@ const KIRO_OAUTH_CONFIG = {
|
|||
authServiceEndpoint: 'https://prod.us-east-1.auth.desktop.kiro.dev',
|
||||
|
||||
// AWS SSO OIDC 端点 (用于 Builder ID)
|
||||
ssoOIDCEndpoint: 'https://oidc.us-east-1.amazonaws.com',
|
||||
ssoOIDCEndpoint: 'https://oidc.{{region}}.amazonaws.com',
|
||||
|
||||
// AWS Builder ID 起始 URL
|
||||
builderIDStartURL: 'https://view.awsapps.com/start',
|
||||
|
|
@ -34,8 +34,8 @@ const KIRO_OAUTH_CONFIG = {
|
|||
'codewhisperer:completions',
|
||||
'codewhisperer:analysis',
|
||||
'codewhisperer:conversations',
|
||||
'codewhisperer:transformations',
|
||||
'codewhisperer:taskassist'
|
||||
// 'codewhisperer:transformations',
|
||||
// 'codewhisperer:taskassist'
|
||||
],
|
||||
|
||||
// 凭据存储(符合现有规范)
|
||||
|
|
@ -252,7 +252,10 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) {
|
|||
console.log(`${KIRO_OAUTH_CONFIG.logPrefix} Using Builder ID Start URL: ${builderIDStartURL}`);
|
||||
|
||||
// 1. 注册 OIDC 客户端
|
||||
const regResponse = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/client/register`, {
|
||||
const region = options.region || 'us-east-1';
|
||||
const ssoOIDCEndpoint = KIRO_OAUTH_CONFIG.ssoOIDCEndpoint.replace('{{region}}', region);
|
||||
|
||||
const regResponse = await fetchWithProxy(`${ssoOIDCEndpoint}/client/register`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -262,7 +265,7 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) {
|
|||
clientName: 'Kiro IDE',
|
||||
clientType: 'public',
|
||||
scopes: KIRO_OAUTH_CONFIG.scopes,
|
||||
grantTypes: ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token']
|
||||
// grantTypes: ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token']
|
||||
})
|
||||
}, 'claude-kiro-oauth');
|
||||
|
||||
|
|
@ -273,11 +276,10 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) {
|
|||
const regData = await regResponse.json();
|
||||
|
||||
// 2. 启动设备授权
|
||||
const authResponse = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/device_authorization`, {
|
||||
const authResponse = await fetchWithProxy(`${ssoOIDCEndpoint}/device_authorization`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'KiroIDE'
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
clientId: regData.clientId,
|
||||
|
|
@ -304,7 +306,7 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) {
|
|||
5,
|
||||
300,
|
||||
taskId,
|
||||
options
|
||||
{ ...options, region }
|
||||
).catch(error => {
|
||||
console.error(`${KIRO_OAUTH_CONFIG.logPrefix} 轮询失败 [${taskId}]:`, error);
|
||||
broadcastEvent('oauth_error', {
|
||||
|
|
@ -356,7 +358,9 @@ async function pollKiroBuilderIDToken(clientId, clientSecret, deviceCode, interv
|
|||
attempts++;
|
||||
|
||||
try {
|
||||
const response = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/token`, {
|
||||
const region = options.region || 'us-east-1';
|
||||
const ssoOIDCEndpoint = KIRO_OAUTH_CONFIG.ssoOIDCEndpoint.replace('{{region}}', region);
|
||||
const response = await fetchWithProxy(`${ssoOIDCEndpoint}/token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -391,7 +395,7 @@ async function pollKiroBuilderIDToken(clientId, clientSecret, deviceCode, interv
|
|||
authMethod: 'builder-id',
|
||||
clientId,
|
||||
clientSecret,
|
||||
region: 'us-east-1'
|
||||
idcRegion: options.region || 'us-east-1'
|
||||
};
|
||||
|
||||
await fs.promises.mkdir(path.dirname(credPath), { recursive: true });
|
||||
|
|
@ -634,7 +638,8 @@ const KIRO_REFRESH_CONSTANTS = {
|
|||
AUTH_METHOD_SOCIAL: 'social',
|
||||
DEFAULT_PROVIDER: 'Google',
|
||||
REQUEST_TIMEOUT: 30000,
|
||||
DEFAULT_REGION: 'us-east-1'
|
||||
DEFAULT_REGION: 'us-east-1',
|
||||
IDC_REGION: 'us-east-1' // 用于 REFRESH_IDC_URL 的区域配置
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1024,7 +1029,8 @@ export async function importAwsCredentials(credentials, skipDuplicateCheck = fal
|
|||
accessToken: credentials.accessToken,
|
||||
refreshToken: credentials.refreshToken,
|
||||
authMethod: credentials.authMethod || 'builder-id',
|
||||
region: credentials.region || KIRO_REFRESH_CONSTANTS.DEFAULT_REGION
|
||||
// region: credentials.region || KIRO_REFRESH_CONSTANTS.DEFAULT_REGION,
|
||||
idcRegion: credentials.idcRegion || KIRO_REFRESH_CONSTANTS.IDC_REGION
|
||||
};
|
||||
|
||||
// 可选字段
|
||||
|
|
@ -1042,8 +1048,8 @@ export async function importAwsCredentials(credentials, skipDuplicateCheck = fal
|
|||
try {
|
||||
console.log(`${KIRO_OAUTH_CONFIG.logPrefix} Attempting to refresh token with provided credentials...`);
|
||||
|
||||
const region = credentials.region || KIRO_REFRESH_CONSTANTS.DEFAULT_REGION;
|
||||
const refreshUrl = KIRO_REFRESH_CONSTANTS.REFRESH_IDC_URL.replace('{{region}}', region);
|
||||
const refreshRegion = credentials.idcRegion || KIRO_REFRESH_CONSTANTS.IDC_REGION;
|
||||
const refreshUrl = KIRO_REFRESH_CONSTANTS.REFRESH_IDC_URL.replace('{{region}}', refreshRegion);
|
||||
|
||||
const refreshResponse = await fetchWithProxy(refreshUrl, {
|
||||
method: 'POST',
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ const KIRO_CONSTANTS = {
|
|||
REFRESH_URL: 'https://prod.{{region}}.auth.desktop.kiro.dev/refreshToken',
|
||||
REFRESH_IDC_URL: 'https://oidc.{{region}}.amazonaws.com/token',
|
||||
BASE_URL: 'https://q.{{region}}.amazonaws.com/generateAssistantResponse',
|
||||
AMAZON_Q_URL: 'https://codewhisperer.{{region}}.amazonaws.com/SendMessageStreaming',
|
||||
USAGE_LIMITS_URL: 'https://q.{{region}}.amazonaws.com/getUsageLimits',
|
||||
DEFAULT_MODEL_NAME: 'claude-opus-4-5',
|
||||
DEFAULT_MODEL_NAME: 'claude-sonnet-4-5',
|
||||
AXIOS_TIMEOUT: 120000, // 2 minutes timeout for normal requests
|
||||
TOKEN_REFRESH_TIMEOUT: 15000, // 15 seconds timeout for token refresh (shorter to avoid blocking)
|
||||
USER_AGENT: 'KiroIDE',
|
||||
|
|
@ -49,9 +47,7 @@ const FULL_MODEL_MAPPING = {
|
|||
"claude-opus-4-5":"claude-opus-4.5",
|
||||
"claude-opus-4-5-20251101":"claude-opus-4.5",
|
||||
"claude-sonnet-4-5": "CLAUDE_SONNET_4_5_20250929_V1_0",
|
||||
"claude-sonnet-4-5-20250929": "CLAUDE_SONNET_4_5_20250929_V1_0",
|
||||
"claude-sonnet-4-20250514": "CLAUDE_SONNET_4_20250514_V1_0",
|
||||
"claude-3-7-sonnet-20250219": "CLAUDE_3_7_SONNET_20250219_V1_0"
|
||||
"claude-sonnet-4-5-20250929": "CLAUDE_SONNET_4_5_20250929_V1_0"
|
||||
};
|
||||
|
||||
// 只保留 KIRO_MODELS 中存在的模型映射
|
||||
|
|
@ -362,7 +358,6 @@ export class KiroApiService {
|
|||
// this.refreshUrl = KIRO_CONSTANTS.REFRESH_URL;
|
||||
// this.refreshIDCUrl = KIRO_CONSTANTS.REFRESH_IDC_URL;
|
||||
// this.baseUrl = KIRO_CONSTANTS.BASE_URL;
|
||||
// this.amazonQUrl = KIRO_CONSTANTS.AMAZON_Q_URL;
|
||||
|
||||
// Add kiro-oauth-creds-base64 and kiro-oauth-creds-file to config
|
||||
if (config.KIRO_OAUTH_CREDS_BASE64) {
|
||||
|
|
@ -536,16 +531,21 @@ async loadCredentials() {
|
|||
this.expiresAt = this.expiresAt || mergedCredentials.expiresAt;
|
||||
this.profileArn = this.profileArn || mergedCredentials.profileArn;
|
||||
this.region = this.region || mergedCredentials.region;
|
||||
this.idcRegion = this.idcRegion || mergedCredentials.idcRegion;
|
||||
|
||||
if (!this.region) {
|
||||
console.warn('[Kiro Auth] Region not found in credentials. Using default region us-east-1 for URLs.');
|
||||
this.region = 'us-east-1';
|
||||
}
|
||||
|
||||
// idcRegion 用于 REFRESH_IDC_URL,如果未设置则使用 region
|
||||
if (!this.idcRegion) {
|
||||
this.idcRegion = this.region;
|
||||
}
|
||||
|
||||
this.refreshUrl = (this.config.KIRO_REFRESH_URL || KIRO_CONSTANTS.REFRESH_URL).replace("{{region}}", this.region);
|
||||
this.refreshIDCUrl = (this.config.KIRO_REFRESH_IDC_URL || KIRO_CONSTANTS.REFRESH_IDC_URL).replace("{{region}}", this.region);
|
||||
this.refreshIDCUrl = (this.config.KIRO_REFRESH_IDC_URL || KIRO_CONSTANTS.REFRESH_IDC_URL).replace("{{region}}", this.idcRegion);
|
||||
this.baseUrl = (this.config.KIRO_BASE_URL || KIRO_CONSTANTS.BASE_URL).replace("{{region}}", this.region);
|
||||
this.amazonQUrl = (KIRO_CONSTANTS.AMAZON_Q_URL).replace("{{region}}", this.region);
|
||||
} catch (error) {
|
||||
console.warn(`[Kiro Auth] Error during credential loading: ${error.message}`);
|
||||
}
|
||||
|
|
@ -2724,7 +2724,8 @@ async saveCredentialsToFile(filePath, newData) {
|
|||
const resourceType = 'AGENTIC_REQUEST';
|
||||
|
||||
// 构建请求 URL
|
||||
const usageLimitsUrl = KIRO_CONSTANTS.USAGE_LIMITS_URL.replace('{{region}}', this.region);
|
||||
let usageLimitsUrl = this.baseUrl;
|
||||
usageLimitsUrl = usageLimitsUrl.replace('generateAssistantResponse', 'getUsageLimits');
|
||||
const params = new URLSearchParams({
|
||||
isEmailRequired: 'true',
|
||||
origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR,
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ const translations = {
|
|||
'oauth.kiro.batchImportInstructions': '请输入 refreshToken,每行一个。系统将自动刷新并生成凭据文件。',
|
||||
'oauth.kiro.awsImport': '导入 AWS 账号',
|
||||
'oauth.kiro.awsImportDesc': '从 AWS SSO cache 目录导入凭据文件,适用于 AWS Builder ID 模式。',
|
||||
'oauth.kiro.awsImportInstructions': '请上传 AWS SSO cache 目录中的 JSON 文件,需包含 clientId、clientSecret、accessToken、refreshToken 四个字段。',
|
||||
'oauth.kiro.awsImportInstructions': '请上传 AWS SSO cache 目录中的 JSON 文件,需包含 clientId、clientSecret、accessToken、refreshToken 四个字段。如果是AWS企业用户,需增加 idcRegion 字段。',
|
||||
'oauth.kiro.awsModeFile': '文件上传',
|
||||
'oauth.kiro.awsModeJson': 'JSON 粘贴',
|
||||
'oauth.kiro.awsUploadFiles': '上传凭据文件',
|
||||
|
|
@ -856,7 +856,7 @@ const translations = {
|
|||
'oauth.kiro.batchImportInstructions': 'Enter refreshTokens, one per line. The system will automatically refresh and generate credential files.',
|
||||
'oauth.kiro.awsImport': 'Import AWS Account',
|
||||
'oauth.kiro.awsImportDesc': 'Import credential files from AWS SSO cache directory. For AWS Builder ID mode.',
|
||||
'oauth.kiro.awsImportInstructions': 'Upload JSON files from AWS SSO cache directory. Must contain clientId, clientSecret, accessToken, and refreshToken.',
|
||||
'oauth.kiro.awsImportInstructions': 'Upload JSON files from AWS SSO cache directory. Must contain clientId, clientSecret, accessToken, and refreshToken. For AWS enterprise users, add the idcRegion field.',
|
||||
'oauth.kiro.awsModeFile': 'File Upload',
|
||||
'oauth.kiro.awsModeJson': 'Paste JSON',
|
||||
'oauth.kiro.awsUploadFiles': 'Upload Credential Files',
|
||||
|
|
|
|||
|
|
@ -1723,7 +1723,12 @@ function showAuthModal(authUrl, authInfo) {
|
|||
<div class="modal-body">
|
||||
<div class="auth-info">
|
||||
<p><strong data-i18n="oauth.modal.provider">${t('oauth.modal.provider')}</strong> ${authInfo.provider}</p>
|
||||
<div class="port-info-section" style="margin: 12px 0; padding: 12px; background: #fef3c7; border: 1px solid #fcd34d; border-radius: 8px;">
|
||||
<div class="port-info-section" style="margin: 12px 0; padding: 12px; background: #fef3c7; border: 1px solid #fcd34d; border-radius: 8px; position: relative;">
|
||||
${(authInfo.provider === 'claude-kiro-oauth' && authInfo.authMethod === 'builder-id') ? `
|
||||
<button class="regenerate-builder-id-btn" title="${t('common.generate')}" style="position: absolute; top: 12px; right: 12px; background: none; border: 1px solid #d97706; border-radius: 4px; cursor: pointer; color: #d97706; padding: 4px 8px;">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
<div style="margin: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
|
||||
<i class="fas fa-network-wired" style="color: #d97706;"></i>
|
||||
<strong data-i18n="oauth.modal.requiredPort">${t('oauth.modal.requiredPort')}</strong>
|
||||
|
|
@ -1751,15 +1756,25 @@ function showAuthModal(authUrl, authInfo) {
|
|||
placeholder="https://view.awsapps.com/start"
|
||||
style="flex: 1; padding: 6px 10px; border: 1px solid #fcd34d; border-radius: 4px; font-size: 13px; color: #92400e; background: white;"
|
||||
/>
|
||||
<button class="regenerate-builder-id-btn" title="${t('common.generate')}" style="background: none; border: 1px solid #d97706; border-radius: 4px; cursor: pointer; color: #d97706; padding: 4px 8px;">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p style="margin: 6px 0 0 0; font-size: 0.75rem; color: #b45309;">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span data-i18n="oauth.kiro.builderIDStartURLHint">${t('oauth.kiro.builderIDStartURLHint') || '如果您使用 AWS IAM Identity Center,请输入您的 Start URL'}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="builder-id-region-section" style="margin-top: 12px; padding-top: 12px; border-top: 1px dashed #fcd34d;">
|
||||
<label style="display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 13px; font-weight: 600; color: #92400e;">
|
||||
<i class="fas fa-globe"></i>
|
||||
<span>AWS Region</span>
|
||||
</label>
|
||||
<div style="display: flex; align-items: center; gap: 4px;">
|
||||
<input type="text" class="builder-id-region-input"
|
||||
value="${authInfo.region || 'us-east-1'}"
|
||||
placeholder="us-east-1"
|
||||
style="flex: 1; padding: 6px 10px; border: 1px solid #fcd34d; border-radius: 4px; font-size: 13px; color: #92400e; background: white;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
${instructionsHtml}
|
||||
|
|
@ -1819,11 +1834,13 @@ function showAuthModal(authUrl, authInfo) {
|
|||
if (regenerateBuilderIdBtn) {
|
||||
regenerateBuilderIdBtn.onclick = async () => {
|
||||
const builderIdStartUrl = modal.querySelector('.builder-id-start-url-input').value.trim();
|
||||
const region = modal.querySelector('.builder-id-region-input').value.trim();
|
||||
modal.remove();
|
||||
// 构造重新请求的参数
|
||||
const options = {
|
||||
...authInfo,
|
||||
builderIDStartURL: builderIdStartUrl || 'https://view.awsapps.com/start'
|
||||
builderIDStartURL: builderIdStartUrl || 'https://view.awsapps.com/start',
|
||||
region: region || 'us-east-1'
|
||||
};
|
||||
// 移除不需要传递回后端的字段
|
||||
delete options.provider;
|
||||
|
|
|
|||
Loading…
Reference in a new issue