Connector calls, semantic rules, and DuckDB memory keep long runs stable, and stream retry stops chats from stalling. Co-authored-by: Cursor <cursoragent@cursor.com>
79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from kamidso.contracts.errors import KamidsoError, KamidsoErrorCode
|
|
from kamidso.contracts.resource import ResourceRef
|
|
from kamidso.contracts.user import CurrentUser
|
|
from kamidso.repositories.store import RepositoryStore
|
|
|
|
|
|
class ResourceRegistry:
|
|
def __init__(self, store: RepositoryStore) -> None:
|
|
self._store = store
|
|
|
|
async def authorize(self, user: CurrentUser, ref: ResourceRef) -> Dict[str, Any]:
|
|
if ref.type == "file":
|
|
doc = await self._store.get_file(user.workspace_id, ref.id)
|
|
elif ref.type == "datasource":
|
|
doc = await self._store.get_datasource(user.workspace_id, ref.id)
|
|
elif ref.type == "knowledge":
|
|
doc = await self._store.get_knowledge_source(user.workspace_id, ref.id)
|
|
elif ref.type == "connector":
|
|
doc = _authorize_connector(user, ref.id)
|
|
else:
|
|
raise KamidsoError(KamidsoErrorCode.RESOURCE_NOT_FOUND)
|
|
if doc is None:
|
|
raise KamidsoError(KamidsoErrorCode.RESOURCE_NOT_FOUND)
|
|
status = str(doc.get("status") or "ready")
|
|
if status not in {"ready", "active"}:
|
|
raise KamidsoError(KamidsoErrorCode.RESOURCE_NOT_READY)
|
|
return doc
|
|
|
|
async def authorize_many(
|
|
self, user: CurrentUser, refs: List[ResourceRef]
|
|
) -> List[Dict[str, Any]]:
|
|
return [await self.authorize(user, ref) for ref in refs]
|
|
|
|
async def bind_engine(
|
|
self,
|
|
*,
|
|
workspace_id: str,
|
|
resource_id: str,
|
|
engine: str,
|
|
engine_resource_id: str,
|
|
binding_type: str = "persistent",
|
|
) -> Dict[str, Any]:
|
|
return await self._store.upsert_resource_binding(
|
|
{
|
|
"workspace_id": workspace_id,
|
|
"resource_id": resource_id,
|
|
"engine": engine,
|
|
"engine_resource_id": engine_resource_id,
|
|
"binding_type": binding_type,
|
|
"status": "ready",
|
|
}
|
|
)
|
|
|
|
|
|
def _authorize_connector(user: CurrentUser, connector_id: str) -> Optional[Dict[str, Any]]:
|
|
"""Public connector row. Credentials stay in the encrypted connector table."""
|
|
from kamidso.native_connectors.resolve import load_public_instance
|
|
|
|
row = load_public_instance(connector_id)
|
|
if row is None:
|
|
return None
|
|
owner = str(row.get("user_name") or "")
|
|
if owner and owner != user.id:
|
|
return None
|
|
workspace = str(row.get("sys_code") or "")
|
|
if workspace and user.workspace_id and workspace != user.workspace_id:
|
|
return None
|
|
status = str(row.get("status") or "")
|
|
return {
|
|
"id": row.get("connector_id"),
|
|
"status": status,
|
|
"name": row.get("display_name") or connector_id,
|
|
"connector_type": row.get("connector_type"),
|
|
}
|