cellcog 2.1.2__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {cellcog-2.1.2 → cellcog-2.2.0}/PKG-INFO +1 -1
  2. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/__init__.py +1 -1
  3. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/files.py +14 -4
  4. {cellcog-2.1.2 → cellcog-2.2.0}/pyproject.toml +1 -1
  5. cellcog-2.2.0/tests/test_gs_url_handling.py +54 -0
  6. {cellcog-2.1.2 → cellcog-2.2.0}/.convex/.gitignore +0 -0
  7. {cellcog-2.1.2 → cellcog-2.2.0}/.convex/local/default/config.json +0 -0
  8. {cellcog-2.1.2 → cellcog-2.2.0}/.convex/local/default/convex_local_backend.sqlite3 +0 -0
  9. {cellcog-2.1.2 → cellcog-2.2.0}/.convex/local/default/convex_local_storage/modules/18330a2b-2cf5-4f51-89a5-8d97a422e7a2.blob +0 -0
  10. {cellcog-2.1.2 → cellcog-2.2.0}/.gitignore +0 -0
  11. {cellcog-2.1.2 → cellcog-2.2.0}/LICENSE +0 -0
  12. {cellcog-2.1.2 → cellcog-2.2.0}/README.md +0 -0
  13. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/auth.py +0 -0
  14. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/chat.py +0 -0
  15. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/client.py +0 -0
  16. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/config.py +0 -0
  17. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/daemon/__init__.py +0 -0
  18. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/daemon/delivery.py +0 -0
  19. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/daemon/main.py +0 -0
  20. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/daemon/state.py +0 -0
  21. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/docs/__init__.py +0 -0
  22. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/docs/api_reference.md +0 -0
  23. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/docs/support.md +0 -0
  24. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/exceptions.py +0 -0
  25. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/message_formatter.py +0 -0
  26. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/message_processor.py +0 -0
  27. {cellcog-2.1.2 → cellcog-2.2.0}/cellcog/version_detection.py +0 -0
  28. {cellcog-2.1.2 → cellcog-2.2.0}/examples/basic_usage.py +0 -0
  29. {cellcog-2.1.2 → cellcog-2.2.0}/examples/file_handling.py +0 -0
  30. {cellcog-2.1.2 → cellcog-2.2.0}/examples/streaming_usage.py +0 -0
  31. {cellcog-2.1.2 → cellcog-2.2.0}/examples/sync_usage.py +0 -0
  32. {cellcog-2.1.2 → cellcog-2.2.0}/examples/workflow_usage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellcog
3
- Version: 2.1.2
3
+ Version: 2.2.0
4
4
  Summary: Python SDK for CellCog - Any-to-Any AI for agents. Fire-and-forget pattern with WebSocket notifications.
5
5
  Project-URL: Homepage, https://cellcog.ai
6
6
  Project-URL: Documentation, https://cellcog.ai/developer/docs
@@ -48,7 +48,7 @@ from .exceptions import (
48
48
  SDKUpgradeRequiredError,
49
49
  )
50
50
 
51
- __version__ = "2.1.1"
51
+ __version__ = "2.2.0"
52
52
  __all__ = [
53
53
  "CellCogClient",
54
54
  "CellCogError",
@@ -66,8 +66,10 @@ class FileProcessor:
66
66
  attrs = match.group(1)
67
67
  file_path = match.group(2).strip()
68
68
 
69
- # Skip empty paths and URLs — not local files
70
- if not file_path or file_path.startswith(("http://", "https://")):
69
+ # Skip empty paths and URLs — not local files. gs:// is a CellCog
70
+ # storage reference (already-uploaded file); leave it untouched so it
71
+ # is not mistaken for a missing local file (which would raise).
72
+ if not file_path or file_path.startswith(("http://", "https://", "gs://")):
71
73
  return match.group(0)
72
74
 
73
75
  # Cross-platform local file detection:
@@ -272,17 +274,25 @@ class FileProcessor:
272
274
  """
273
275
  Generate safe download path under ~/.cellcog/chats/{chat_id}/.
274
276
 
275
- Handles two blob_name formats:
277
+ Handles these blob_name formats:
278
+ - gs://bucket/{chat_id}/path/to/file.ext (canonical explicit GS URL)
276
279
  - {chat_id}//home/app/path/to/file.ext (double slash = from CellCog's /home/app/)
277
280
  - {chat_id}/path/to/file.ext (single slash = relative path)
278
281
 
279
282
  Args:
280
- blob_name: Full blob name from CellCog
283
+ blob_name: Full blob name (or gs:// URL) from CellCog
281
284
  chat_id: Chat ID for organizing downloads
282
285
 
283
286
  Returns:
284
287
  Local path like ~/.cellcog/chats/{chat_id}/{path}
285
288
  """
289
+ # Strip a canonical gs://bucket/ prefix down to the bare blob name
290
+ # ({chat_id}/path...) so the existing chat_id-prefix logic applies.
291
+ if blob_name.startswith("gs://"):
292
+ # gs://bucket/{chat_id}/path → drop scheme + bucket (first 3 segments)
293
+ parts = blob_name.split("/", 3)
294
+ blob_name = parts[3] if len(parts) > 3 else parts[-1]
295
+
286
296
  if "/" not in blob_name:
287
297
  # Malformed - use blob_name as filename
288
298
  return str(self.default_download_dir / chat_id / blob_name)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cellcog"
7
- version = "2.1.2"
7
+ version = "2.2.0"
8
8
  description = "Python SDK for CellCog - Any-to-Any AI for agents. Fire-and-forget pattern with WebSocket notifications."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,54 @@
1
+ """Standalone tests for SDK gs:// SHOW_FILE handling.
2
+
3
+ Run: python3 tests/test_gs_url_handling.py
4
+ """
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
10
+
11
+ from cellcog.config import Config
12
+ from cellcog.files import FileProcessor
13
+
14
+ CHAT = "687a8aa4fcf12067f5a5b9e0"
15
+ failed = 0
16
+
17
+
18
+ def check(label, got, want):
19
+ global failed
20
+ ok = got == want
21
+ if not ok:
22
+ failed += 1
23
+ print(f"[FAIL] {label}\n got : {got}\n want: {want}")
24
+ else:
25
+ print(f"[OK ] {label}")
26
+
27
+
28
+ fp = FileProcessor(Config())
29
+
30
+ # --- download-path derivation strips gs://bucket/ then chat_id ---
31
+ # Real CellCog blobs from /home/app are {chat_id}//home/app/... (double slash:
32
+ # {chat_id}/ + the absolute /home/app/... path). The /home/app/ prefix is stripped.
33
+ p = fp._generate_auto_download_path(f"gs://cellcog_files/{CHAT}//home/app/out.png", CHAT)
34
+ check("gs:// download path strips scheme+bucket+chat+/home/app",
35
+ p, str(fp.default_download_dir / CHAT / "out.png"))
36
+
37
+ # A non-/home/app relative path keeps its sub-path after the chat_id.
38
+ p = fp._generate_auto_download_path(f"gs://cellcog_files/{CHAT}/sub/dir/file.pdf", CHAT)
39
+ check("gs:// download path nested",
40
+ p, str(fp.default_download_dir / CHAT / "sub/dir/file.pdf"))
41
+
42
+ # --- legacy bare blob still works (back-compat), double-slash /home/app form ---
43
+ p = fp._generate_auto_download_path(f"{CHAT}//home/app/out.png", CHAT)
44
+ check("legacy bare blob still derives correctly",
45
+ p, str(fp.default_download_dir / CHAT / "out.png"))
46
+
47
+ # --- outgoing: gs:// is left untouched (not treated as missing local file) ---
48
+ msg = f"Here <SHOW_FILE>gs://cellcog_files/{CHAT}/a.png</SHOW_FILE> done"
49
+ transformed, uploaded = fp.transform_outgoing(msg)
50
+ check("outgoing gs:// unchanged", transformed, msg)
51
+ check("outgoing gs:// nothing uploaded", uploaded, [])
52
+
53
+ print("\n" + ("ALL PASS" if failed == 0 else f"{failed} FAILURE(S)"))
54
+ sys.exit(1 if failed else 0)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes