atlas-iac/services/hermes/switchyard-configmap.yaml

465 lines
19 KiB
YAML

# services/hermes/switchyard-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: hermes-switchyard
namespace: hermes
labels:
app: hermes-switchyard
data:
routes.toml: |
schema_version = 1
[llm_clients.classifier]
format = "openai_chat"
base_url = "http://ollama.ai.svc.cluster.local:11434/v1"
max_retries = 1
[llm_clients.local_low]
format = "openai_chat"
base_url = "http://hermes-model-gate.hermes.svc.cluster.local:11434/v1"
max_retries = 1
[llm_clients.local_medium]
format = "openai_chat"
base_url = "http://hermes-model-gate.hermes.svc.cluster.local:11434/v1"
max_retries = 1
[llm_clients.codex_low]
format = "openai_responses"
base_url = "http://hermes-codex-broker.hermes.svc.cluster.local:9003/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.codex_medium]
format = "openai_responses"
base_url = "http://hermes-codex-broker.hermes.svc.cluster.local:9003/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.codex_high]
format = "openai_responses"
base_url = "http://hermes-codex-broker.hermes.svc.cluster.local:9003/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.codex_xhigh]
format = "openai_responses"
base_url = "http://hermes-codex-broker.hermes.svc.cluster.local:9003/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.claude_low]
format = "anthropic_messages"
base_url = "http://127.0.0.1:9006/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.claude_medium]
format = "anthropic_messages"
base_url = "http://127.0.0.1:9006/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.claude_high]
format = "anthropic_messages"
base_url = "http://127.0.0.1:9006/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.claude_xhigh]
format = "anthropic_messages"
base_url = "http://127.0.0.1:9006/v1"
api_key_env = "ATLAS_BROKER_KEY"
max_retries = 1
[llm_clients.worker_decision]
format = "openai_chat"
base_url = "http://127.0.0.1:9007/v1"
max_retries = 0
[targets.classifier]
id = "qwen2.5:3b-instruct-q4_0"
llm_client = "classifier"
[targets.local_qwen_low]
id = "route/local/qwen2.5-14b/low"
llm_client = "local_low"
extra_body = { reasoning_effort = "low" }
[targets.local_qwen_medium]
id = "route/local/qwen2.5-14b/medium"
llm_client = "local_medium"
extra_body = { reasoning_effort = "medium" }
[targets.codex_luna_low]
id = "route/codex/luna/low"
llm_client = "codex_low"
extra_body = { reasoning = { effort = "low" } }
[targets.codex_terra_low]
id = "route/codex/terra/low"
llm_client = "codex_low"
extra_body = { reasoning = { effort = "low" } }
[targets.codex_terra_medium]
id = "route/codex/terra/medium"
llm_client = "codex_medium"
extra_body = { reasoning = { effort = "medium" } }
[targets.codex_terra_high]
id = "route/codex/terra/high"
llm_client = "codex_high"
extra_body = { reasoning = { effort = "high" } }
[targets.codex_sol_medium]
id = "route/codex/sol/medium"
llm_client = "codex_medium"
extra_body = { reasoning = { effort = "medium" } }
[targets.codex_sol_high]
id = "route/codex/sol/high"
llm_client = "codex_high"
extra_body = { reasoning = { effort = "high" } }
[targets.codex_sol_xhigh]
id = "route/codex/sol/xhigh"
llm_client = "codex_xhigh"
extra_body = { reasoning = { effort = "xhigh" } }
[targets.claude_haiku_low]
id = "route/claude/haiku/low"
llm_client = "claude_low"
extra_body = { thinking = { type = "adaptive" }, output_config = { effort = "low" } }
[targets.claude_sonnet_medium]
id = "route/claude/sonnet/medium"
llm_client = "claude_medium"
extra_body = { thinking = { type = "adaptive" }, output_config = { effort = "medium" } }
[targets.claude_sonnet_high]
id = "route/claude/sonnet/high"
llm_client = "claude_high"
extra_body = { thinking = { type = "adaptive" }, output_config = { effort = "high" } }
[targets.claude_opus_high]
id = "route/claude/opus/high"
llm_client = "claude_high"
extra_body = { thinking = { type = "adaptive" }, output_config = { effort = "high" } }
[targets.claude_opus_xhigh]
id = "route/claude/opus/xhigh"
llm_client = "claude_xhigh"
extra_body = { thinking = { type = "adaptive" }, output_config = { effort = "xhigh" } }
[targets.worker_codex_luna_low]
id = "worker/codex/luna/low"
llm_client = "worker_decision"
[targets.worker_codex_terra_medium]
id = "worker/codex/terra/medium"
llm_client = "worker_decision"
[targets.worker_codex_sol_high]
id = "worker/codex/sol/high"
llm_client = "worker_decision"
[targets.worker_codex_sol_xhigh]
id = "worker/codex/sol/xhigh"
llm_client = "worker_decision"
[targets.worker_claude_haiku_low]
id = "worker/claude/haiku/low"
llm_client = "worker_decision"
[targets.worker_claude_sonnet_medium]
id = "worker/claude/sonnet/medium"
llm_client = "worker_decision"
[targets.worker_claude_sonnet_high]
id = "worker/claude/sonnet/high"
llm_client = "worker_decision"
[targets.worker_claude_opus_xhigh]
id = "worker/claude/opus/xhigh"
llm_client = "worker_decision"
[routes.auto_fast]
id = "atlas/auto/fast"
type = "llm_classifier"
mode = "custom"
classifier_target = "classifier"
targets = ["codex_terra_medium", "claude_sonnet_medium", "codex_luna_low", "claude_haiku_low", "local_qwen_low", "local_qwen_medium", "codex_terra_low", "codex_terra_high", "codex_sol_medium", "codex_sol_high", "codex_sol_xhigh", "claude_sonnet_high", "claude_opus_high", "claude_opus_xhigh"]
default_target = "codex_terra_medium"
max_output_tokens = 96
session_affinity = false
recent_turn_window = 8
context_window = 272000
tool_calling = true
reasoning = true
prompt = """
You are the routing authority for a private family assistant. Choose exactly
one configured target for this model-call boundary. Mildly favor fast and
economical answers, but never trade away correctness for difficult,
ambiguous, safety-sensitive, tool-heavy, or consequential work. Use local
Qwen only for simple low-risk conversation, formatting, or continuity.
Prefer Codex for implementation, debugging, tests, and direct repository
work. Prefer Claude for architecture, ambiguity, long-context synthesis,
risk analysis, and independent review. Interpret requests such as "answer
quickly", "think hard", or "use Claude" semantically. An explicit user
provider, model, or depth instruction wins unless it would undercut a clear
safety floor. Every request is a fresh boundary; classify the actual current
objective and recent context, including referential instructions like
"continue" or "do it". Never select effort above xhigh.
"""
response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["codex_terra_medium","claude_sonnet_medium","codex_luna_low","claude_haiku_low","local_qwen_low","local_qwen_medium","codex_terra_low","codex_terra_high","codex_sol_medium","codex_sol_high","codex_sol_xhigh","claude_sonnet_high","claude_opus_high","claude_opus_xhigh"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
'''
[routes.auto_fast.policy]
type = "target_selector"
selector = "/decision/target"
[routes.auto_balanced]
id = "atlas/auto/balanced"
type = "llm_classifier"
mode = "custom"
classifier_target = "classifier"
targets = ["codex_terra_medium", "claude_sonnet_medium", "codex_luna_low", "claude_haiku_low", "local_qwen_low", "local_qwen_medium", "codex_terra_low", "codex_terra_high", "codex_sol_medium", "codex_sol_high", "codex_sol_xhigh", "claude_sonnet_high", "claude_opus_high", "claude_opus_xhigh"]
default_target = "codex_terra_medium"
max_output_tokens = 96
session_affinity = false
recent_turn_window = 8
context_window = 272000
tool_calling = true
reasoning = true
prompt = """
You are the routing authority for a private general assistant. Choose
exactly one configured target for this model-call boundary. Balance latency,
cost, and intelligence while giving difficult, uncertain, tool-heavy, or
consequential work enough capability. Use local Qwen only for simple
low-risk conversation, formatting, or continuity. Prefer Codex for
implementation, debugging, tests, and direct repository work. Prefer Claude
for architecture, ambiguity, long-context synthesis, risk analysis, and
independent review. Interpret speed/depth and provider requests
semantically; explicit user intent wins unless it undercuts a clear safety
floor. Classify the actual current objective and recent context, including
referential instructions such as "continue" or "do it". Never select effort
above xhigh.
"""
response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["codex_terra_medium","claude_sonnet_medium","codex_luna_low","claude_haiku_low","local_qwen_low","local_qwen_medium","codex_terra_low","codex_terra_high","codex_sol_medium","codex_sol_high","codex_sol_xhigh","claude_sonnet_high","claude_opus_high","claude_opus_xhigh"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
'''
[routes.auto_balanced.policy]
type = "target_selector"
selector = "/decision/target"
[routes.auto_deep]
id = "atlas/auto/deep"
type = "llm_classifier"
mode = "custom"
classifier_target = "classifier"
targets = ["claude_sonnet_high", "codex_sol_high", "codex_terra_medium", "claude_sonnet_medium", "codex_terra_high", "codex_sol_medium", "claude_opus_high", "codex_sol_xhigh", "claude_opus_xhigh", "codex_luna_low", "claude_haiku_low", "local_qwen_medium", "local_qwen_low", "codex_terra_low"]
default_target = "claude_sonnet_high"
max_output_tokens = 96
session_affinity = false
recent_turn_window = 12
context_window = 272000
tool_calling = true
reasoning = true
prompt = """
You are the routing authority for operations triage. Choose exactly one
configured target for this model-call boundary. Favor evidence, diagnosis,
uncertainty handling, and correctness over marginal latency savings. Cheap
routes are appropriate only for genuinely mechanical low-risk steps. Prefer
Codex for implementation, debugging, tests, and repository work; prefer
Claude for diagnosis, architecture, ambiguity, synthesis, risk analysis,
and independent review. Interpret requests for speed, depth, or a provider
semantically. Explicit user intent wins unless it violates a safety floor.
Re-evaluate every current boundary using recent tool evidence and resolve
referential instructions such as "continue" or "do it" from that context.
Never select effort above xhigh.
"""
response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["claude_sonnet_high","codex_sol_high","codex_terra_medium","claude_sonnet_medium","codex_terra_high","codex_sol_medium","claude_opus_high","codex_sol_xhigh","claude_opus_xhigh","codex_luna_low","claude_haiku_low","local_qwen_medium","local_qwen_low","codex_terra_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
'''
[routes.auto_deep.policy]
type = "target_selector"
selector = "/decision/target"
[routes.auto_maximum]
id = "atlas/auto/maximum"
type = "llm_classifier"
mode = "custom"
classifier_target = "classifier"
targets = ["codex_sol_high", "claude_opus_high", "claude_sonnet_high", "codex_terra_high", "codex_sol_xhigh", "claude_opus_xhigh", "codex_terra_medium", "claude_sonnet_medium", "codex_sol_medium", "codex_luna_low", "claude_haiku_low", "local_qwen_medium", "local_qwen_low", "codex_terra_low"]
default_target = "codex_sol_high"
max_output_tokens = 96
session_affinity = false
recent_turn_window = 16
context_window = 272000
tool_calling = true
reasoning = true
prompt = """
You are the routing authority for an owner-only engineering agent. Choose
exactly one configured target for this model-call boundary. Strongly favor
correctness, verification, and task completion; do not waste premium
capacity on truly mechanical steps. Prefer Codex for implementation,
debugging, tests, and direct repository changes. Prefer Claude for
architecture, difficult ambiguity, long-context synthesis, risk analysis,
and independent review. Production changes, security, migrations, data-loss
risk, destructive work, and critical final review require high or xhigh.
Interpret user requests for speed, deeper thought, or a specific provider
semantically. Explicit user intent wins unless it undercuts the safety
floor. Re-evaluate every current boundary from the objective and recent tool
evidence, including referential instructions such as "continue" or "do
it". Never select effort above xhigh.
"""
response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["codex_sol_high","claude_opus_high","claude_sonnet_high","codex_terra_high","codex_sol_xhigh","claude_opus_xhigh","codex_terra_medium","claude_sonnet_medium","codex_sol_medium","codex_luna_low","claude_haiku_low","local_qwen_medium","local_qwen_low","codex_terra_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
'''
[routes.auto_maximum.policy]
type = "target_selector"
selector = "/decision/target"
[routes.worker_auto_maximum]
id = "atlas/worker/auto/maximum"
type = "llm_classifier"
mode = "custom"
classifier_target = "classifier"
targets = ["worker_codex_sol_high", "worker_claude_sonnet_high", "worker_codex_sol_xhigh", "worker_claude_opus_xhigh", "worker_codex_terra_medium", "worker_claude_sonnet_medium", "worker_codex_luna_low", "worker_claude_haiku_low"]
default_target = "worker_codex_sol_high"
max_output_tokens = 96
session_affinity = false
recent_turn_window = 16
context_window = 272000
tool_calling = false
reasoning = true
prompt = """
You are the sole routing authority for one durable engineering-worker
launch. Choose exactly one configured worker target from the current
objective, acceptance criteria, risk, and any prior-provider failure in the
request. Prefer Codex for implementation, debugging, tests, and repository
changes. Prefer Claude for architecture, ambiguity, synthesis, adversarial
analysis, and independent review. Use low only for mechanical bounded work,
medium for ordinary work, high for difficult or consequential work, and
xhigh for critical security, migration, destructive-risk, or independent
final review. Never exceed xhigh. If the request says a provider has failed
or exhausted capacity, do not select that provider.
"""
response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["worker_codex_sol_high","worker_claude_sonnet_high","worker_codex_sol_xhigh","worker_claude_opus_xhigh","worker_codex_terra_medium","worker_claude_sonnet_medium","worker_codex_luna_low","worker_claude_haiku_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
'''
[routes.worker_auto_maximum.policy]
type = "target_selector"
selector = "/decision/target"
[routes.worker_manual_codex_low]
id = "atlas/worker/manual/codex/low"
type = "random"
targets = ["worker_codex_luna_low"]
[routes.worker_manual_codex_medium]
id = "atlas/worker/manual/codex/medium"
type = "random"
targets = ["worker_codex_terra_medium"]
[routes.worker_manual_codex_high]
id = "atlas/worker/manual/codex/high"
type = "random"
targets = ["worker_codex_sol_high"]
[routes.worker_manual_codex_xhigh]
id = "atlas/worker/manual/codex/xhigh"
type = "random"
targets = ["worker_codex_sol_xhigh"]
[routes.worker_manual_claude_low]
id = "atlas/worker/manual/claude/low"
type = "random"
targets = ["worker_claude_haiku_low"]
[routes.worker_manual_claude_medium]
id = "atlas/worker/manual/claude/medium"
type = "random"
targets = ["worker_claude_sonnet_medium"]
[routes.worker_manual_claude_high]
id = "atlas/worker/manual/claude/high"
type = "random"
targets = ["worker_claude_sonnet_high"]
[routes.worker_manual_claude_xhigh]
id = "atlas/worker/manual/claude/xhigh"
type = "random"
targets = ["worker_claude_opus_xhigh"]
# A zero-weight target is not selected initially. Switchyard still walks
# this ordered list after 403/408/429/5xx, timeout, or transport failure.
[routes.manual_codex_luna]
id = "atlas/manual/codex/luna"
type = "random"
targets = ["codex_luna_low", "claude_haiku_low", "codex_terra_medium", "claude_sonnet_medium", "local_qwen_low"]
weights = [1, 0, 0, 0, 0]
context_window = 272000
tool_calling = true
reasoning = true
[routes.manual_codex_terra]
id = "atlas/manual/codex/terra"
type = "random"
targets = ["codex_terra_medium", "claude_sonnet_medium", "codex_sol_high", "claude_sonnet_high", "local_qwen_medium"]
weights = [1, 0, 0, 0, 0]
context_window = 272000
tool_calling = true
reasoning = true
[routes.manual_codex_sol]
id = "atlas/manual/codex/sol"
type = "random"
targets = ["codex_sol_high", "claude_opus_high", "claude_sonnet_high", "codex_terra_high", "local_qwen_medium"]
weights = [1, 0, 0, 0, 0]
context_window = 272000
tool_calling = true
reasoning = true
[routes.manual_claude_haiku]
id = "atlas/manual/claude/haiku"
type = "random"
targets = ["claude_haiku_low", "codex_luna_low", "claude_sonnet_medium", "codex_terra_medium", "local_qwen_low"]
weights = [1, 0, 0, 0, 0]
context_window = 272000
tool_calling = true
reasoning = true
[routes.manual_claude_sonnet]
id = "atlas/manual/claude/sonnet"
type = "random"
targets = ["claude_sonnet_high", "codex_sol_high", "claude_opus_high", "codex_terra_high", "local_qwen_medium"]
weights = [1, 0, 0, 0, 0]
context_window = 272000
tool_calling = true
reasoning = true
[routes.manual_claude_opus]
id = "atlas/manual/claude/opus"
type = "random"
targets = ["claude_opus_high", "codex_sol_high", "claude_sonnet_high", "codex_terra_high", "local_qwen_medium"]
weights = [1, 0, 0, 0, 0]
context_window = 272000
tool_calling = true
reasoning = true
[routes.manual_local_qwen]
id = "atlas/manual/local/qwen-14b"
type = "random"
targets = ["local_qwen_medium", "codex_terra_medium", "claude_sonnet_medium", "codex_luna_low", "claude_haiku_low"]
weights = [1, 0, 0, 0, 0]
context_window = 131072
tool_calling = true
reasoning = false