main
py 108 lines 3.77 KB
Raw
1 """POST /api/plugins/_a0_connector/v1/projects."""
2 from __future__ import annotations
3
4 from typing import Any, Mapping
5
6 from helpers.api import Request, Response
7 import plugins._a0_connector.api.v1.base as connector_base
8
9
10 def _string(value: object) -> str:
11 if value is None:
12 return ""
13 return str(value).strip()
14
15
16 def _normalize_project_summary(value: object) -> dict[str, str] | None:
17 if not isinstance(value, Mapping):
18 return None
19
20 name = _string(value.get("name"))
21 if not name:
22 return None
23
24 return {
25 "name": name,
26 "title": _string(value.get("title")),
27 "description": _string(value.get("description")),
28 "color": _string(value.get("color")),
29 }
30
31
32 class Projects(connector_base.ProtectedConnectorApiHandler):
33 """Thin connector proxy around the core `api.projects.Projects` surface."""
34
35 async def process(self, input: dict, request: Request) -> dict | Response:
36 action = _string(input.get("action")).lower() or "list"
37 if action not in {"list", "load", "update", "activate", "deactivate"}:
38 return {"ok": False, "error": f"Unsupported action: {action or '<missing>'}"}
39
40 core_response = await self._call_core(
41 {
42 "action": action,
43 "context_id": _string(input.get("context_id")),
44 "name": _string(input.get("name")),
45 "project": input.get("project"),
46 },
47 request,
48 )
49 if isinstance(core_response, Response):
50 return core_response
51 if not isinstance(core_response, Mapping):
52 return {"ok": False, "error": "Invalid response from core projects handler"}
53 if not core_response.get("ok"):
54 return {"ok": False, "error": _string(core_response.get("error")) or "Project request failed"}
55
56 if action in {"activate", "deactivate", "list"}:
57 return await self._normalized_list_state(_string(input.get("context_id")), request)
58
59 project = core_response.get("data")
60 return {
61 "ok": True,
62 "project": dict(project) if isinstance(project, Mapping) else {},
63 }
64
65 async def _normalized_list_state(self, context_id: str, request: Request) -> dict[str, Any] | Response:
66 core_response = await self._call_core(
67 {
68 "action": "list",
69 "context_id": context_id,
70 },
71 request,
72 )
73 if isinstance(core_response, Response):
74 return core_response
75 if not isinstance(core_response, Mapping):
76 return {"ok": False, "error": "Invalid response from core projects handler"}
77 if not core_response.get("ok"):
78 return {"ok": False, "error": _string(core_response.get("error")) or "Project request failed"}
79
80 projects: list[dict[str, str]] = []
81 for item in core_response.get("data") or []:
82 normalized = _normalize_project_summary(item)
83 if normalized is not None:
84 projects.append(normalized)
85
86 return {
87 "ok": True,
88 "projects": projects,
89 "current_project": self._load_current_project(context_id),
90 }
91
92 async def _call_core(self, payload: dict[str, Any], request: Request) -> dict | Response:
93 from api.projects import Projects as CoreProjects
94
95 handler = CoreProjects(self.app, self.thread_lock)
96 return await handler.process(payload, request)
97
98 def _load_current_project(self, context_id: str) -> dict[str, str] | None:
99 if not context_id:
100 return None
101
102 from agent import AgentContext
103
104 context = AgentContext.get(context_id)
105 if context is None:
106 return None
107
108 return _normalize_project_summary(context.get_output_data("project"))