Skip to main content

Overview

This project uses two model tiers:
  • PRIMARY_MODEL for heavyweight generation paths
  • SECONDARY_MODEL for lightweight or high-volume paths
Both env vars use provider:model format (for example anthropic:claude-opus-4-5 or openai:gpt-5-mini).

Where each tier is used

PRIMARY_MODEL

AreaCode pathNotes
Agent main chat loopsrc/agents/agent.tsUsed when no agent-specific llm_model override is set
Module overview docssrc/services/doc-generator.tsgenerateModuleDocs
Business process docssrc/services/doc-generator.tsgenerateBusinessProcessDocs
Clean Core analysis narrativessrc/services/clean-core-analyzer.tsPersists model_used
Conversion readiness narrativessrc/services/conversion-readiness-analyzer.tsPersists model_used

SECONDARY_MODEL

AreaCode pathNotes
Agent title generationsrc/agents/agent.tsFirst-turn title synthesis
Technical docs generationsrc/services/doc-generator.tsgenerateTechnicalDocs
Business process inferencesrc/services/business-process-inferrer.tsInference pass used by enrichment

Defaults

Defaults are defined in src/lib/model-selection.ts:
  • PRIMARY_MODEL default: anthropic:claude-opus-4-5
  • SECONDARY_MODEL default: anthropic:claude-haiku-4-5
If an env var is not set, runtime falls back to these defaults.

What happens with incorrect values

1) Invalid model string format or unsupported provider

If PRIMARY_MODEL/SECONDARY_MODEL is set to an invalid string, selection code falls back to the default tier model instead of crashing. Examples:
  • PRIMARY_MODEL=not-a-model -> falls back to anthropic:claude-opus-4-5
  • SECONDARY_MODEL=foo:bar -> falls back to anthropic:claude-haiku-4-5

2) Valid format, but provider rejects model id

If the value is parseable (for example openai:gpt-5-2) but the provider does not recognize it, runtime fails at provider call time (for example model-not-found errors).

3) Invalid per-agent override sent to API

Agent-level llmModel override values are validated in routes. Invalid values are rejected with 400.

Agent override behavior

For the main chat loop:
  • If agents.llm_model is set, it overrides PRIMARY_MODEL
  • If agents.llm_model is null, runtime uses PRIMARY_MODEL
llm_provider is treated as derived metadata and is not used as a standalone selector.

Hardcoded model values (not tier-controlled)

These values are currently hardcoded and not controlled by PRIMARY_MODEL/SECONDARY_MODEL:
  • Embeddings: text-embedding-3-small
    • src/services/embedding-service.ts
    • src/data/embed-knowledge.ts
The old legacy fallback that inferred openai:gpt-5-mini from provider-only rows was removed. If llm_model is null, no OpenAI model is inferred.
# Balanced default
PRIMARY_MODEL=anthropic:claude-opus-4-5
SECONDARY_MODEL=anthropic:claude-haiku-4-5

# OpenAI-primary example
PRIMARY_MODEL=openai:gpt-5.2-pro
SECONDARY_MODEL=anthropic:claude-haiku-4-5