ltcai 10.0.0 → 10.3.0

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 (214) hide show
  1. package/README.md +43 -32
  2. package/docs/CHANGELOG.md +204 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  4. package/docs/DEVELOPMENT.md +1 -1
  5. package/docs/HYBRID_CLOUD_KG_STREAMING.md +101 -0
  6. package/docs/MYPY_BACKLOG.md +98 -0
  7. package/docs/ONBOARDING.md +1 -1
  8. package/docs/OPERATIONS.md +1 -1
  9. package/docs/TRUST_MODEL.md +1 -1
  10. package/docs/WHY_LATTICE.md +1 -1
  11. package/docs/kg-schema.md +1 -1
  12. package/lattice_brain/__init__.py +1 -1
  13. package/lattice_brain/archive.py +5 -4
  14. package/lattice_brain/conversations.py +14 -3
  15. package/lattice_brain/embeddings.py +12 -2
  16. package/lattice_brain/graph/_kg_common.py +5 -5
  17. package/lattice_brain/graph/_kg_fsutil.py +5 -4
  18. package/lattice_brain/graph/discovery.py +4 -3
  19. package/lattice_brain/graph/discovery_index.py +0 -1
  20. package/lattice_brain/graph/documents.py +3 -2
  21. package/lattice_brain/graph/fusion.py +4 -0
  22. package/lattice_brain/graph/ingest.py +12 -2
  23. package/lattice_brain/graph/projection.py +3 -2
  24. package/lattice_brain/graph/provenance.py +5 -3
  25. package/lattice_brain/graph/rerank.py +4 -1
  26. package/lattice_brain/graph/retrieval.py +0 -1
  27. package/lattice_brain/graph/retrieval_docgen.py +0 -1
  28. package/lattice_brain/graph/retrieval_reads.py +0 -1
  29. package/lattice_brain/graph/retrieval_vector.py +0 -1
  30. package/lattice_brain/graph/schema.py +4 -3
  31. package/lattice_brain/graph/store.py +18 -4
  32. package/lattice_brain/graph/write_master.py +46 -1
  33. package/lattice_brain/ingestion.py +4 -1
  34. package/lattice_brain/portability.py +5 -2
  35. package/lattice_brain/quality.py +12 -5
  36. package/lattice_brain/quiet.py +43 -0
  37. package/lattice_brain/runtime/agent_runtime.py +19 -10
  38. package/lattice_brain/runtime/hooks.py +3 -2
  39. package/lattice_brain/runtime/multi_agent.py +2 -3
  40. package/lattice_brain/sensitivity.py +94 -0
  41. package/lattice_brain/storage/base.py +30 -2
  42. package/lattice_brain/storage/migration.py +3 -2
  43. package/lattice_brain/storage/postgres.py +2 -2
  44. package/lattice_brain/storage/sqlite.py +6 -4
  45. package/lattice_brain/workflow.py +4 -2
  46. package/latticeai/__init__.py +1 -1
  47. package/latticeai/api/admin.py +1 -1
  48. package/latticeai/api/agents.py +4 -2
  49. package/latticeai/api/auth.py +5 -1
  50. package/latticeai/api/automation_intelligence.py +2 -1
  51. package/latticeai/api/browser.py +3 -2
  52. package/latticeai/api/chat.py +28 -17
  53. package/latticeai/api/chat_agent_http.py +22 -8
  54. package/latticeai/api/chat_contracts.py +4 -0
  55. package/latticeai/api/chat_documents.py +6 -2
  56. package/latticeai/api/chat_hybrid.py +82 -0
  57. package/latticeai/api/computer_use.py +8 -3
  58. package/latticeai/api/knowledge_graph.py +1 -1
  59. package/latticeai/api/mcp.py +4 -4
  60. package/latticeai/api/models.py +5 -2
  61. package/latticeai/api/network_boundary.py +220 -0
  62. package/latticeai/api/permissions.py +0 -1
  63. package/latticeai/api/realtime.py +1 -1
  64. package/latticeai/api/security_dashboard.py +1 -1
  65. package/latticeai/api/setup.py +16 -3
  66. package/latticeai/api/static_routes.py +2 -1
  67. package/latticeai/api/tools.py +12 -8
  68. package/latticeai/api/voice_capture.py +3 -1
  69. package/latticeai/api/workflow_designer.py +1 -1
  70. package/latticeai/api/workspace.py +1 -2
  71. package/latticeai/app_factory.py +174 -145
  72. package/latticeai/cli/entrypoint.py +6 -4
  73. package/latticeai/core/agent.py +55 -495
  74. package/latticeai/core/agent_eval.py +2 -2
  75. package/latticeai/core/agent_helpers.py +493 -0
  76. package/latticeai/core/agent_prompts.py +0 -1
  77. package/latticeai/core/agent_registry.py +3 -1
  78. package/latticeai/core/agent_state.py +41 -0
  79. package/latticeai/core/audit.py +1 -1
  80. package/latticeai/core/builtin_hooks.py +2 -1
  81. package/latticeai/core/config.py +0 -1
  82. package/latticeai/core/embedding_providers.py +12 -1
  83. package/latticeai/core/file_generation.py +3 -0
  84. package/latticeai/core/invitations.py +4 -1
  85. package/latticeai/core/io_utils.py +3 -1
  86. package/latticeai/core/legacy_compatibility.py +1 -2
  87. package/latticeai/core/local_embeddings.py +12 -1
  88. package/latticeai/core/marketplace.py +1 -2
  89. package/latticeai/core/mcp_registry.py +0 -1
  90. package/latticeai/core/model_compat.py +1 -1
  91. package/latticeai/core/model_resolution.py +1 -1
  92. package/latticeai/core/network_boundary.py +168 -0
  93. package/latticeai/core/oidc.py +3 -0
  94. package/latticeai/core/permission_mode.py +6 -6
  95. package/latticeai/core/plugins.py +3 -2
  96. package/latticeai/core/policy.py +0 -1
  97. package/latticeai/core/quiet.py +84 -0
  98. package/latticeai/core/realtime.py +3 -2
  99. package/latticeai/core/run_store.py +4 -2
  100. package/latticeai/core/security.py +4 -0
  101. package/latticeai/core/users.py +5 -3
  102. package/latticeai/core/workspace_graph_trace.py +3 -0
  103. package/latticeai/core/workspace_os.py +65 -273
  104. package/latticeai/core/workspace_os_constants.py +126 -0
  105. package/latticeai/core/workspace_os_state.py +180 -0
  106. package/latticeai/core/workspace_os_utils.py +3 -1
  107. package/latticeai/core/workspace_permissions.py +1 -0
  108. package/latticeai/core/workspace_snapshots.py +3 -1
  109. package/latticeai/core/workspace_timeline.py +3 -1
  110. package/latticeai/integrations/telegram_bot.py +25 -16
  111. package/latticeai/models/router.py +6 -3
  112. package/latticeai/runtime/access_runtime.py +3 -1
  113. package/latticeai/runtime/audit_runtime.py +3 -2
  114. package/latticeai/runtime/chat_wiring.py +4 -1
  115. package/latticeai/runtime/history_runtime.py +1 -1
  116. package/latticeai/runtime/history_writer.py +138 -0
  117. package/latticeai/runtime/lifespan_runtime.py +3 -1
  118. package/latticeai/runtime/network_boundary_wiring.py +124 -0
  119. package/latticeai/runtime/persistence_runtime.py +3 -1
  120. package/latticeai/runtime/router_registration.py +11 -1
  121. package/latticeai/services/architecture_readiness.py +1 -2
  122. package/latticeai/services/change_proposals.py +2 -1
  123. package/latticeai/services/cloud_egress_audit.py +85 -0
  124. package/latticeai/services/cloud_extraction.py +129 -0
  125. package/latticeai/services/cloud_streaming.py +266 -0
  126. package/latticeai/services/cloud_token_guard.py +84 -0
  127. package/latticeai/services/command_center.py +2 -1
  128. package/latticeai/services/folder_watch.py +3 -0
  129. package/latticeai/services/funnel_metrics.py +3 -1
  130. package/latticeai/services/hybrid_chat.py +265 -0
  131. package/latticeai/services/hybrid_context.py +228 -0
  132. package/latticeai/services/hybrid_policy.py +178 -0
  133. package/latticeai/services/memory_service.py +1 -1
  134. package/latticeai/services/model_catalog.py +10 -1
  135. package/latticeai/services/model_engines.py +35 -14
  136. package/latticeai/services/model_loading.py +3 -2
  137. package/latticeai/services/model_runtime.py +68 -17
  138. package/latticeai/services/multimodal_streaming.py +123 -0
  139. package/latticeai/services/network_boundary_service.py +154 -0
  140. package/latticeai/services/openai_compatible_adapter.py +100 -0
  141. package/latticeai/services/p_reinforce.py +4 -0
  142. package/latticeai/services/platform_runtime.py +9 -4
  143. package/latticeai/services/process_audit.py +0 -1
  144. package/latticeai/services/product_readiness.py +1 -1
  145. package/latticeai/services/run_executor.py +3 -2
  146. package/latticeai/services/search_service.py +1 -4
  147. package/latticeai/services/setup_detection.py +2 -1
  148. package/latticeai/services/tool_dispatch.py +7 -2
  149. package/latticeai/services/upload_service.py +2 -1
  150. package/latticeai/setup/auto_setup.py +10 -7
  151. package/latticeai/setup/wizard.py +15 -11
  152. package/latticeai/tools/__init__.py +3 -3
  153. package/latticeai/tools/commands.py +7 -7
  154. package/latticeai/tools/computer.py +3 -2
  155. package/latticeai/tools/documents.py +10 -9
  156. package/latticeai/tools/filesystem.py +7 -4
  157. package/latticeai/tools/knowledge.py +2 -0
  158. package/latticeai/tools/local_files.py +1 -1
  159. package/latticeai/tools/network.py +2 -1
  160. package/package.json +7 -3
  161. package/scripts/bench_agent_smoke.py +0 -1
  162. package/scripts/bench_models.py +0 -1
  163. package/scripts/brain_quality_eval.py +7 -2
  164. package/scripts/bump_version.py +2 -1
  165. package/scripts/check_current_release_docs.mjs +1 -1
  166. package/scripts/migrate_brain_storage.py +5 -1
  167. package/scripts/profile_kg.py +2 -7
  168. package/scripts/verify_hf_model_registry.py +2 -2
  169. package/src-tauri/Cargo.lock +1 -1
  170. package/src-tauri/Cargo.toml +1 -1
  171. package/src-tauri/tauri.conf.json +1 -1
  172. package/static/app/asset-manifest.json +37 -37
  173. package/static/app/assets/{Act-BtCREeN1.js → Act-DrKIGZeJ.js} +1 -1
  174. package/static/app/assets/{AdminConsole-TPeeN18T.js → AdminConsole-CEV1VefA.js} +1 -1
  175. package/static/app/assets/{Brain-BKs6JAp0.js → Brain-BZSXnwWU.js} +1 -1
  176. package/static/app/assets/{BrainHome-BPGOvSd6.js → BrainHome-CEBd86k6.js} +1 -1
  177. package/static/app/assets/{BrainSignals-CtzQZ15J.js → BrainSignals-O4s6R7av.js} +1 -1
  178. package/static/app/assets/{Capture-1_NaHWqB.js → Capture-AGbOxsg-.js} +1 -1
  179. package/static/app/assets/{CommandPalette-pqvQOXe4.js → CommandPalette-CeqBjCn2.js} +1 -1
  180. package/static/app/assets/Library-CXnbNiQW.js +1 -0
  181. package/static/app/assets/{LivingBrain-DlQ20Q75.js → LivingBrain-D9Iei2ZJ.js} +1 -1
  182. package/static/app/assets/{ProductFlow-BZvGDRi_.js → ProductFlow-JlXiDfMM.js} +1 -1
  183. package/static/app/assets/{ReviewCard-BWgI0D2s.js → ReviewCard-QQly2bTV.js} +1 -1
  184. package/static/app/assets/System-Bp9ZY4ER.js +1 -0
  185. package/static/app/assets/{activity-Dlfk8YC7.js → activity-CxRPOQ2F.js} +1 -1
  186. package/static/app/assets/{bot-CDvUB76P.js → bot-1bcsWB2s.js} +1 -1
  187. package/static/app/assets/{brain-xczrohrt.js → brain-CxaeKCRM.js} +1 -1
  188. package/static/app/assets/{button-SOdH3Oyf.js → button-ZYFqGan7.js} +1 -1
  189. package/static/app/assets/{circle-pause-CG1ythH4.js → circle-pause-B5NOIqvk.js} +1 -1
  190. package/static/app/assets/{circle-play-HXwvjS6W.js → circle-play-BiJVFXf7.js} +1 -1
  191. package/static/app/assets/{cpu-B0d-rGyk.js → cpu-Vvq0OKTr.js} +1 -1
  192. package/static/app/assets/{download-BGIkTQL6.js → download-SEcXzkx1.js} +1 -1
  193. package/static/app/assets/{folder-open-Dst_Z0_K.js → folder-open-Dw1ff_Qa.js} +1 -1
  194. package/static/app/assets/{hard-drive-D53MsWkV.js → hard-drive-B00fR7_r.js} +1 -1
  195. package/static/app/assets/index-CEkL4_M-.css +2 -0
  196. package/static/app/assets/{index-C_IrlQMV.js → index-Dm9VXl1o.js} +3 -3
  197. package/static/app/assets/{input-C5m0riF6.js → input-DtdWYQEa.js} +1 -1
  198. package/static/app/assets/{network-C5a-E5iS.js → network-CpjBu0kI.js} +1 -1
  199. package/static/app/assets/{primitives-vNXYf58F.js → primitives-CwsudBwc.js} +1 -1
  200. package/static/app/assets/search-CwEJWBEA.js +1 -0
  201. package/static/app/assets/{shield-alert-Cc-WVXqN.js → shield-alert-CpjBc-gQ.js} +1 -1
  202. package/static/app/assets/{textarea-BkZ0EqVO.js → textarea-DUPyjHQs.js} +1 -1
  203. package/static/app/assets/{useFocusTrap-CTtKbAOU.js → useFocusTrap-BWcMtCWH.js} +1 -1
  204. package/static/app/assets/{useQuery-Dx1fi4Wu.js → useQuery-Dg5fPqTS.js} +1 -1
  205. package/static/app/assets/{users-BFpQXtEF.js → users-BgcdTQGM.js} +1 -1
  206. package/static/app/assets/{utils-BA_lmW3J.js → utils-a3YXFtEO.js} +2 -2
  207. package/static/app/assets/workspace-BMUEiXUm.js +1 -0
  208. package/static/app/index.html +4 -4
  209. package/static/sw.js +1 -1
  210. package/static/app/assets/Library-DhvoPvC7.js +0 -1
  211. package/static/app/assets/System-CSMdYLMy.js +0 -1
  212. package/static/app/assets/index-FxDusbr0.css +0 -2
  213. package/static/app/assets/search-DhbSgW6m.js +0 -1
  214. package/static/app/assets/workspace-DBPB0jkX.js +0 -1
@@ -12,8 +12,28 @@ import json
12
12
  import shutil
13
13
  import sqlite3
14
14
  from collections import deque
15
+ from contextlib import contextmanager
15
16
  from pathlib import Path
16
- from typing import Any, Callable, Dict, Iterable, List, Optional
17
+ from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional
18
+
19
+ from latticeai.core.quiet import quiet
20
+
21
+ from .timeutil import now_iso as _now
22
+ from .workspace_graph_trace import WorkspaceGraphTrace
23
+ from .workspace_memory import WorkspaceMemory
24
+ from .workspace_os_constants import (
25
+ DEFAULT_WORKSPACE_ID,
26
+ EXECUTION_EVENT_TYPES,
27
+ MEMORY_KINDS,
28
+ ONBOARDING_STEPS,
29
+ ROLE_PERMISSIONS,
30
+ WORKSPACE_AREAS,
31
+ WORKSPACE_OS_VERSION,
32
+ WORKSPACE_PERMISSIONS,
33
+ WORKSPACE_ROLES,
34
+ WORKSPACE_TYPES,
35
+ )
36
+ from .workspace_os_state import default_state, migrate_workspaces, new_workspace_record
17
37
 
18
38
  # Extracted pure helpers (keeps this module smaller and focused on the store).
19
39
  from .workspace_os_utils import (
@@ -24,16 +44,16 @@ from .workspace_os_utils import (
24
44
  _safe_slug,
25
45
  remove_skill_directory,
26
46
  )
27
- from .timeutil import now_iso as _now
28
- from .workspace_permissions import WorkspacePermissionManager, _member_role # type: ignore
29
- from .workspace_timeline import WorkspaceTimeline
47
+ from .workspace_permissions import ( # type: ignore
48
+ WorkspacePermissionManager,
49
+ _member_role,
50
+ )
30
51
  from .workspace_plugins import WorkspacePluginManager
31
- from .workspace_memory import WorkspaceMemory
32
- from .workspace_snapshots import WorkspaceSnapshots
33
- from .workspace_graph_trace import WorkspaceGraphTrace
34
52
  from .workspace_review_items import WorkspaceReviewItems
35
53
  from .workspace_runs import WorkspaceRuns
36
54
  from .workspace_skills import WorkspaceSkills
55
+ from .workspace_snapshots import WorkspaceSnapshots
56
+ from .workspace_timeline import WorkspaceTimeline
37
57
 
38
58
  __all__ = [
39
59
  "WORKSPACE_OS_VERSION",
@@ -50,120 +70,16 @@ __all__ = [
50
70
  "remove_skill_directory",
51
71
  ]
52
72
 
53
- WORKSPACE_OS_VERSION = "10.0.0"
54
-
55
- # Workspace types separate single-user Personal workspaces from shared
56
- # Organization workspaces. Both keep the same local-first JSON store; the type
57
- # only changes how membership and permissions are evaluated.
58
- WORKSPACE_TYPES = ("personal", "organization")
59
-
60
- DEFAULT_WORKSPACE_ID = "personal"
61
-
62
- # Role hierarchy for Organization workspaces. Personal workspaces always grant
63
- # their single local user the owner role.
64
- WORKSPACE_ROLES = ("owner", "admin", "member", "viewer")
65
-
66
- # Capability-style permissions. Kept intentionally small so Enterprise editions
67
- # can layer advanced RBAC/ABAC on top via the enterprise seam without changing
68
- # these community defaults.
69
- WORKSPACE_PERMISSIONS = ("read", "write", "manage_members", "manage_workspace")
70
-
71
- ROLE_PERMISSIONS: Dict[str, set] = {
72
- "owner": {"read", "write", "manage_members", "manage_workspace"},
73
- "admin": {"read", "write", "manage_members", "manage_workspace"},
74
- "member": {"read", "write"},
75
- "viewer": {"read"},
76
- }
77
-
78
- WORKSPACE_AREAS = [
79
- "graph",
80
- "snapshot",
81
- "memory",
82
- "agent",
83
- "workflow",
84
- "plugins",
85
- "skills",
86
- "marketplace",
87
- "timeline",
88
- ]
89
73
 
90
- ONBOARDING_STEPS = [
91
- "account",
92
- "admin",
93
- "hardware",
94
- "model_recommendation",
95
- "model_install",
96
- "model_connection",
97
- "folder_connection",
98
- "first_question",
99
- "complete",
100
- ]
101
74
 
102
- MEMORY_KINDS = {
103
- "short_term",
104
- "workspace",
105
- "preferences",
106
- "decisions",
107
- "working_style",
108
- "frequently_used_tools",
109
- "long_term",
110
- }
111
-
112
- EXECUTION_EVENT_TYPES = {
113
- "agent_started",
114
- "handoff_created",
115
- "handoff_accepted",
116
- "handoff_completed",
117
- "review_requested",
118
- "review_approved",
119
- "review_rejected",
120
- "retry_requested",
121
- "workflow_started",
122
- "workflow_completed",
123
- "plugin_started",
124
- "plugin_completed",
125
- "execution_failed",
126
- "execution_cancelled",
127
- "execution_interrupted",
128
- }
129
-
130
- DEFAULT_AGENTS = [
131
- {
132
- "id": "agent:planner",
133
- "name": "Planner",
134
- "role": "Breaks workspace goals into executable plans.",
135
- "status": "available",
136
- "relationships": ["agent:executor", "agent:reviewer"],
137
- },
138
- {
139
- "id": "agent:executor",
140
- "name": "Executor",
141
- "role": "Runs approved tool and code workflows.",
142
- "status": "available",
143
- "relationships": ["agent:planner", "agent:reviewer"],
144
- },
145
- {
146
- "id": "agent:reviewer",
147
- "name": "Reviewer",
148
- "role": "Checks outputs, tests, and regressions.",
149
- "status": "available",
150
- "relationships": ["agent:executor", "agent:release"],
151
- },
152
- {
153
- "id": "agent:researcher",
154
- "name": "Researcher",
155
- "role": "Finds and curates relevant workspace knowledge.",
156
- "status": "available",
157
- "relationships": ["agent:planner"],
158
- },
159
- {
160
- "id": "agent:release",
161
- "name": "Release Agent",
162
- "role": "Coordinates versioning, packaging, and release checks.",
163
- "status": "available",
164
- "relationships": ["agent:reviewer"],
165
- },
166
- ]
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
167
83
 
168
84
 
169
85
  class WorkspaceOSStore:
@@ -193,7 +109,13 @@ class WorkspaceOSStore:
193
109
  self.review_items = WorkspaceReviewItems(self)
194
110
  self.skills = WorkspaceSkills(self)
195
111
 
196
- def _connect_state_db(self) -> sqlite3.Connection:
112
+ @contextmanager
113
+ def _connect_state_db(self) -> Iterator[sqlite3.Connection]:
114
+ """Transactional connection that is closed when the block exits.
115
+
116
+ ``with sqlite3.connect(...)`` commits but never closes; see
117
+ :meth:`lattice_brain.storage.base.StorageEngine.session`.
118
+ """
197
119
  conn = sqlite3.connect(self.sqlite_path)
198
120
  conn.execute("PRAGMA journal_mode=WAL")
199
121
  conn.execute(
@@ -204,7 +126,26 @@ class WorkspaceOSStore:
204
126
  "CREATE TABLE IF NOT EXISTS workspace_os_meta ("
205
127
  "key TEXT PRIMARY KEY, value TEXT NOT NULL)"
206
128
  )
207
- return conn
129
+ try:
130
+ with conn:
131
+ yield conn
132
+ finally:
133
+ conn.close()
134
+
135
+ # ── moved to workspace_os_state.py (10.2.0) ───────────────────────────────
136
+ # Kept as delegators: `_default_state` and `_migrate_workspaces` are called
137
+ # by name in tests and by subclasses, and `_new_workspace_record` is used
138
+ # across the manager classes. The behaviour lives in one place now; these
139
+ # keep every existing call site working.
140
+ @staticmethod
141
+ def _new_workspace_record(**kwargs) -> Dict[str, Any]:
142
+ return new_workspace_record(**kwargs)
143
+
144
+ def _migrate_workspaces(self, state: Dict[str, Any]) -> Dict[str, Any]:
145
+ return migrate_workspaces(state)
146
+
147
+ def _default_state(self) -> Dict[str, Any]:
148
+ return default_state()
208
149
 
209
150
  def _load_sqlite_state(self) -> Optional[Dict[str, Any]]:
210
151
  try:
@@ -243,82 +184,10 @@ class WorkspaceOSStore:
243
184
  if not any(self.state_path.parent.glob(f"{self.state_path.name}.pre-sqlite.*.json")):
244
185
  shutil.copy2(self.state_path, backup)
245
186
  except Exception:
246
- pass
187
+ quiet()
247
188
  return _deep_merge(default, loaded)
248
189
 
249
- @staticmethod
250
- def _new_workspace_record(
251
- *,
252
- workspace_id: str,
253
- name: str,
254
- workspace_type: str,
255
- owner_user_id: Optional[str],
256
- settings: Optional[Dict[str, Any]] = None,
257
- members: Optional[List[Dict[str, Any]]] = None,
258
- ) -> Dict[str, Any]:
259
- if workspace_type not in WORKSPACE_TYPES:
260
- raise ValueError(f"unknown workspace type: {workspace_type}")
261
- now = _now()
262
- member_list = list(members or [])
263
- if owner_user_id and not any(m.get("user_id") == owner_user_id for m in member_list):
264
- member_list.insert(0, {"user_id": owner_user_id, "role": "owner", "added_at": now})
265
- return {
266
- "workspace_id": workspace_id,
267
- "id": workspace_id,
268
- "name": name,
269
- "type": workspace_type,
270
- "owner_user_id": owner_user_id,
271
- "members": member_list,
272
- "roles": {role: sorted(perms) for role, perms in ROLE_PERMISSIONS.items()},
273
- "status": "active",
274
- "areas": list(WORKSPACE_AREAS),
275
- "settings": settings or {},
276
- "created_at": now,
277
- "updated_at": now,
278
- }
279
190
 
280
- def _migrate_workspaces(self, state: Dict[str, Any]) -> Dict[str, Any]:
281
- """Non-destructive upgrade of legacy workspace entries to the v1.1 model.
282
-
283
- Existing 1.0.x state files stored minimal ``{id,name,type,areas}`` dicts.
284
- This backfills membership/role/timestamp fields without dropping data and
285
- guarantees the default Personal workspace always exists.
286
- """
287
- workspaces = state.get("workspaces")
288
- if not isinstance(workspaces, dict):
289
- workspaces = {}
290
- migrated: Dict[str, Any] = {}
291
- for ws_id, ws in workspaces.items():
292
- if not isinstance(ws, dict):
293
- continue
294
- ws_type = ws.get("type") if ws.get("type") in WORKSPACE_TYPES else "organization"
295
- if ws_id == DEFAULT_WORKSPACE_ID:
296
- ws_type = "personal"
297
- base = self._new_workspace_record(
298
- workspace_id=ws_id,
299
- name=ws.get("name") or ws_id,
300
- workspace_type=ws_type,
301
- owner_user_id=ws.get("owner_user_id"),
302
- settings=ws.get("settings") or {},
303
- members=ws.get("members") if isinstance(ws.get("members"), list) else None,
304
- )
305
- # Preserve any pre-existing timestamps / status from the loaded record.
306
- base["created_at"] = ws.get("created_at") or base["created_at"]
307
- base["updated_at"] = ws.get("updated_at") or base["updated_at"]
308
- base["status"] = ws.get("status") or base["status"]
309
- migrated[ws_id] = base
310
- if DEFAULT_WORKSPACE_ID not in migrated:
311
- migrated[DEFAULT_WORKSPACE_ID] = self._new_workspace_record(
312
- workspace_id=DEFAULT_WORKSPACE_ID,
313
- name="Personal Workspace",
314
- workspace_type="personal",
315
- owner_user_id=None,
316
- )
317
- state["workspaces"] = migrated
318
- active = state.get("active_workspace")
319
- if active not in migrated:
320
- state["active_workspace"] = DEFAULT_WORKSPACE_ID
321
- return state
322
191
 
323
192
  def migrate_workspace_identities(self, email_to_id: Dict[str, str]) -> int:
324
193
  """Rewrite workspace membership identities from legacy emails to UUIDs.
@@ -361,83 +230,6 @@ class WorkspaceOSStore:
361
230
  self.record_timeline_event("workspace", "identity_uuid_migrated", {"records": changed})
362
231
  return changed
363
232
 
364
- def _default_state(self) -> Dict[str, Any]:
365
- return {
366
- "version": WORKSPACE_OS_VERSION,
367
- "identity": "AI Workspace OS",
368
- "created_at": _now(),
369
- "updated_at": _now(),
370
- "active_workspace": DEFAULT_WORKSPACE_ID,
371
- "workspaces": {
372
- DEFAULT_WORKSPACE_ID: self._new_workspace_record(
373
- workspace_id=DEFAULT_WORKSPACE_ID,
374
- name="Personal Workspace",
375
- workspace_type="personal",
376
- owner_user_id=None,
377
- ),
378
- },
379
- "feature_flags": {
380
- "workspace_os": True,
381
- "graph_trace": True,
382
- "snapshots": True,
383
- "personal_memory": True,
384
- "multi_agent_graph": True,
385
- "workflow_graph": True,
386
- "skill_marketplace": True,
387
- "local_computer_memory": False,
388
- "organization_workspaces": True,
389
- "enterprise_seam": True,
390
- "plugin_sdk": True,
391
- "workflow_designer": True,
392
- "multi_agent_runtime": True,
393
- "realtime_collaboration": True,
394
- "agent_handoff": True,
395
- "agent_context_packets": True,
396
- "review_retry_loops": True,
397
- "timeline_replay": True,
398
- "agent_memory": True,
399
- "agent_planning": True,
400
- "marketplace_foundation": True,
401
- "realtime_execution_observability": True,
402
- },
403
- "onboarding": {
404
- "completed": False,
405
- "current_step": "account",
406
- "steps": {
407
- step: {
408
- "id": step,
409
- "status": "pending",
410
- "data": {},
411
- "error": "",
412
- "updated_at": None,
413
- }
414
- for step in ONBOARDING_STEPS
415
- },
416
- },
417
- "snapshots": [],
418
- "traces": [],
419
- "memories": [],
420
- "memory_snapshots": [],
421
- "agents": list(DEFAULT_AGENTS),
422
- "agent_runs": [],
423
- "handoffs": [],
424
- "workflows": [],
425
- "workflow_runs": [],
426
- "review_items": [],
427
- "skill_registry": {},
428
- "plugin_registry": {},
429
- "template_registry": {},
430
- "computer_memory": {
431
- "enabled": False,
432
- "approved": False,
433
- "approved_at": None,
434
- "approved_by": None,
435
- "scopes": ["Downloads", "Documents", "Repositories"],
436
- "activities": [],
437
- "notice": "Local Computer Memory is OFF by default and requires explicit approval.",
438
- },
439
- "timeline": [],
440
- }
441
233
 
442
234
  def load_state(self) -> Dict[str, Any]:
443
235
  default = self._default_state()
@@ -476,7 +268,7 @@ class WorkspaceOSStore:
476
268
  try:
477
269
  self.record_timeline_event(area, event_type, payload, workspace_id=workspace_id)
478
270
  except Exception:
479
- pass
271
+ quiet()
480
272
 
481
273
  def _emit_replayable_timeline_events(
482
274
  self,
@@ -1164,7 +956,7 @@ class WorkspaceOSStore:
1164
956
  inbound = [edge for edge in edges if edge.get("to") == node_id]
1165
957
  outbound = [edge for edge in edges if edge.get("from") == node_id]
1166
958
  except Exception:
1167
- pass
959
+ quiet()
1168
960
 
1169
961
  related_ids = []
1170
962
  for edge in inbound + outbound:
@@ -0,0 +1,126 @@
1
+ """Workspace OS vocabulary: types, roles, permissions, areas, defaults.
2
+
3
+ Split out of ``workspace_os.py`` in 10.2.0 so the store module holds behaviour
4
+ and this one holds the vocabulary that behaviour is written against. Every name
5
+ is re-exported from ``workspace_os`` — the import path callers use has not
6
+ changed.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Dict
12
+
13
+ WORKSPACE_OS_VERSION = "10.3.0"
14
+
15
+ # Workspace types separate single-user Personal workspaces from shared
16
+ # Organization workspaces. Both keep the same local-first JSON store; the type
17
+ # only changes how membership and permissions are evaluated.
18
+ WORKSPACE_TYPES = ("personal", "organization")
19
+
20
+ DEFAULT_WORKSPACE_ID = "personal"
21
+
22
+ # Role hierarchy for Organization workspaces. Personal workspaces always grant
23
+ # their single local user the owner role.
24
+ WORKSPACE_ROLES = ("owner", "admin", "member", "viewer")
25
+
26
+ # Capability-style permissions. Kept intentionally small so Enterprise editions
27
+ # can layer advanced RBAC/ABAC on top via the enterprise seam without changing
28
+ # these community defaults.
29
+ WORKSPACE_PERMISSIONS = ("read", "write", "manage_members", "manage_workspace")
30
+
31
+ ROLE_PERMISSIONS: Dict[str, set] = {
32
+ "owner": {"read", "write", "manage_members", "manage_workspace"},
33
+ "admin": {"read", "write", "manage_members", "manage_workspace"},
34
+ "member": {"read", "write"},
35
+ "viewer": {"read"},
36
+ }
37
+
38
+ WORKSPACE_AREAS = [
39
+ "graph",
40
+ "snapshot",
41
+ "memory",
42
+ "agent",
43
+ "workflow",
44
+ "plugins",
45
+ "skills",
46
+ "marketplace",
47
+ "timeline",
48
+ ]
49
+
50
+ ONBOARDING_STEPS = [
51
+ "account",
52
+ "admin",
53
+ "hardware",
54
+ "model_recommendation",
55
+ "model_install",
56
+ "model_connection",
57
+ "folder_connection",
58
+ "first_question",
59
+ "complete",
60
+ ]
61
+
62
+ MEMORY_KINDS = {
63
+ "short_term",
64
+ "workspace",
65
+ "preferences",
66
+ "decisions",
67
+ "working_style",
68
+ "frequently_used_tools",
69
+ "long_term",
70
+ }
71
+
72
+ EXECUTION_EVENT_TYPES = {
73
+ "agent_started",
74
+ "handoff_created",
75
+ "handoff_accepted",
76
+ "handoff_completed",
77
+ "review_requested",
78
+ "review_approved",
79
+ "review_rejected",
80
+ "retry_requested",
81
+ "workflow_started",
82
+ "workflow_completed",
83
+ "plugin_started",
84
+ "plugin_completed",
85
+ "execution_failed",
86
+ "execution_cancelled",
87
+ "execution_interrupted",
88
+ }
89
+
90
+ DEFAULT_AGENTS = [
91
+ {
92
+ "id": "agent:planner",
93
+ "name": "Planner",
94
+ "role": "Breaks workspace goals into executable plans.",
95
+ "status": "available",
96
+ "relationships": ["agent:executor", "agent:reviewer"],
97
+ },
98
+ {
99
+ "id": "agent:executor",
100
+ "name": "Executor",
101
+ "role": "Runs approved tool and code workflows.",
102
+ "status": "available",
103
+ "relationships": ["agent:planner", "agent:reviewer"],
104
+ },
105
+ {
106
+ "id": "agent:reviewer",
107
+ "name": "Reviewer",
108
+ "role": "Checks outputs, tests, and regressions.",
109
+ "status": "available",
110
+ "relationships": ["agent:executor", "agent:release"],
111
+ },
112
+ {
113
+ "id": "agent:researcher",
114
+ "name": "Researcher",
115
+ "role": "Finds and curates relevant workspace knowledge.",
116
+ "status": "available",
117
+ "relationships": ["agent:planner"],
118
+ },
119
+ {
120
+ "id": "agent:release",
121
+ "name": "Release Agent",
122
+ "role": "Coordinates versioning, packaging, and release checks.",
123
+ "status": "available",
124
+ "relationships": ["agent:reviewer"],
125
+ },
126
+ ]