Files
provenance/backend/app/api/v1/ai.py
T
justin c6b1e72130 Per-tree AI model policy (owner-only admin view)
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>
2026-06-09 20:52:30 -04:00

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)