diff --git a/navi/content_store.py b/navi/content_store.py index 8a752fb..e46a6d5 100644 --- a/navi/content_store.py +++ b/navi/content_store.py @@ -44,7 +44,7 @@ def _file_url(session_id: str, filename: str, *, download: bool = False) -> str: base_url = settings.public_url.rstrip("/") - url = f"{base_url}/sessions/{session_id}/files/{filename}" + url = f"{base_url}/api/sessions/{session_id}/files/{filename}" return f"{url}?download=1" if download else url diff --git a/navi/tools/content_publish.py b/navi/tools/content_publish.py index f68783c..dd8b1a9 100644 --- a/navi/tools/content_publish.py +++ b/navi/tools/content_publish.py @@ -2,7 +2,7 @@ The file must already exist in the session's file directory. Publishing only registers metadata; the file itself is NOT copied. -The user sees the file via the existing /sessions/{id}/files/{name} endpoint, +The user sees the file via the existing /api/sessions/{id}/files/{name} endpoint, so edits made by the agent are immediately visible. """ diff --git a/navi/tools/share_file.py b/navi/tools/share_file.py index 61adbef..c1ccb4f 100644 --- a/navi/tools/share_file.py +++ b/navi/tools/share_file.py @@ -27,7 +27,7 @@ "datasets, PDFs, CSV/JSON files, or other generated artifacts.\n\n" "Mechanics: share_file takes an ABSOLUTE source path, copies that file into " "SESSION_FILES_DIR/{session_id}/ under the optional clean filename, and returns a URL at " - "/sessions/{session_id}/files/{filename}. The source file remains where it was. " + "/api/sessions/{session_id}/files/{filename}. The source file remains where it was." "If a file with the same name already exists in the session directory, share_file creates " "a numbered filename instead of overwriting it. Max file size is SHARE_FILE_MAX_SIZE_MB " "(default 1024 MB / 1 GB).\n\n" @@ -133,7 +133,7 @@ size = dest.stat().st_size base_url = settings.public_url.rstrip("/") - url = f"{base_url}/sessions/{quote(session_id, safe='')}/files/{quote(dest.name, safe='')}" + url = f"{base_url}/api/sessions/{quote(session_id, safe='')}/files/{quote(dest.name, safe='')}" return ToolResult( success=True, diff --git a/tests/unit/test_content_store.py b/tests/unit/test_content_store.py index ad3f707..6c3075d 100644 --- a/tests/unit/test_content_store.py +++ b/tests/unit/test_content_store.py @@ -71,8 +71,8 @@ ) assert info["id"] == "sess-1_logo.svg" - assert info["url"] == "http://localhost:8000/sessions/sess-1/files/logo.svg" - assert info["download_url"] == "http://localhost:8000/sessions/sess-1/files/logo.svg?download=1" + assert info["url"] == "http://localhost:8000/api/sessions/sess-1/files/logo.svg" + assert info["download_url"] == "http://localhost:8000/api/sessions/sess-1/files/logo.svg?download=1" call = conn.calls[0] assert call[0] == "execute" assert "ON CONFLICT (session_id, filename) DO UPDATE" in call[1] @@ -98,7 +98,7 @@ ) assert info["source_filename"] == "model.scad" - assert info["source_url"] == "http://localhost:8000/sessions/sess-1/files/model.scad" + assert info["source_url"] == "http://localhost:8000/api/sessions/sess-1/files/model.scad" assert conn.calls[0][2][5] == "model.scad" async def test_publish_ignores_missing_source_file(self, monkeypatch, tmp_path): @@ -191,8 +191,8 @@ "filename": "logo.svg", "content_type": "svg", "title": "Logo", - "url": "http://localhost:8000/sessions/sess-1/files/logo.svg", - "download_url": "http://localhost:8000/sessions/sess-1/files/logo.svg?download=1", + "url": "http://localhost:8000/api/sessions/sess-1/files/logo.svg", + "download_url": "http://localhost:8000/api/sessions/sess-1/files/logo.svg?download=1", "created_at": "2026-04-30T00:00:00+00:00", "updated_at": "2026-04-30T01:02:03+00:00", }] diff --git a/tests/unit/tools/test_share_file.py b/tests/unit/tools/test_share_file.py index 6628e5d..7d39c2e 100644 --- a/tests/unit/tools/test_share_file.py +++ b/tests/unit/tools/test_share_file.py @@ -61,9 +61,9 @@ assert result.success parsed = urlparse(result.metadata["url"]) assert parsed.path.endswith( - "/sessions/sess%201/files/%D0%BE%D1%82%D1%87%D1%91%D1%82%20%231.txt" + "/api/sessions/sess%201/files/%D0%BE%D1%82%D1%87%D1%91%D1%82%20%231.txt" ) - assert unquote(parsed.path).endswith("/sessions/sess 1/files/отчёт #1.txt") + assert unquote(parsed.path).endswith("/api/sessions/sess 1/files/отчёт #1.txt") async def test_duplicate_filename_gets_numbered_copy(self, tool, tmp_path): src = tmp_path / "source.txt" diff --git a/webclient/dist/content-viewers/stl.html b/webclient/dist/content-viewers/stl.html index 7c39978..11c9b7f 100644 --- a/webclient/dist/content-viewers/stl.html +++ b/webclient/dist/content-viewers/stl.html @@ -63,7 +63,7 @@ + 'Try enabling hardware acceleration or a different browser.

' + ''; console.error('WebGL init failed:', err); - throw err; + return; } const controls = new OrbitControls(camera, renderer.domElement); diff --git a/webclient/public/content-viewers/stl.html b/webclient/public/content-viewers/stl.html index 7c39978..11c9b7f 100644 --- a/webclient/public/content-viewers/stl.html +++ b/webclient/public/content-viewers/stl.html @@ -63,7 +63,7 @@ + 'Try enabling hardware acceleration or a different browser.

' + ''; console.error('WebGL init failed:', err); - throw err; + return; } const controls = new OrbitControls(camera, renderer.domElement); diff --git a/webclient/src/utils/contentLinks.js b/webclient/src/utils/contentLinks.js index fc8efaf..29e615d 100644 --- a/webclient/src/utils/contentLinks.js +++ b/webclient/src/utils/contentLinks.js @@ -15,7 +15,8 @@ parsed.port === DEV_API_PORT && ['localhost', '127.0.0.1'].includes(parsed.hostname) ) { - return `/api${parsed.pathname}${parsed.search}${parsed.hash}` + const path = parsed.pathname.startsWith('/api/') ? parsed.pathname : `/api${parsed.pathname}` + return `${path}${parsed.search}${parsed.hash}` } if (parsed.origin === window.location.origin) {