feat(ai): curated OpenRouter model picker for hybrid backend

Add OPENROUTER_ALLOWED_MODELS env var and GET /insights/openrouter/models
endpoint returning the curated list verbatim. Drop the live capability
precheck in hybrid mode — trust the operator's allowlist; bad ids surface
as a chat-call error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cameron
2026-04-21 10:36:19 -04:00
parent 3ac0cd62eb
commit e2eefbd156
7 changed files with 99 additions and 25 deletions

View File

@@ -2525,30 +2525,10 @@ Return ONLY the summary, nothing else."#,
// 2. Verify chat model supports tool calling.
// - local: existing Ollama model availability + capability check.
// - hybrid: query OpenRouter's /models for the chosen model.
// - hybrid: trust the operator's curated allowlist
// (OPENROUTER_ALLOWED_MODELS) — no live precheck. A bad model id
// surfaces as a chat-call error on the next step.
let has_vision = if is_hybrid {
let or_client = openrouter_client
.as_ref()
.expect("openrouter_client constructed when is_hybrid");
let caps = or_client
.model_capabilities(&or_client.primary_model)
.await
.map_err(|e| {
anyhow::anyhow!(
"OpenRouter capability lookup failed for '{}': {}",
or_client.primary_model,
e
)
})?;
if !caps.has_tool_calling {
return Err(anyhow::anyhow!(
"tool calling not supported by OpenRouter model '{}'",
or_client.primary_model
));
}
insight_cx
.span()
.set_attribute(KeyValue::new("model_has_tool_calling", true));
// In hybrid mode the chat model never sees images directly — we
// describe-then-inject, so `has_vision` drives only whether we
// bother loading the image to describe it, which we always do.
@@ -2776,7 +2756,7 @@ Return ONLY the summary, nothing else."#,
3. Use recall_facts_for_photo to load any previously stored knowledge about subjects in this photo.\n\
4. Use recall_entities to look up known people, places, or things that appear in this photo.\n\
5. When you identify people, places, events, or notable things in this photo: use store_entity to record them and store_fact to record key facts (relationships, roles, attributes). This builds a persistent memory for future insights.\n\
6. Only produce your final insight AFTER you have gathered context from at least 5-12 tool calls.\n\
6. Only produce your final insight AFTER you have gathered context from at least 5 tool calls.\n\
7. If a tool returns no results, that is useful information — continue calling the remaining tools anyway.",
cameron_id_note = cameron_id_note
);