Skip to content

refactor(platform/copilot): consolidate 4 model-routing LD flags into 1 JSON flag#12917

Merged
majdyz merged 2 commits into
devfrom
feat/consolidate-copilot-model-routing-flag
Apr 25, 2026
Merged

refactor(platform/copilot): consolidate 4 model-routing LD flags into 1 JSON flag#12917
majdyz merged 2 commits into
devfrom
feat/consolidate-copilot-model-routing-flag

Conversation

@majdyz
Copy link
Copy Markdown
Contributor

@majdyz majdyz commented Apr 24, 2026

What

Replaces 4 string-valued LaunchDarkly flags with a single JSON-valued flag for copilot model routing:

  • copilot-fast-standard-model
  • copilot-fast-advanced-model
  • copilot-thinking-standard-model
  • copilot-thinking-advanced-model

New: copilot-model-routing (JSON), keyed {mode: {tier: model}}:

{
  "fast":     { "standard": "anthropic/claude-sonnet-4-6", "advanced": "anthropic/claude-opus-4-6" },
  "thinking": { "standard": "moonshotai/kimi-k2.6",         "advanced": "anthropic/claude-opus-4-6" }
}

Why

Same pattern as the sibling consolidation in #12915 (pricing / cost-limits flags) and the merged #12910 (tier-multipliers):

  • One flag per config domain — less LD UI clutter, easier audit trail.
  • Atomic updates — rotating fast.standard + thinking.standard is a single save.
  • Fewer LD entities to name, version, target, explain.
  • Mirrors the now-uniform copilot-* JSON-flag shape.

How

  • backend/util/feature_flag.py: drop the four COPILOT_*_MODEL enum values, add COPILOT_MODEL_ROUTING.
  • backend/copilot/model_router.py: rewrite resolve_model to fetch the JSON flag once per call and walk payload[mode][tier]. Missing mode, missing tier-within-mode, non-string cell value, non-dict payload, or LD failure all fall back to the corresponding ChatConfig default (same user-visible semantics as before). _FLAG_BY_CELL removed entirely; _config_default / ModelMode / ModelTier unchanged.
  • Per-user LD targeting preserved — cohorts can still receive different routing.
  • No caching added (preserves existing uncached behaviour).
  • Docstring references in copilot/config.py + copilot/sdk/service.py updated to point at the new nested key path; one docstring in service_test.py likewise.

Operator action required BEFORE merging

This PR removes 4 LD flags and introduces 1 replacement.

  1. In LaunchDarkly, create copilot-model-routing (type: JSON, server-side only). Default variation = union of the current four string flags, shaped as:

    {
      "fast":     { "standard": "<current copilot-fast-standard-model>",     "advanced": "<current copilot-fast-advanced-model>" },
      "thinking": { "standard": "<current copilot-thinking-standard-model>", "advanced": "<current copilot-thinking-advanced-model>" }
    }

    Omit any cell that's currently unset (its ChatConfig default will be used).

  2. Merge this PR.

  3. After deploy + smoke, delete the four legacy flags:

    • copilot-fast-standard-model
    • copilot-fast-advanced-model
    • copilot-thinking-standard-model
    • copilot-thinking-advanced-model

Testing

  • backend/copilot/model_router_test.py rewritten — 27 tests pass:
    • LD unset / None payload → fallback for every cell.
    • Full JSON → each cell maps to its value (parametrized).
    • Partial JSON (missing mode, missing tier-within-mode, mode value not a dict).
    • Non-dict payloads (str / list / int / bool) → fallback + warning.
    • Non-string cell values (number, list, bool, dict) → fallback + 'non-string' warning.
    • Empty-string cell → fallback + 'empty string' warning (not 'non-string').
    • LD raises → fallback + warning with exc_info.
    • user_id=None → skip LD entirely.
    • Single-LD-call regression guard against re-introducing per-cell flag fan-out.
  • backend/copilot/sdk/service_test.py: 61 tests still pass (it mocks _resolve_thinking_model_for_user, so the inner flag change is transparent).
  • black --check / ruff check / isort --check all clean.

Sibling

Checklist

  • I have read the project's contributing guide.
  • I have clearly described what this PR changes and why.
  • My code follows the style guidelines of this project.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes (CI will confirm).

… 1 JSON flag

Replaces 4 string-valued LaunchDarkly flags (copilot-fast-standard-model,
copilot-fast-advanced-model, copilot-thinking-standard-model,
copilot-thinking-advanced-model) with a single JSON flag
`copilot-model-routing` keyed by `{mode: {tier: model}}`.

Same pattern as #12915 (pricing flags) and #12910 (tier-multipliers): one
flag per config domain, atomic updates, smaller LD UI surface. Per-user
targeting is preserved. Missing mode, missing tier-within-mode, non-string
cell value, non-dict payload, and LD failures all fall back to the
existing ChatConfig default — user-visible semantics don't change.

Removes the per-cell _FLAG_BY_CELL dispatch dict in model_router.py;
docstring references in copilot/config.py + copilot/sdk/service.py
updated to point at the new nested key path.
@majdyz majdyz requested a review from a team as a code owner April 24, 2026 23:36
@github-project-automation github-project-automation Bot moved this to 🆕 Needs initial review in AutoGPT development kanban Apr 24, 2026
@majdyz majdyz requested review from 0ubbe and Bentlybro and removed request for a team April 24, 2026 23:36
@github-actions github-actions Bot added platform/backend AutoGPT Platform - Back end size/l labels Apr 24, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

Walkthrough

Consolidates four per-cell LaunchDarkly string flags into a single JSON-valued copilot-model-routing flag; resolve_model now reads and validates the JSON payload and falls back to ChatConfig defaults when the payload is missing, malformed, or LD evaluation fails.

Changes

Cohort / File(s) Summary
Feature Flag Enum
autogpt_platform/backend/backend/util/feature_flag.py
Removed four per-cell flag members and added a single COPILOT_MODEL_ROUTING enum member; updated docstring describing expected mode→tier→model payload shape and fallback semantics.
Core Router Logic
autogpt_platform/backend/backend/copilot/model_router.py
Replaced per-cell LD lookups with one JSON flag fetch (copilot-model-routing); validate top-level object, mode cell types, and per-cell string values; log warnings for malformed payloads and fall back to ChatConfig defaults on missing/invalid values or LD errors.
Configuration Docs
autogpt_platform/backend/backend/copilot/config.py
Updated Field(..., description=...) strings for four ChatConfig model fields to reference copilot-model-routing[<mode>][<tier>] instead of legacy flag names.
SDK Docs
autogpt_platform/backend/backend/copilot/sdk/service.py
Updated inline comments/docstrings to reference the new copilot-model-routing[thinking][{tier}] flag format; no executable changes.
Tests
autogpt_platform/backend/backend/copilot/model_router_test.py, autogpt_platform/backend/backend/copilot/sdk/service_test.py
Switched tests from per-cell string-flag expectations to JSON payload testing: None fallback, full/partial overrides, whitespace stripping, type/shape validation, warning logs for malformed payloads, and asserting a single copilot-model-routing lookup.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Router as model_router.resolve_model()
    participant LD as LaunchDarkly
    participant Config as ChatConfig

    App->>Router: resolve_model(user, mode, tier)
    Router->>LD: get_feature_flag_value('copilot-model-routing', default=None)
    LD-->>Router: payload (dict or None)

    alt Valid JSON payload with string at [mode][tier]
        Router->>Router: validate payload structure
        Router-->>App: return model from payload
    else Payload None / missing / invalid / non-string
        Router->>Config: read default model field
        Config-->>Router: default model
        Router-->>App: return default model
    else LD exception
        Router->>Router: log "LD lookup failed" (with exc_info)
        Router->>Config: read default model field
        Config-->>Router: default model
        Router-->>App: return default model
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Swiftyos
  • Pwuts

Poem

🐰 One flag to rule the tiers, nested neat and bright,
I nibble through JSON, parsing day and night.
If LaunchDarkly whispers true, I'll bounce the chosen name,
If it falters or goes missing, ChatConfig saves the game. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: consolidating four separate LaunchDarkly flags into one JSON flag for copilot model routing.
Description check ✅ Passed The description comprehensively explains what changes, why (using consistent pattern from sibling PRs), how it's implemented, testing coverage, and required operator actions before and after merge.
Docstring Coverage ✅ Passed Docstring coverage is 80.95% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/consolidate-copilot-model-routing-flag

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

🔍 PR Overlap Detection

This check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early.

🔴 Merge Conflicts Detected

The following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.

  • fix(copilot): prevent 524 timeout on chat deletion by deferring cleanup #12668 (Otto-AGPT · updated 8d ago)

    • autogpt_platform/backend/backend/api/features/library/db.py (5 conflicts, ~67 lines)
    • autogpt_platform/backend/backend/api/features/library/model.py (1 conflict, ~4 lines)
    • autogpt_platform/backend/backend/api/features/subscription_routes_test.py (22 conflicts, ~1047 lines)
    • autogpt_platform/backend/backend/api/features/v1.py (10 conflicts, ~233 lines)
    • autogpt_platform/backend/backend/copilot/baseline/service.py (2 conflicts, ~15 lines)
    • autogpt_platform/backend/backend/copilot/model_test.py (1 conflict, ~5 lines)
    • autogpt_platform/backend/backend/copilot/prompting.py (1 conflict, ~5 lines)
    • autogpt_platform/backend/backend/copilot/sdk/service.py (3 conflicts, ~51 lines)
    • autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py (1 conflict, ~129 lines)
    • autogpt_platform/backend/backend/copilot/transcript.py (1 conflict, ~11 lines)
    • autogpt_platform/backend/backend/data/credit.py (12 conflicts, ~816 lines)
    • autogpt_platform/backend/backend/data/credit_subscription_test.py (26 conflicts, ~1894 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/components/PulseChips/usePulseChips.ts (1 conflict, ~13 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/components/usageHelpers.ts (1 conflict, ~9 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/AgentBriefingPanel/BriefingTabContent.tsx (9 conflicts, ~147 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/AgentBriefingPanel/StatsGrid.tsx (2 conflicts, ~9 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/ContextualActionButton/ContextualActionButton.tsx (2 conflicts, ~12 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/SitrepItem.tsx (2 conflicts, ~15 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/useSitrepItems.ts (4 conflicts, ~97 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/hooks/useAgentStatus.ts (2 conflicts, ~10 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/hooks/useLibraryFleetSummary.ts (7 conflicts, ~57 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/types.ts (1 conflict, ~4 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx (11 conflicts, ~185 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/__tests__/SubscriptionTierSection.test.tsx (21 conflicts, ~486 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/useSubscriptionTierSection.ts (4 conflicts, ~60 lines)
    • autogpt_platform/frontend/src/app/api/openapi.json (2 conflicts, ~40 lines)
    • docs/integrations/block-integrations/llm.md (7 conflicts, ~35 lines)
    • docs/integrations/block-integrations/misc.md (1 conflict, ~5 lines)
  • feat(platform): Add AllQuiet alert integration alongside Discord alerts #11234 (ntindle · updated 4d ago)

    • autogpt_platform/backend/backend/api/features/chat/routes.py (2 conflicts, ~10 lines)
    • autogpt_platform/backend/backend/api/features/chat/routes_test.py (2 conflicts, ~734 lines)
    • autogpt_platform/backend/backend/api/features/subscription_routes_test.py (1 conflict, ~209 lines)
    • autogpt_platform/backend/backend/api/features/v1.py (6 conflicts, ~50 lines)
    • autogpt_platform/backend/backend/copilot/baseline/service.py (10 conflicts, ~328 lines)
    • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py (2 conflicts, ~919 lines)
    • autogpt_platform/backend/backend/copilot/config.py (2 conflicts, ~73 lines)
    • autogpt_platform/backend/backend/copilot/model_test.py (2 conflicts, ~183 lines)
    • autogpt_platform/backend/backend/copilot/prompting.py (4 conflicts, ~69 lines)
    • autogpt_platform/backend/backend/copilot/sdk/response_adapter.py (4 conflicts, ~267 lines)
    • autogpt_platform/backend/backend/copilot/sdk/response_adapter_test.py (1 conflict, ~4 lines)
    • autogpt_platform/backend/backend/copilot/sdk/service.py (4 conflicts, ~75 lines)
    • autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py (1 conflict, ~129 lines)
    • autogpt_platform/backend/backend/copilot/sdk/service_test.py (1 conflict, ~225 lines)
    • autogpt_platform/backend/backend/copilot/tools/__init__.py (1 conflict, ~4 lines)
    • autogpt_platform/backend/backend/copilot/tools/edit_agent.py (1 conflict, ~21 lines)
    • autogpt_platform/backend/backend/copilot/tools/helpers.py (2 conflicts, ~62 lines)
    • autogpt_platform/backend/backend/data/credit.py (4 conflicts, ~223 lines)
    • autogpt_platform/backend/backend/data/credit_subscription_test.py (8 conflicts, ~1388 lines)
    • autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/__tests__/helpers.test.ts (deleted here, modified there)
    • autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/helpers.ts (deleted here, modified there)
    • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx (1 conflict, ~5 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (2 conflicts, ~10 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.ts (1 conflict, ~5 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts (2 conflicts, ~16 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts (2 conflicts, ~42 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx (7 conflicts, ~132 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/useSubscriptionTierSection.ts (1 conflict, ~4 lines)
    • autogpt_platform/frontend/src/app/api/openapi.json (2 conflicts, ~14 lines)
    • docs/integrations/block-integrations/llm.md (7 conflicts, ~35 lines)
    • docs/integrations/block-integrations/misc.md (1 conflict, ~5 lines)
  • feat(platform): estimate CoPilot turn cost and require approval for high-cost requests #12877 (Rushi-Balapure · updated 2d ago)

    • 📁 autogpt_platform/backend/backend/
      • api/features/chat/routes.py (2 conflicts, ~32 lines)
      • util/feature_flag.py (1 conflict, ~11 lines)

🟢 Low Risk — File Overlap Only

These PRs touch the same files but different sections (click to expand)

Summary: 3 conflict(s), 0 medium risk, 5 low risk (out of 8 PRs with file overlap)


Auto-generated on push. Ignores: openapi.json, lock files.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
autogpt_platform/backend/backend/copilot/model_router.py (1)

95-111: Prefer typed payload validation over nested dict checks.

The JSON routing payload is structured data; validating it through chained isinstance(..., dict) checks makes the shape rules harder to maintain and duplicates type logic in branches.

♻️ Suggested refactor (typed payload model)
+from pydantic import BaseModel, ValidationError
+
+class _TierRouting(BaseModel):
+    standard: str | None = None
+    advanced: str | None = None
+
+class _ModelRoutingPayload(BaseModel):
+    fast: _TierRouting | None = None
+    thinking: _TierRouting | None = None
+
 async def resolve_model(
@@
-    if not isinstance(payload, dict):
-        logger.warning(
-            "[model_router] copilot-model-routing expected a JSON object, got %r — "
-            "using config default %s for (%s, %s)",
-            payload,
-            fallback,
-            mode,
-            tier,
-        )
-        return fallback
-
-    mode_cell = payload.get(mode)
-    if not isinstance(mode_cell, dict):
+    try:
+        parsed = _ModelRoutingPayload.model_validate(payload)
+    except ValidationError:
+        logger.warning(
+            "[model_router] copilot-model-routing expected a valid JSON object, got %r — "
+            "using config default %s for (%s, %s)",
+            payload,
+            fallback,
+            mode,
+            tier,
+        )
         return fallback
 
-    value = mode_cell.get(tier)
+    mode_cell = parsed.fast if mode == "fast" else parsed.thinking
+    if mode_cell is None:
+        return fallback
+    value = mode_cell.advanced if tier == "advanced" else mode_cell.standard

As per coding guidelines: "Use Pydantic models over dataclass/namedtuple/dict for structured data" and "Do not use duck typing — avoid hasattr/getattr/isinstance for type dispatch; use typed interfaces/unions/protocols instead".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@autogpt_platform/backend/backend/copilot/model_router.py` around lines 95 -
111, Replace the ad-hoc nested dict/isinstance checks in model_router.py with a
Pydantic model that represents the expected routing payload shape and validate
payload once at the start of the function; specifically, create a Pydantic model
(e.g., RoutingPayload with fields like mode: dict[str, dict[str, str]] or a
nested model for mode_cell) and use it to parse/validate the incoming payload
instead of checking isinstance(payload, dict), isinstance(mode_cell, dict),
etc., then read the validated model (referencing payload, mode, tier, mode_cell,
value) to get the string mapping and return fallback when Pydantic parsing fails
or the mapping is missing/empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@autogpt_platform/backend/backend/copilot/model_router.py`:
- Around line 95-111: Replace the ad-hoc nested dict/isinstance checks in
model_router.py with a Pydantic model that represents the expected routing
payload shape and validate payload once at the start of the function;
specifically, create a Pydantic model (e.g., RoutingPayload with fields like
mode: dict[str, dict[str, str]] or a nested model for mode_cell) and use it to
parse/validate the incoming payload instead of checking isinstance(payload,
dict), isinstance(mode_cell, dict), etc., then read the validated model
(referencing payload, mode, tier, mode_cell, value) to get the string mapping
and return fallback when Pydantic parsing fails or the mapping is missing/empty.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9fd9c21a-2426-4882-89c1-48879338cbef

📥 Commits

Reviewing files that changed from the base of the PR and between 2deac20 and cefce3b.

📒 Files selected for processing (6)
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: type-check (3.11)
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
autogpt_platform/backend/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development

autogpt_platform/backend/**/*.py: Use poetry run ... command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies like openpyxl
Use absolute imports with from backend.module import ... for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoid hasattr/getattr/isinstance for type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no # type: ignore, # noqa, # pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use %s for deferred interpolation in debug log statements for efficiency; use f-strings elsewhere for readability (e.g., logger.debug("Processing %s items", count) vs logger.info(f"Processing {count} items"))
Sanitize error paths by using os.path.basename() in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Use transaction=True for Redis pipelines to ensure atomicity on multi-step operations
Use max(0, value) guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...

Files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
autogpt_platform/backend/**/*_test.py

📄 CodeRabbit inference engine (autogpt_platform/backend/AGENTS.md)

autogpt_platform/backend/**/*_test.py: Use pytest with snapshot testing for API responses
Colocate test files with source files using *_test.py naming convention
Mock at boundaries — mock where the symbol is used, not where it's defined; after refactoring, update mock targets to match new module paths
Use AsyncMock from unittest.mock for async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with @pytest.mark.xfail before implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, use poetry run pytest path/to/test.py --snapshot-update; always review snapshot changes with git diff before committing

Files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
🧠 Learnings (23)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/sdk/service.py:0-0
Timestamp: 2026-04-22T12:26:42.571Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py`, `_resolve_sdk_model_for_request`: when a per-user LaunchDarkly model value fails `_normalize_model_name` (e.g. a `moonshotai/kimi-*` slug in direct-Anthropic mode), the fallback must be tier-specific — `config.thinking_advanced_model` for advanced tier, `config.thinking_standard_model` for standard tier — NOT the generic `_resolve_sdk_model()` (which is standard-only and returns None under subscription mode). If the tier-specific config default also fails `_normalize_model_name`, re-raise the original LD error; this is a deployment-level misconfiguration that `model_validator` should have caught at startup. Established in PR `#12881` commit 637d2fef5.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12879
File: autogpt_platform/frontend/src/app/api/openapi.json:14576-14577
Timestamp: 2026-04-22T05:58:28.595Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Process convention: When adding new CoPilot tool response models and updating ToolResponseUnion in backend/api/features/chat/routes.py, regenerate the frontend OpenAPI schema via `poetry run export-api-schema` (do not hand-edit autogpt_platform/frontend/src/app/api/openapi.json).
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/config.py:0-0
Timestamp: 2026-04-22T11:46:04.431Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), `anthropic/claude-sonnet-4-6` (hyphen-separated) is the project-wide convention for the Claude Sonnet 4.6 model ID, used consistently in llm.py, blocks/test, reasoning.py, _is_anthropic_model tests, and config defaults. OpenRouter accepts both `anthropic/claude-sonnet-4-6` (hyphen) and `anthropic/claude-sonnet-4.6` (dot). Do NOT flag the hyphen form as incorrect — it has been in production since the Sonnet 4.6 upgrade and is intentional.
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12536
File: autogpt_platform/frontend/src/app/api/openapi.json:5770-5790
Timestamp: 2026-03-24T21:25:15.983Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12536`
File: autogpt_platform/frontend/src/app/api/openapi.json
Learning: The OpenAPI spec file is auto-generated; per established convention, endpoints generally declare only 200/201, 401, and 422 responses. Do not suggest adding explicit 403/404 response entries for single operations unless planning a repo-wide spec update. Prefer clarifying such behaviors in endpoint descriptions/docstrings instead of altering response maps.
📚 Learning: 2026-04-22T12:26:42.571Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/sdk/service.py:0-0
Timestamp: 2026-04-22T12:26:42.571Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py`, `_resolve_sdk_model_for_request`: when a per-user LaunchDarkly model value fails `_normalize_model_name` (e.g. a `moonshotai/kimi-*` slug in direct-Anthropic mode), the fallback must be tier-specific — `config.thinking_advanced_model` for advanced tier, `config.thinking_standard_model` for standard tier — NOT the generic `_resolve_sdk_model()` (which is standard-only and returns None under subscription mode). If the tier-specific config default also fails `_normalize_model_name`, re-raise the original LD error; this is a deployment-level misconfiguration that `model_validator` should have caught at startup. Established in PR `#12881` commit 637d2fef5.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-17T10:57:12.953Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-21T04:36:19.755Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12865
File: autogpt_platform/backend/backend/data/credit_subscription_test.py:1119-1122
Timestamp: 2026-04-21T04:36:19.755Z
Learning: In `autogpt_platform/backend/backend/data/credit_subscription_test.py` (and related subscription test files), test mocks for the user object returned by `get_user_by_id` should use snake_case `subscription_tier` (not camelCase `subscriptionTier`). This is because `get_user_by_id` (defined in `backend/data/user.py`) returns `backend.data.model.User` — a Pydantic application model with `subscription_tier: SubscriptionTier` — not a raw Prisma model. Production code in `backend/data/credit.py` reads `user.subscription_tier` from that Pydantic model. Do NOT flag `mock_user.subscription_tier = ...` as incorrect in these tests.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
📚 Learning: 2026-02-26T17:02:22.448Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12211
File: .pre-commit-config.yaml:160-179
Timestamp: 2026-02-26T17:02:22.448Z
Learning: Keep the pre-commit hook pattern broad for autogpt_platform/backend to ensure OpenAPI schema changes are captured. Do not narrow to backend/api/ alone, since the generated schema depends on Pydantic models across multiple directories (backend/data/, backend/blocks/, backend/copilot/, backend/integrations/, backend/util/). Narrowing could miss schema changes and cause frontend type desynchronization.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-04T08:04:35.881Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12273
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:216-220
Timestamp: 2026-03-04T08:04:35.881Z
Learning: In the AutoGPT Copilot backend, ensure that SVG images are not treated as vision image types by excluding 'image/svg+xml' from INLINEABLE_MIME_TYPES and MULTIMODAL_TYPES in tool_adapter.py; the Claude API supports PNG, JPEG, GIF, and WebP for vision. SVGs (XML text) should be handled via the text path instead, not the vision path.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-01T04:17:41.600Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:41.600Z
Learning: When reviewing AutoGPT Copilot tool implementations, accept that `readOnlyHint=True` (provided via `ToolAnnotations`) may be applied unconditionally to *all* tools—even tools that have side effects (e.g., `bash_exec`, `write_workspace_file`, or other write/save operations). Do **not** flag these tools for having `readOnlyHint=True`; this is intentional to enable fully-parallel dispatch by the Anthropic SDK/CLI and has been E2E validated. Only flag `readOnlyHint` issues if they conflict with the established `ToolAnnotations` behavior (e.g., missing/incorrect propagation relative to the intended annotation mechanism).

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-05T15:42:08.207Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12297
File: .claude/skills/backend-check/SKILL.md:14-16
Timestamp: 2026-03-05T15:42:08.207Z
Learning: In Python files under autogpt_platform/backend (recursively), rely on poetry run format to perform formatting (Black + isort) and linting (ruff). Do not run poetry run lint as a separate step after poetry run format, since format already includes linting checks.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-16T16:35:40.236Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/api/features/workflow_import.py:54-63
Timestamp: 2026-03-16T16:35:40.236Z
Learning: Avoid using the word 'competitor' in public-facing identifiers and text. Use neutral naming for API paths, model names, function names, and UI text. Examples: rename 'CompetitorFormat' to 'SourcePlatform', 'convert_competitor_workflow' to 'convert_workflow', '/competitor-workflow' to '/workflow'. Apply this guideline to files under autogpt_platform/backend and autogpt_platform/frontend.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-31T15:37:38.626Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/tools/agent_generator/fixer.py:37-47
Timestamp: 2026-03-31T15:37:38.626Z
Learning: When validating/constructing Anthropic API model IDs in Significant-Gravitas/AutoGPT, allow the hyphen-separated Claude Opus 4.6 model ID `claude-opus-4-6` (it corresponds to `LlmModel.CLAUDE_4_6_OPUS` in `autogpt_platform/backend/backend/blocks/llm.py`). Do NOT require the dot-separated form in Anthropic contexts. Only OpenRouter routing variants should use the dot separator (e.g., `anthropic/claude-opus-4.6`); `claude-opus-4-6` should be treated as correct when passed to Anthropic, and flagged only if it’s used in the OpenRouter path where the dot form is expected.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-22T11:46:04.431Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/config.py:0-0
Timestamp: 2026-04-22T11:46:04.431Z
Learning: Do not flag the Claude Sonnet 4.6 model ID as incorrect when it uses the project’s established hyphenated convention: `anthropic/claude-sonnet-4-6`. This hyphen form is the intentional, production convention and should be treated as valid (including in files like llm.py, blocks tests, reasoning.py, `_is_anthropic_model` tests, and config defaults). Note that OpenRouter also accepts the dot variant `anthropic/claude-sonnet-4.6`, so either form may be tolerated, but `anthropic/claude-sonnet-4-6` should be considered the standard to match project usage.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-22T11:46:12.892Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/baseline/service.py:322-332
Timestamp: 2026-04-22T11:46:12.892Z
Learning: In this codebase (Significant-Gravitas/AutoGPT), OpenRouter-routed Anthropic model IDs should use the hyphen-separated convention (e.g., `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-6`). Although OpenRouter may accept both hyphen and dot variants, treat the hyphen-separated form as the intended, correct codebase-wide convention and do not flag it as an error. Only flag the dot-separated variant (e.g., `anthropic/claude-sonnet-4.6`) as incorrect when reviewing/validating model ID strings for OpenRouter-routed Anthropic models.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service_test.py
  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/api/features/**/*.py : Update routes in '/backend/backend/api/features/' and add/update Pydantic models in the same directory for API development

Applied to files:

  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-13T14:19:19.341Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.

Applied to files:

  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-04-22T05:58:28.595Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12879
File: autogpt_platform/frontend/src/app/api/openapi.json:14576-14577
Timestamp: 2026-04-22T05:58:28.595Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Process convention: When adding new CoPilot tool response models and updating ToolResponseUnion in backend/api/features/chat/routes.py, regenerate the frontend OpenAPI schema via `poetry run export-api-schema` (do not hand-edit autogpt_platform/frontend/src/app/api/openapi.json).

Applied to files:

  • autogpt_platform/backend/backend/util/feature_flag.py
  • autogpt_platform/backend/backend/copilot/config.py
  • autogpt_platform/backend/backend/copilot/model_router.py
  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-04T23:57:59.510Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:5593-5593
Timestamp: 2026-03-04T23:57:59.510Z
Learning: In Significant-Gravitas/AutoGPT backend (FastAPI), openapi.json is autogenerated: descriptions come from route docstrings and schemas from response_model/type annotations. To prevent drift when models are renamed (e.g., AdminView variants), avoid embedding specific schema class names in route docstrings; instead describe behavior, or keep names synced via backend edits—never hand-edit frontend/src/app/api/openapi.json.

Applied to files:

  • autogpt_platform/backend/backend/copilot/sdk/service.py
  • autogpt_platform/backend/backend/copilot/config.py
📚 Learning: 2026-03-04T23:58:18.476Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.

Applied to files:

  • autogpt_platform/backend/backend/copilot/config.py
📚 Learning: 2026-04-08T17:27:07.646Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: classic/forge/CLAUDE.md:0-0
Timestamp: 2026-04-08T17:27:07.646Z
Learning: Applies to classic/forge/**/forge/llm/providers/**/*.py : Supported model names include OpenAI (GPT3, GPT3_16k, GPT4, GPT4_32k, GPT4_TURBO, GPT4_O), Anthropic (CLAUDE3_OPUS, CLAUDE3_SONNET, CLAUDE3_HAIKU, CLAUDE3_5_SONNET, CLAUDE3_5_SONNET_v2, CLAUDE3_5_HAIKU, CLAUDE4_SONNET, CLAUDE4_OPUS, CLAUDE4_5_OPUS), and Groq (LLAMA3_8B, LLAMA3_70B, MIXTRAL_8X7B)

Applied to files:

  • autogpt_platform/backend/backend/copilot/config.py
📚 Learning: 2026-03-31T14:05:48.405Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/frontend/src/app/api/openapi.json:12934-12940
Timestamp: 2026-03-31T14:05:48.405Z
Learning: AutoGPT OpenAPI/codegen convention: To restrict allowed string values, define the Pydantic field with typing.Literal so the auto-generated openapi.json emits an enum and FastAPI returns 422 for invalid inputs. Example: in backend/api/features/chat/routes.py, StreamChatRequest.mode uses Literal['fast','extended_thinking'] | None; the generated frontend openapi.json now shows enum ["fast","extended_thinking"] with null allowed.

Applied to files:

  • autogpt_platform/backend/backend/copilot/config.py
📚 Learning: 2026-04-23T00:07:27.117Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-23T00:07:27.117Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/openrouter_cost.py`, the `openrouter-cost-reconcile` Langfuse event carries `cost_source` ("openrouter" for authoritative OpenRouter-resolved cost, "fallback" for rate-card fallback) and `resolved_generation_id_count` alongside the reconciled cost and token/model/provider metadata. This lets operators distinguish authoritative reconciliations from fallbacks in Langfuse. Established in PR `#12889` commit 5ce3d0388.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-03T11:14:16.378Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/transcript_builder.py:30-34
Timestamp: 2026-04-03T11:14:16.378Z
Learning: In `autogpt_platform/backend/backend/copilot/transcript_builder.py` (and its re-export shim at `sdk/transcript_builder.py`), `TranscriptEntry.parentUuid` is typed `str` (not `str | None`) and root entries use `parentUuid=""` (empty string) to match the canonical `_messages_to_transcript` JSONL format. `_parse_entry`, `append_user`, and `append_assistant` all coerce `None` to `""`. Do NOT flag `parentUuid=""` as incorrect — it is the correct root marker. This was fixed in PR `#12623`, commit b753cb7d0b.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router_test.py
📚 Learning: 2026-03-09T10:50:43.907Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-03-09T10:50:43.907Z
Learning: Repo: Significant-Gravitas/AutoGPT — File: autogpt_platform/backend/backend/blocks/llm.py
For xAI Grok models accessed via OpenRouter, the API returns `null` for `max_completion_tokens`. The convention in this codebase is to use the model's context window size as the `max_output_tokens` value in ModelMetadata. For example, Grok 3 uses 131072 (128k) and Grok 4 uses 262144 (256k). Do not flag these as incorrect max output token values.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router_test.py
🔇 Additional comments (6)
autogpt_platform/backend/backend/copilot/config.py (1)

51-53: LD routing docs look correct after flag consolidation.

Line 52, Line 59, Line 68, and Line 77 now correctly reference copilot-model-routing[mode][tier], matching the new single-JSON-flag model routing contract.

Also applies to: 58-60, 67-69, 76-78

autogpt_platform/backend/backend/copilot/sdk/service_test.py (1)

616-620: Test docstring rename is accurate.

Line 617-Line 620 correctly reflects the consolidated LD key path (copilot-model-routing[thinking][standard]) with no test behavior changes.

autogpt_platform/backend/backend/copilot/sdk/service.py (1)

795-799: Inline routing docs are consistent with the new JSON flag.

Line 797-Line 798, Line 834-Line 838, and Line 868-Line 869 all correctly describe the copilot-model-routing[thinking][tier] lookup semantics and subscription interaction.

Also applies to: 830-839, 863-870

autogpt_platform/backend/backend/copilot/model_router.py (1)

68-127: Good consolidation to a single LD lookup with safe per-cell fallback.

The resolver keeps behavior stable (user-targeted lookup + tier-specific fallback) while removing per-cell flag fan-out cleanly.

autogpt_platform/backend/backend/copilot/model_router_test.py (1)

84-317: Strong regression coverage for the JSON routing migration.

These cases cover the important failure modes (shape validation, whitespace handling, LD exceptions, and single-call guard) and match the new resolver contract well.

autogpt_platform/backend/backend/util/feature_flag.py (1)

50-60: Legacy routing references successfully removed.

No remaining references to removed Flag.COPILOT_*_*_MODEL enum members or old LaunchDarkly keys (copilot-{fast,thinking}-{standard,advanced}-model) found in the codebase. The consolidation to Flag.COPILOT_MODEL_ROUTING is complete.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.24%. Comparing base (2deac20) to head (dd6e19d).
⚠️ Report is 1 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #12917      +/-   ##
==========================================
+ Coverage   68.23%   68.24%   +0.01%     
==========================================
  Files        1960     1960              
  Lines      150178   150234      +56     
  Branches    15621    15626       +5     
==========================================
+ Hits       102473   102534      +61     
+ Misses      44664    44660       -4     
+ Partials     3041     3040       -1     
Flag Coverage Δ
platform-backend 77.89% <100.00%> (+0.01%) ⬆️
platform-frontend-e2e 29.60% <ø> (-0.19%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Platform Backend 77.89% <100.00%> (+0.01%) ⬆️
Platform Frontend 32.60% <ø> (-0.02%) ⬇️
AutoGPT Libs ∅ <ø> (∅)
Classic AutoGPT 28.43% <ø> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread autogpt_platform/backend/backend/copilot/model_router.py
Comment thread autogpt_platform/backend/backend/copilot/model_router.py
- Mirror the top-level non-dict warning down to the per-mode level: if the
  operator types a string at copilot-model-routing[<mode>] instead of a
  {tier: model} dict, log a warning so the typo surfaces in operator-facing
  logs instead of silently dropping to ChatConfig defaults.
- Annotate `payload: object` to make the dynamic-typed return value explicit
  for readers who land mid-function.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
autogpt_platform/backend/backend/copilot/model_router.py (1)

106-119: Optional: collapse the two mode_cell checks into one block.

The warning predicate (mode in payload and not isinstance(mode_cell, dict)) and the early-return predicate (not isinstance(mode_cell, dict)) overlap — when the warning fires, the return also fires. Folding them avoids the second isinstance and makes the "warn-then-return" intent explicit:

♻️ Proposed simplification
     mode_cell = payload.get(mode)
-    if mode in payload and not isinstance(mode_cell, dict):
-        # Operator typed something at the mode level (e.g. a string) instead of
-        # a {tier: model} dict — surface the typo in logs.
-        logger.warning(
-            "[model_router] copilot-model-routing[%s] expected a JSON object, "
-            "got %r — using config default %s for tier %s",
-            mode,
-            mode_cell,
-            fallback,
-            tier,
-        )
     if not isinstance(mode_cell, dict):
+        if mode in payload:
+            # Operator typed something at the mode level (e.g. a string)
+            # instead of a {tier: model} dict — surface the typo in logs.
+            logger.warning(
+                "[model_router] copilot-model-routing[%s] expected a JSON "
+                "object, got %r — using config default %s for tier %s",
+                mode,
+                mode_cell,
+                fallback,
+                tier,
+            )
         return fallback

Behavior is equivalent; purely a readability nit — feel free to skip.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@autogpt_platform/backend/backend/copilot/model_router.py` around lines 106 -
119, Condense the duplicated type checks by replacing the separate warning and
early-return with a single conditional around the existing mode_cell usage:
after retrieving mode_cell = payload.get(mode) in model_router (the block that
currently checks mode in payload and not isinstance(mode_cell, dict) then later
checks not isinstance(mode_cell, dict)), use one if not isinstance(mode_cell,
dict): inside it, if mode in payload: emit the existing logger.warning(...) with
the same arguments (mode, mode_cell, fallback, tier), then return fallback; this
preserves behavior while avoiding the repeated isinstance check and makes the
warn-then-return intent explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@autogpt_platform/backend/backend/copilot/model_router.py`:
- Around line 106-119: Condense the duplicated type checks by replacing the
separate warning and early-return with a single conditional around the existing
mode_cell usage: after retrieving mode_cell = payload.get(mode) in model_router
(the block that currently checks mode in payload and not isinstance(mode_cell,
dict) then later checks not isinstance(mode_cell, dict)), use one if not
isinstance(mode_cell, dict): inside it, if mode in payload: emit the existing
logger.warning(...) with the same arguments (mode, mode_cell, fallback, tier),
then return fallback; this preserves behavior while avoiding the repeated
isinstance check and makes the warn-then-return intent explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e89ea45-0dee-4c1b-86f4-21911f95bc5a

📥 Commits

Reviewing files that changed from the base of the PR and between cefce3b and dd6e19d.

📒 Files selected for processing (1)
  • autogpt_platform/backend/backend/copilot/model_router.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: check API types
  • GitHub Check: end-to-end tests
  • GitHub Check: type-check (3.11)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.13)
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (typescript)
🧰 Additional context used
📓 Path-based instructions (2)
autogpt_platform/backend/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development

autogpt_platform/backend/**/*.py: Use poetry run ... command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies like openpyxl
Use absolute imports with from backend.module import ... for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoid hasattr/getattr/isinstance for type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no # type: ignore, # noqa, # pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use %s for deferred interpolation in debug log statements for efficiency; use f-strings elsewhere for readability (e.g., logger.debug("Processing %s items", count) vs logger.info(f"Processing {count} items"))
Sanitize error paths by using os.path.basename() in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Use transaction=True for Redis pipelines to ensure atomicity on multi-step operations
Use max(0, value) guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...

Files:

  • autogpt_platform/backend/backend/copilot/model_router.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/copilot/model_router.py
🧠 Learnings (20)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/sdk/service.py:0-0
Timestamp: 2026-04-22T12:26:42.571Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py`, `_resolve_sdk_model_for_request`: when a per-user LaunchDarkly model value fails `_normalize_model_name` (e.g. a `moonshotai/kimi-*` slug in direct-Anthropic mode), the fallback must be tier-specific — `config.thinking_advanced_model` for advanced tier, `config.thinking_standard_model` for standard tier — NOT the generic `_resolve_sdk_model()` (which is standard-only and returns None under subscription mode). If the tier-specific config default also fails `_normalize_model_name`, re-raise the original LD error; this is a deployment-level misconfiguration that `model_validator` should have caught at startup. Established in PR `#12881` commit 637d2fef5.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12879
File: autogpt_platform/frontend/src/app/api/openapi.json:14576-14577
Timestamp: 2026-04-22T05:58:28.595Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Process convention: When adding new CoPilot tool response models and updating ToolResponseUnion in backend/api/features/chat/routes.py, regenerate the frontend OpenAPI schema via `poetry run export-api-schema` (do not hand-edit autogpt_platform/frontend/src/app/api/openapi.json).
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12536
File: autogpt_platform/frontend/src/app/api/openapi.json:5770-5790
Timestamp: 2026-03-24T21:25:15.983Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12536`
File: autogpt_platform/frontend/src/app/api/openapi.json
Learning: The OpenAPI spec file is auto-generated; per established convention, endpoints generally declare only 200/201, 401, and 422 responses. Do not suggest adding explicit 403/404 response entries for single operations unless planning a repo-wide spec update. Prefer clarifying such behaviors in endpoint descriptions/docstrings instead of altering response maps.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12622
File: autogpt_platform/backend/backend/copilot/tools/agent_search.py:223-236
Timestamp: 2026-03-31T14:22:29.127Z
Learning: When reviewing code under autogpt_platform/backend/backend/copilot/tools/, the `AgentInfo.graph` field (in agent_search.py / models.py) uses `Graph | None` (the typed `backend.data.graph.Graph` Pydantic model), NOT `dict[str, Any]`. The enrichment function `_enrich_agents_with_graph` calls `graph_db().get_graph(graph_id, version=None, user_id=user_id)` directly rather than going through `get_agent_as_json()` / `graph_to_json()`. This was updated in PR `#12622` (commit 22d05bc).
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12536
File: autogpt_platform/frontend/src/app/api/openapi.json:5732-5752
Timestamp: 2026-03-24T21:27:22.326Z
Learning: Repo: Significant-Gravitas/AutoGPT — Preference: Do not add explicit 403/404 entries to FastAPI route decorators for admin endpoints just to influence OpenAPI. Keep openapi.json autogenerated and use route docstrings to document admin-only (403) and not-found (404) behavior; rely on tests for enforcement. File context: autogpt_platform/backend/backend/api/features/admin/store_admin_routes.py. PR `#12536`.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:25.545Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.
📚 Learning: 2026-04-22T12:26:42.571Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/sdk/service.py:0-0
Timestamp: 2026-04-22T12:26:42.571Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py`, `_resolve_sdk_model_for_request`: when a per-user LaunchDarkly model value fails `_normalize_model_name` (e.g. a `moonshotai/kimi-*` slug in direct-Anthropic mode), the fallback must be tier-specific — `config.thinking_advanced_model` for advanced tier, `config.thinking_standard_model` for standard tier — NOT the generic `_resolve_sdk_model()` (which is standard-only and returns None under subscription mode). If the tier-specific config default also fails `_normalize_model_name`, re-raise the original LD error; this is a deployment-level misconfiguration that `model_validator` should have caught at startup. Established in PR `#12881` commit 637d2fef5.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-17T10:57:12.953Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-23T00:07:27.117Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-23T00:07:27.117Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/openrouter_cost.py`, the `openrouter-cost-reconcile` Langfuse event carries `cost_source` ("openrouter" for authoritative OpenRouter-resolved cost, "fallback" for rate-card fallback) and `resolved_generation_id_count` alongside the reconciled cost and token/model/provider metadata. This lets operators distinguish authoritative reconciliations from fallbacks in Langfuse. Established in PR `#12889` commit 5ce3d0388.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-31T14:22:29.127Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12622
File: autogpt_platform/backend/backend/copilot/tools/agent_search.py:223-236
Timestamp: 2026-03-31T14:22:29.127Z
Learning: When reviewing code under autogpt_platform/backend/backend/copilot/tools/, the `AgentInfo.graph` field (in agent_search.py / models.py) uses `Graph | None` (the typed `backend.data.graph.Graph` Pydantic model), NOT `dict[str, Any]`. The enrichment function `_enrich_agents_with_graph` calls `graph_db().get_graph(graph_id, version=None, user_id=user_id)` directly rather than going through `get_agent_as_json()` / `graph_to_json()`. This was updated in PR `#12622` (commit 22d05bc).

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-31T15:37:38.626Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/tools/agent_generator/fixer.py:37-47
Timestamp: 2026-03-31T15:37:38.626Z
Learning: When validating/constructing Anthropic API model IDs in Significant-Gravitas/AutoGPT, allow the hyphen-separated Claude Opus 4.6 model ID `claude-opus-4-6` (it corresponds to `LlmModel.CLAUDE_4_6_OPUS` in `autogpt_platform/backend/backend/blocks/llm.py`). Do NOT require the dot-separated form in Anthropic contexts. Only OpenRouter routing variants should use the dot separator (e.g., `anthropic/claude-opus-4.6`); `claude-opus-4-6` should be treated as correct when passed to Anthropic, and flagged only if it’s used in the OpenRouter path where the dot form is expected.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-02T13:16:03.050Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12649
File: .gitleaks.toml:34-35
Timestamp: 2026-04-02T13:16:03.050Z
Learning: In Significant-Gravitas/AutoGPT, the `.gitleaks.toml` allowlist regex `Llama-\d.*Instruct` is intentionally narrow. Only `Llama-X-...-Instruct-FP8` style model name enum values in `autogpt_platform/backend/backend/blocks/llm.py` actually trigger gitleaks' `generic-api-key` rule due to high entropy in the FP8-quantization suffix. Lowercase variants (e.g., `llama-3.3-70b-versatile`) and Mistral model names do not reach gitleaks' entropy/pattern thresholds, so broadening the pattern is unnecessary. Do not flag this allowlist as too narrow.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-09T10:50:43.907Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-03-09T10:50:43.907Z
Learning: Repo: Significant-Gravitas/AutoGPT — File: autogpt_platform/backend/backend/blocks/llm.py
For xAI Grok models accessed via OpenRouter, the API returns `null` for `max_completion_tokens`. The convention in this codebase is to use the model's context window size as the `max_output_tokens` value in ModelMetadata. For example, Grok 3 uses 131072 (128k) and Grok 4 uses 262144 (256k). Do not flag these as incorrect max output token values.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-24T21:27:22.326Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12536
File: autogpt_platform/frontend/src/app/api/openapi.json:5732-5752
Timestamp: 2026-03-24T21:27:22.326Z
Learning: Repo: Significant-Gravitas/AutoGPT — Preference: Do not add explicit 403/404 entries to FastAPI route decorators for admin endpoints just to influence OpenAPI. Keep openapi.json autogenerated and use route docstrings to document admin-only (403) and not-found (404) behavior; rely on tests for enforcement. File context: autogpt_platform/backend/backend/api/features/admin/store_admin_routes.py. PR `#12536`.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-17T06:48:26.471Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-24T21:25:15.983Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12536
File: autogpt_platform/frontend/src/app/api/openapi.json:5770-5790
Timestamp: 2026-03-24T21:25:15.983Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12536`
File: autogpt_platform/frontend/src/app/api/openapi.json
Learning: The OpenAPI spec file is auto-generated; per established convention, endpoints generally declare only 200/201, 401, and 422 responses. Do not suggest adding explicit 403/404 response entries for single operations unless planning a repo-wide spec update. Prefer clarifying such behaviors in endpoint descriptions/docstrings instead of altering response maps.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-22T05:58:28.595Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12879
File: autogpt_platform/frontend/src/app/api/openapi.json:14576-14577
Timestamp: 2026-04-22T05:58:28.595Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Process convention: When adding new CoPilot tool response models and updating ToolResponseUnion in backend/api/features/chat/routes.py, regenerate the frontend OpenAPI schema via `poetry run export-api-schema` (do not hand-edit autogpt_platform/frontend/src/app/api/openapi.json).

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-02-26T17:02:22.448Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12211
File: .pre-commit-config.yaml:160-179
Timestamp: 2026-02-26T17:02:22.448Z
Learning: Keep the pre-commit hook pattern broad for autogpt_platform/backend to ensure OpenAPI schema changes are captured. Do not narrow to backend/api/ alone, since the generated schema depends on Pydantic models across multiple directories (backend/data/, backend/blocks/, backend/copilot/, backend/integrations/, backend/util/). Narrowing could miss schema changes and cause frontend type desynchronization.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-04T08:04:35.881Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12273
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:216-220
Timestamp: 2026-03-04T08:04:35.881Z
Learning: In the AutoGPT Copilot backend, ensure that SVG images are not treated as vision image types by excluding 'image/svg+xml' from INLINEABLE_MIME_TYPES and MULTIMODAL_TYPES in tool_adapter.py; the Claude API supports PNG, JPEG, GIF, and WebP for vision. SVGs (XML text) should be handled via the text path instead, not the vision path.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-01T04:17:41.600Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:41.600Z
Learning: When reviewing AutoGPT Copilot tool implementations, accept that `readOnlyHint=True` (provided via `ToolAnnotations`) may be applied unconditionally to *all* tools—even tools that have side effects (e.g., `bash_exec`, `write_workspace_file`, or other write/save operations). Do **not** flag these tools for having `readOnlyHint=True`; this is intentional to enable fully-parallel dispatch by the Anthropic SDK/CLI and has been E2E validated. Only flag `readOnlyHint` issues if they conflict with the established `ToolAnnotations` behavior (e.g., missing/incorrect propagation relative to the intended annotation mechanism).

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-05T15:42:08.207Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12297
File: .claude/skills/backend-check/SKILL.md:14-16
Timestamp: 2026-03-05T15:42:08.207Z
Learning: In Python files under autogpt_platform/backend (recursively), rely on poetry run format to perform formatting (Black + isort) and linting (ruff). Do not run poetry run lint as a separate step after poetry run format, since format already includes linting checks.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-03-16T16:35:40.236Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/api/features/workflow_import.py:54-63
Timestamp: 2026-03-16T16:35:40.236Z
Learning: Avoid using the word 'competitor' in public-facing identifiers and text. Use neutral naming for API paths, model names, function names, and UI text. Examples: rename 'CompetitorFormat' to 'SourcePlatform', 'convert_competitor_workflow' to 'convert_workflow', '/competitor-workflow' to '/workflow'. Apply this guideline to files under autogpt_platform/backend and autogpt_platform/frontend.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-22T11:46:04.431Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/config.py:0-0
Timestamp: 2026-04-22T11:46:04.431Z
Learning: Do not flag the Claude Sonnet 4.6 model ID as incorrect when it uses the project’s established hyphenated convention: `anthropic/claude-sonnet-4-6`. This hyphen form is the intentional, production convention and should be treated as valid (including in files like llm.py, blocks tests, reasoning.py, `_is_anthropic_model` tests, and config defaults). Note that OpenRouter also accepts the dot variant `anthropic/claude-sonnet-4.6`, so either form may be tolerated, but `anthropic/claude-sonnet-4-6` should be considered the standard to match project usage.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
📚 Learning: 2026-04-22T11:46:12.892Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/baseline/service.py:322-332
Timestamp: 2026-04-22T11:46:12.892Z
Learning: In this codebase (Significant-Gravitas/AutoGPT), OpenRouter-routed Anthropic model IDs should use the hyphen-separated convention (e.g., `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-6`). Although OpenRouter may accept both hyphen and dot variants, treat the hyphen-separated form as the intended, correct codebase-wide convention and do not flag it as an error. Only flag the dot-separated variant (e.g., `anthropic/claude-sonnet-4.6`) as incorrect when reviewing/validating model ID strings for OpenRouter-routed Anthropic models.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model_router.py
🔇 Additional comments (1)
autogpt_platform/backend/backend/copilot/model_router.py (1)

59-138: LGTM — clean consolidation with sensible fallback hierarchy.

The validation ladder is well-structured:

  • Missing user / LD failure → silent fallback (LD failure logs warning).
  • Payload None → silent fallback (legitimate "not configured" state).
  • Payload non-dict / mode cell non-dict / tier value non-string-or-empty → warning + fallback (operator misconfiguration).

The asymmetry between silent-on-missing and loud-on-malformed correctly distinguishes "flag not set" from "flag set incorrectly", which is exactly what an operator wants from logs. Per-user LD targeting is preserved, and trimming the config default at line 73 keeps the comparison/return surface consistent with the trimmed payload values at line 123.

@majdyz majdyz merged commit 06188a8 into dev Apr 25, 2026
40 checks passed
@majdyz majdyz deleted the feat/consolidate-copilot-model-routing-flag branch April 25, 2026 01:15
@github-project-automation github-project-automation Bot moved this from 🆕 Needs initial review to ✅ Done in AutoGPT development kanban Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform/backend AutoGPT Platform - Back end size/l

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

1 participant