diff --git a/.env.example b/.env.example index f84c978..96f1206 100644 --- a/.env.example +++ b/.env.example @@ -31,6 +31,7 @@ RATE_LIMIT_PER_MIN=30 # Agent Execution Limits & Guardrails MAX_STEPS=10 +MAX_RETRIES=3 RUN_TIMEOUT_S=60 TOOL_TIMEOUT_S=15 SESSION_TTL_S=3600 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9cdcafa..12b1254 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,9 +52,8 @@ jobs: REDIS_URL: redis://localhost:6379/0 GEMINI_API_KEY: fake_gemini_key_for_testing OPENAI_API_KEY: fake_openai_key_for_testing - TAVILY_API_KEY: fake_tavily_key_for_testing + SEARCH_API_KEY: fake_search_key_for_testing API_KEYS: test_api_key_1,test_api_key_2 - JWT_SECRET: test_secret_key_at_least_32_bytes_long PYTHONPATH: . steps: - name: Check out repository diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index dd4d9e0..3aa7471 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -108,3 +108,20 @@ This log records significant architectural, technical, and design decisions made - `docker compose up` boots directly into a fully seeded, turnkey environment ready for analytical queries via `sql_readonly`. - Database seeding is safely re-entrant across container restarts without data duplication or integrity errors. +--- + +## ADR-008: Gemini Multi-Turn Function Response Role Specification and Model Standardization + +- **Date**: 2026-10-01 +- **Status**: Accepted +- **Context**: The official Google Gemini GenAI SDK requires function execution responses in multi-turn chat history to be represented with `role="user"` wrapping `types.Part.from_function_response(...)`. Setting `role="tool"` triggers an upstream `400 INVALID_ARGUMENT` error because the Gemini API expects function outputs to be submitted as user turns containing function responses. Furthermore, Gemini API access tiers and quotas vary across model tiers; `gemini-3.1-flash-lite` provides ultra-low latency, robust tool calling, and high throughput without encountering regional or tier rate limitations. +- **Decision**: + - Update `GeminiClient.chat()` to wrap function responses with `role="user"` using `types.Part.from_function_response(name=tool_name, response={"result": msg.content})`. + - Standardize the default active Gemini model to `gemini-3.1-flash-lite` across `Settings`, `GeminiClient`, `create_llm_client`, `.env.example`, `docker-compose.yml`, and documentation. + - Wire `RetryingLLMClient` with configurable `MAX_RETRIES` (default 3) and exponential backoff into `create_llm_client_from_settings()`. +- **Consequences**: + - Eliminates 400 Invalid Argument errors on multi-turn ReAct tool execution with Gemini. + - Consistent model behavior across local, containerized, and CI environments. + - Automatic resilience against transient 429 quota exhaustion and 5xx network spikes. + + diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 35fd81c..fba2b0e 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -178,8 +178,6 @@ Fetch production secrets dynamically using the AWS CLI: # Create parameters in AWS SSM aws ssm put-parameter --name "/agentkit/production/DATABASE_PASSWORD" \ --value "$(openssl rand -hex 24)" --type "SecureString" -aws ssm put-parameter --name "/agentkit/production/JWT_SECRET" \ - --value "$(openssl rand -hex 32)" --type "SecureString" aws ssm put-parameter --name "/agentkit/production/API_KEYS" \ --value "prod_key_$(openssl rand -hex 16)" --type "SecureString" aws ssm put-parameter --name "/agentkit/production/GEMINI_API_KEY" \ @@ -191,23 +189,22 @@ cat << 'EOF' > /opt/agentkit/fetch_secrets.sh set -euo pipefail DB_PASS=$(aws ssm get-parameter --name "/agentkit/production/DATABASE_PASSWORD" --with-decryption --query "Parameter.Value" --output text) -JWT_SEC=$(aws ssm get-parameter --name "/agentkit/production/JWT_SECRET" --with-decryption --query "Parameter.Value" --output text) API_KEYS=$(aws ssm get-parameter --name "/agentkit/production/API_KEYS" --with-decryption --query "Parameter.Value" --output text) GEMINI_KEY=$(aws ssm get-parameter --name "/agentkit/production/GEMINI_API_KEY" --with-decryption --query "Parameter.Value" --output text) cat << ENVFILE > /opt/agentkit/.env -ENVIRONMENT=production -LOG_LEVEL=INFO DATABASE_URL=postgresql+asyncpg://agentkit:${DB_PASS}@postgres:5432/agentkit POSTGRES_USER=agentkit POSTGRES_PASSWORD=${DB_PASS} POSTGRES_DB=agentkit REDIS_URL=redis://redis:6379/0 LLM_PROVIDER=gemini +LLM_MODEL=gemini-3.1-flash-lite GEMINI_API_KEY=${GEMINI_KEY} -JWT_SECRET=${JWT_SEC} API_KEYS=${API_KEYS} FILE_TOOL_BASE_DIR=/tmp/agentkit_sandbox +RUN_TIMEOUT_S=60 +MAX_RETRIES=3 ENVFILE chmod 600 /opt/agentkit/.env diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index c56feed..157574e 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -56,6 +56,10 @@ This document tracks execution progress across all backlog tasks, including pull | AUD-01 | AUD | Strict Infrastructure Resolution in API Dependencies | `fix/api-deps-strict-infrastructure` | #48 | 2 | Done | Eliminate silent in-memory and fake LLM fallbacks from deps.py | | AUD-04 | AUD | Wire RetryingLLMClient into LLM Factory | `fix/wire-llm-retry-wrapper` | #49 | 2 | Done | Added MAX_RETRIES setting and wrapped live LLM providers with retry | | AUD-05 | AUD | Strict Demo Mode & README Configuration Cleanup | `fix/demo-strict-mode-and-docs` | #50 | 2 | Done | Explicit credential validation in demo and remove unused env keys | +| AUD-07 | AUD | Gemini Multi-Turn Role Specification & Active Model Standard | `feat/gemini-tool-calling-fix` | #51 | 2 | Done | Updated function response to role user and default model to gemini-3.1-flash-lite | +| AUD-08 | AUD | Expose Configurable Timeout in Docker Compose | `fix/docker-compose-timeout` | #52 | 2 | Done | Exposed RUN_TIMEOUT_S in docker-compose.yml | +| AUD-09 | AUD | Live End-to-End Infrastructure Verification & Documentation Proof | `docs/e2e-verification-report` | #53 | 3 | Done | Standardized model, verified live stack, and documented in E2E_REPORT.md | + ---