From 2b04aefa6d931ff67a19417e1747bc0f1b608a8d Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 19 Jan 2026 16:09:59 +0100 Subject: [PATCH] feat(ai): add AWS ECS/IRSA credential detection for Bedrock, fixes #848 Added support for additional AWS credential environment variables: - AWS_CONTAINER_CREDENTIALS_RELATIVE_URI (ECS task roles) - AWS_CONTAINER_CREDENTIALS_FULL_URI (ECS task roles) - AWS_WEB_IDENTITY_TOKEN_FILE (IRSA for Kubernetes) Also fixed undefined currentModel variable in OAuth error handling. --- packages/ai/CHANGELOG.md | 4 ++++ packages/ai/src/stream.ts | 8 +++++++- packages/coding-agent/src/core/sdk.ts | 11 ++++++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 47e53379..1c912be6 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added AWS credential detection for ECS/Kubernetes environments: `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`, `AWS_CONTAINER_CREDENTIALS_FULL_URI`, `AWS_WEB_IDENTITY_TOKEN_FILE` ([#848](https://github.com/badlogic/pi-mono/issues/848)) + ### Fixed - Fixed OpenAI Responses 400 error "reasoning without following item" by skipping errored/aborted assistant messages entirely in transform-messages.ts ([#838](https://github.com/badlogic/pi-mono/pull/838)) diff --git a/packages/ai/src/stream.ts b/packages/ai/src/stream.ts index d91820c6..4164edcb 100644 --- a/packages/ai/src/stream.ts +++ b/packages/ai/src/stream.ts @@ -80,10 +80,16 @@ export function getEnvApiKey(provider: any): string | undefined { // 1. AWS_PROFILE - named profile from ~/.aws/credentials // 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys // 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock API keys (bearer token) + // 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles + // 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI) + // 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts) if ( process.env.AWS_PROFILE || (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) || - process.env.AWS_BEARER_TOKEN_BEDROCK + process.env.AWS_BEARER_TOKEN_BEDROCK || + process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || + process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI || + process.env.AWS_WEB_IDENTITY_TOKEN_FILE ) { return ""; } diff --git a/packages/coding-agent/src/core/sdk.ts b/packages/coding-agent/src/core/sdk.ts index a1d2f485..87438c29 100644 --- a/packages/coding-agent/src/core/sdk.ts +++ b/packages/coding-agent/src/core/sdk.ts @@ -641,17 +641,18 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} } const key = await modelRegistry.getApiKeyForProvider(resolvedProvider); if (!key) { - const isOAuth = modelRegistry.isUsingOAuth(currentModel); + const model = agent.state.model; + const isOAuth = model && modelRegistry.isUsingOAuth(model); if (isOAuth) { throw new Error( - `Authentication failed for "${currentModel.provider}". ` + + `Authentication failed for "${resolvedProvider}". ` + `Credentials may have expired or network is unavailable. ` + - `Run '/login ${currentModel.provider}' to re-authenticate.`, + `Run '/login ${resolvedProvider}' to re-authenticate.`, ); } throw new Error( - `No API key found for "${currentModel.provider}". ` + - `Set an API key environment variable or run '/login ${currentModel.provider}'.`, + `No API key found for "${resolvedProvider}". ` + + `Set an API key environment variable or run '/login ${resolvedProvider}'.`, ); } return key;