c6b1e72130
The operator decides which model providers exist (env / registry — Anthropic,
OpenAI, x.AI, Ollama, several at once). The *tree owner* decides who uses which:
- Members' assistant -> one configured provider (or none)
- Recommender (association/connection finder) -> one configured provider (or none)
- Owner -> may use any configured provider
Backend: two nullable columns on `trees` (ai_member_provider,
ai_recommender_provider) + migration; `configured_llm_providers()` exposes the
registry as {name, model} with no secrets; owner-gated GET/PATCH
/trees/{id}/ai validate names against the configured set. Frontend: owner-only
"AI models" page with a dropdown per role, graceful 403 for non-owners, and a
sidebar link.
Per-model-within-a-provider selection is a follow-up; today each provider maps
to its single configured model.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
35 lines
1.2 KiB
Python
35 lines
1.2 KiB
Python
"""Per-tree AI model policy — owner-only admin view."""
|
|
|
|
import uuid
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from app.api.deps import CurrentUser, SessionDep
|
|
from app.schemas.ai_policy import TreeAiPolicyRead, TreeAiPolicyUpdate
|
|
from app.services import ai_policy_service, tree_service
|
|
|
|
router = APIRouter(prefix="/trees", tags=["ai"])
|
|
|
|
|
|
@router.get("/{tree_id}/ai", response_model=TreeAiPolicyRead)
|
|
async def get_ai_policy(
|
|
tree_id: uuid.UUID, session: SessionDep, current: CurrentUser
|
|
) -> TreeAiPolicyRead:
|
|
tree = await tree_service.get_tree(session, viewer_id=current.id, tree_id=tree_id)
|
|
return TreeAiPolicyRead(**await ai_policy_service.get_policy(session, actor=current, tree=tree))
|
|
|
|
|
|
@router.patch("/{tree_id}/ai", response_model=TreeAiPolicyRead)
|
|
async def update_ai_policy(
|
|
tree_id: uuid.UUID, data: TreeAiPolicyUpdate, session: SessionDep, current: CurrentUser
|
|
) -> TreeAiPolicyRead:
|
|
tree = await tree_service.get_tree(session, viewer_id=current.id, tree_id=tree_id)
|
|
policy = await ai_policy_service.update_policy(
|
|
session,
|
|
actor=current,
|
|
tree=tree,
|
|
member_provider=data.member_provider,
|
|
recommender_provider=data.recommender_provider,
|
|
)
|
|
return TreeAiPolicyRead(**policy)
|