feat(webui): add project workspaces and access controls (#4007)
* feat(webui): add project workspaces and access controls * feat(webui): add project workspaces and access controls * refactor(tools): centralize workspace access resolution * refactor(webui): remove unused workspace host state * fix(webui): hide estimated file edit label * fix(webui): clarify file edit deletion feedback * fix(webui): label deleted file activity * fix(webui): flatten file edit activity rows * fix(core): remove path-only patch deletion * fix(core): keep apply patch non-destructive * refactor(webui): trim workspace host plumbing * fix(tools): register exec with tools config
This commit is contained in:
@@ -8,6 +8,7 @@ from nanobot.agent.tools.base import Tool, tool_parameters
|
||||
from nanobot.agent.tools.context import ContextAware, RequestContext
|
||||
from nanobot.agent.tools.path_utils import resolve_workspace_path
|
||||
from nanobot.agent.tools.schema import ArraySchema, StringSchema, tool_parameters_schema
|
||||
from nanobot.security.workspace_access import current_tool_workspace
|
||||
from nanobot.bus.events import OutboundMessage
|
||||
from nanobot.config.paths import get_workspace_path
|
||||
|
||||
@@ -149,15 +150,19 @@ class MessageTool(Tool, ContextAware):
|
||||
def _resolve_media(self, media: list[str]) -> list[str]:
|
||||
"""Resolve local media attachments and enforce workspace restriction when enabled."""
|
||||
resolved: list[str] = []
|
||||
allowed_dir = self._workspace if self._restrict_to_workspace else None
|
||||
access = current_tool_workspace(
|
||||
self._workspace,
|
||||
restrict_to_workspace=self._restrict_to_workspace,
|
||||
)
|
||||
workspace = access.project_path or self._workspace
|
||||
for p in media:
|
||||
if p.startswith(("http://", "https://")):
|
||||
resolved.append(p)
|
||||
elif not self._restrict_to_workspace:
|
||||
elif not access.restrict_to_workspace:
|
||||
path = Path(p).expanduser()
|
||||
resolved.append(p if path.is_absolute() else str(self._workspace / path))
|
||||
resolved.append(p if path.is_absolute() else str(workspace / path))
|
||||
else:
|
||||
resolved.append(str(resolve_workspace_path(p, self._workspace, allowed_dir)))
|
||||
resolved.append(str(resolve_workspace_path(p, workspace, access.allowed_root)))
|
||||
return resolved
|
||||
|
||||
async def execute(
|
||||
|
||||
Reference in New Issue
Block a user