main
py 190 lines 7.88 KB
Raw
1 from __future__ import annotations
2
3 from helpers.api import ApiHandler, Request
4 from plugins._editor.helpers import markdown_sessions
5 from plugins._office.helpers import document_store
6
7
8 class EditorSession(ApiHandler):
9 async def process(self, input: dict, request: Request) -> dict:
10 action = str(input.get("action") or "open").lower().strip()
11 context_id = str(input.get("ctxid") or input.get("context_id") or "").strip()
12
13 if action == "status":
14 return {
15 "ok": True,
16 "open_files": markdown_sessions.get_manager().list_open(context_id=context_id),
17 }
18 if action == "home":
19 return {"ok": True, "path": document_store.default_open_path(context_id)}
20 if action == "list":
21 return {
22 "ok": True,
23 "open_files": markdown_sessions.get_manager().list_open(
24 context_id=context_id,
25 limit=int(input.get("limit") or 20),
26 ),
27 }
28 if action == "activate":
29 return markdown_sessions.get_manager().activate(str(input.get("session_id") or ""))
30 if action == "close":
31 closed = markdown_sessions.get_manager().close(str(input.get("session_id") or ""))
32 store_session_id = str(input.get("store_session_id") or "").strip()
33 file_id = str(input.get("file_id") or "").strip()
34 closed["store_closed"] = document_store.close_session(
35 session_id=store_session_id,
36 file_id="" if store_session_id else file_id,
37 )
38 return closed
39 if action == "create":
40 fmt = str(input.get("format") or "md").lower().lstrip(".")
41 if fmt not in document_store.EDITOR_TEXT_EXTENSIONS:
42 return {"ok": False, "error": "Editor can only create Markdown (.md) and text (.txt) documents."}
43 try:
44 doc = document_store.create_document(
45 kind="document",
46 title=str(input.get("title") or "Untitled"),
47 fmt=fmt,
48 content=str(input.get("content") or ""),
49 path=str(input.get("path") or ""),
50 context_id=context_id,
51 )
52 except ValueError as exc:
53 return {"ok": False, "error": str(exc)}
54 return await self._open_document(doc, input, request, context_id=context_id)
55 if action == "open":
56 file_id = str(input.get("file_id") or "").strip()
57 try:
58 doc = (
59 document_store.get_document(file_id)
60 if file_id
61 else document_store.register_document(
62 str(input.get("path") or ""),
63 context_id=context_id,
64 allow_base_dir=self._allow_base_dir_open(input),
65 )
66 )
67 except Exception as exc:
68 return {"ok": False, "error": str(exc)}
69 return await self._open_document(doc, input, request, context_id=context_id)
70 if action == "save":
71 session_id = str(input.get("session_id") or "").strip()
72 if not session_id:
73 return {"ok": False, "error": "session_id is required."}
74 return markdown_sessions.get_manager().save(session_id, text=input.get("text"))
75 if action == "save_as":
76 session_id = str(input.get("session_id") or "").strip()
77 path = str(input.get("path") or "").strip()
78 if not session_id:
79 return {"ok": False, "error": "session_id is required."}
80 if not path:
81 return {"ok": False, "error": "path is required."}
82 try:
83 result = markdown_sessions.get_manager().save_as(session_id, path, text=input.get("text"))
84 except Exception as exc:
85 return {"ok": False, "error": str(exc)}
86 document_store.close_session(session_id=str(input.get("store_session_id") or "").strip())
87 store_session = document_store.create_session(
88 result["document"]["file_id"],
89 user_id=str(input.get("user_id") or "agent-zero-user"),
90 permission="write",
91 origin=self._origin(request),
92 )
93 return {
94 **result,
95 "store_session_id": store_session["session_id"],
96 }
97 if action == "renamed":
98 return self._renamed(input, context_id)
99 if action == "refresh":
100 return markdown_sessions.get_manager().refresh_document(str(input.get("file_id") or ""))
101 return {"ok": False, "error": f"Unsupported editor session action: {action}"}
102
103 async def _open_document(
104 self,
105 doc: dict,
106 input: dict,
107 request: Request,
108 context_id: str = "",
109 ) -> dict:
110 if str(doc.get("extension") or "").lower() not in document_store.EDITOR_TEXT_EXTENSIONS:
111 return {
112 "ok": False,
113 "error": f".{doc.get('extension', '')} documents use the Desktop surface.",
114 "requires_desktop": True,
115 "document": _public_doc(doc),
116 }
117
118 mode = "edit" if str(input.get("mode") or "edit").lower() == "edit" else "view"
119 store_session = document_store.create_session(
120 doc["file_id"],
121 user_id=str(input.get("user_id") or "agent-zero-user"),
122 permission="write" if mode == "edit" else "read",
123 origin=self._origin(request),
124 )
125 try:
126 editor = markdown_sessions.get_manager().open(
127 doc,
128 sid="",
129 context_id=context_id,
130 refresh=input.get("refresh") is True,
131 )
132 except ValueError as exc:
133 document_store.close_session(session_id=store_session["session_id"])
134 return {"ok": False, "error": str(exc)}
135 return {
136 **editor,
137 "store_session_id": store_session["session_id"],
138 "session_id": editor["session_id"],
139 "mode": mode,
140 }
141
142 def _renamed(self, input: dict, context_id: str = "") -> dict:
143 file_id = str(input.get("file_id") or "").strip()
144 path = str(input.get("path") or "").strip()
145 if not file_id:
146 return {"ok": False, "error": "file_id is required."}
147 if not path:
148 return {"ok": False, "error": "path is required."}
149 try:
150 updated = document_store.rename_document(
151 file_id,
152 path,
153 content=input.get("text") if "text" in input else None,
154 context_id=context_id,
155 )
156 markdown_sessions.get_manager().renamed(
157 file_id,
158 updated,
159 text=input.get("text") if "text" in input else None,
160 )
161 except Exception as exc:
162 return {"ok": False, "error": str(exc)}
163 return {
164 "ok": True,
165 "document": _public_doc(updated),
166 "version": document_store.item_version(updated),
167 "refreshFiles": False,
168 }
169
170 def _origin(self, request: Request) -> str:
171 origin = request.headers.get("Origin") or request.host_url.rstrip("/")
172 return origin.rstrip("/")
173
174 def _allow_base_dir_open(self, input: dict) -> bool:
175 if str(input.get("source") or "").strip() != "file-browser":
176 return False
177 return bool(str(input.get("path") or "").strip())
178
179
180 def _public_doc(doc: dict) -> dict:
181 return {
182 "file_id": doc["file_id"],
183 "path": document_store.display_path(doc["path"]),
184 "basename": doc["basename"],
185 "title": doc["basename"],
186 "extension": doc["extension"],
187 "size": doc["size"],
188 "version": document_store.item_version(doc),
189 "last_modified": doc["last_modified"],
190 }