ltcai 9.9.9 → 10.2.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.
- package/README.md +51 -38
- package/docs/CHANGELOG.md +197 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/HYBRID_CLOUD_KG_STREAMING.md +101 -0
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/kg-schema.md +1 -1
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/archive.py +5 -4
- package/lattice_brain/conversations.py +14 -3
- package/lattice_brain/embeddings.py +12 -2
- package/lattice_brain/graph/_kg_common.py +5 -5
- package/lattice_brain/graph/_kg_fsutil.py +4 -3
- package/lattice_brain/graph/discovery.py +4 -3
- package/lattice_brain/graph/discovery_index.py +0 -1
- package/lattice_brain/graph/documents.py +3 -2
- package/lattice_brain/graph/fusion.py +4 -0
- package/lattice_brain/graph/ingest.py +12 -2
- package/lattice_brain/graph/projection.py +3 -2
- package/lattice_brain/graph/provenance.py +5 -3
- package/lattice_brain/graph/rerank.py +4 -1
- package/lattice_brain/graph/retrieval.py +0 -1
- package/lattice_brain/graph/retrieval_docgen.py +0 -1
- package/lattice_brain/graph/retrieval_reads.py +0 -1
- package/lattice_brain/graph/retrieval_vector.py +0 -1
- package/lattice_brain/graph/schema.py +4 -3
- package/lattice_brain/graph/store.py +18 -4
- package/lattice_brain/graph/write_master.py +46 -1
- package/lattice_brain/ingestion.py +4 -1
- package/lattice_brain/portability.py +5 -2
- package/lattice_brain/quality.py +12 -5
- package/lattice_brain/quiet.py +43 -0
- package/lattice_brain/runtime/agent_runtime.py +12 -8
- package/lattice_brain/runtime/hooks.py +2 -1
- package/lattice_brain/runtime/multi_agent.py +2 -3
- package/lattice_brain/sensitivity.py +94 -0
- package/lattice_brain/storage/base.py +30 -2
- package/lattice_brain/storage/migration.py +3 -2
- package/lattice_brain/storage/postgres.py +2 -2
- package/lattice_brain/storage/sqlite.py +6 -4
- package/lattice_brain/workflow.py +4 -2
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/admin.py +1 -1
- package/latticeai/api/agents.py +4 -2
- package/latticeai/api/auth.py +5 -1
- package/latticeai/api/automation_intelligence.py +2 -1
- package/latticeai/api/browser.py +3 -2
- package/latticeai/api/chat.py +28 -17
- package/latticeai/api/chat_agent_http.py +22 -8
- package/latticeai/api/chat_contracts.py +4 -0
- package/latticeai/api/chat_documents.py +6 -2
- package/latticeai/api/chat_hybrid.py +82 -0
- package/latticeai/api/computer_use.py +8 -3
- package/latticeai/api/knowledge_graph.py +1 -1
- package/latticeai/api/mcp.py +4 -4
- package/latticeai/api/models.py +5 -2
- package/latticeai/api/network_boundary.py +220 -0
- package/latticeai/api/permissions.py +0 -1
- package/latticeai/api/realtime.py +1 -1
- package/latticeai/api/security_dashboard.py +1 -1
- package/latticeai/api/setup.py +16 -3
- package/latticeai/api/static_routes.py +2 -1
- package/latticeai/api/tools.py +12 -8
- package/latticeai/api/voice_capture.py +3 -1
- package/latticeai/api/workflow_designer.py +1 -1
- package/latticeai/api/workspace.py +1 -2
- package/latticeai/app_factory.py +131 -78
- package/latticeai/cli/entrypoint.py +6 -4
- package/latticeai/core/agent.py +55 -495
- package/latticeai/core/agent_eval.py +2 -2
- package/latticeai/core/agent_helpers.py +493 -0
- package/latticeai/core/agent_prompts.py +0 -1
- package/latticeai/core/agent_registry.py +3 -1
- package/latticeai/core/agent_state.py +41 -0
- package/latticeai/core/audit.py +1 -1
- package/latticeai/core/builtin_hooks.py +2 -1
- package/latticeai/core/config.py +0 -1
- package/latticeai/core/embedding_providers.py +12 -1
- package/latticeai/core/file_generation.py +3 -0
- package/latticeai/core/invitations.py +4 -1
- package/latticeai/core/io_utils.py +3 -1
- package/latticeai/core/legacy_compatibility.py +1 -2
- package/latticeai/core/local_embeddings.py +12 -1
- package/latticeai/core/marketplace.py +1 -2
- package/latticeai/core/mcp_registry.py +0 -1
- package/latticeai/core/model_compat.py +1 -1
- package/latticeai/core/model_resolution.py +1 -1
- package/latticeai/core/network_boundary.py +168 -0
- package/latticeai/core/oidc.py +3 -0
- package/latticeai/core/permission_mode.py +6 -6
- package/latticeai/core/plugins.py +3 -2
- package/latticeai/core/policy.py +0 -1
- package/latticeai/core/quiet.py +84 -0
- package/latticeai/core/realtime.py +3 -2
- package/latticeai/core/run_store.py +4 -2
- package/latticeai/core/security.py +4 -0
- package/latticeai/core/users.py +5 -3
- package/latticeai/core/workspace_graph_trace.py +3 -0
- package/latticeai/core/workspace_os.py +65 -273
- package/latticeai/core/workspace_os_constants.py +126 -0
- package/latticeai/core/workspace_os_state.py +180 -0
- package/latticeai/core/workspace_os_utils.py +3 -1
- package/latticeai/core/workspace_permissions.py +1 -0
- package/latticeai/core/workspace_snapshots.py +3 -1
- package/latticeai/core/workspace_timeline.py +3 -1
- package/latticeai/integrations/telegram_bot.py +25 -16
- package/latticeai/models/router.py +6 -3
- package/latticeai/runtime/access_runtime.py +3 -1
- package/latticeai/runtime/audit_runtime.py +3 -2
- package/latticeai/runtime/chat_wiring.py +4 -1
- package/latticeai/runtime/history_runtime.py +1 -1
- package/latticeai/runtime/lifespan_runtime.py +3 -1
- package/latticeai/runtime/network_boundary_wiring.py +124 -0
- package/latticeai/runtime/persistence_runtime.py +3 -1
- package/latticeai/runtime/router_registration.py +11 -1
- package/latticeai/services/architecture_readiness.py +1 -2
- package/latticeai/services/change_proposals.py +2 -1
- package/latticeai/services/cloud_egress_audit.py +85 -0
- package/latticeai/services/cloud_extraction.py +129 -0
- package/latticeai/services/cloud_streaming.py +266 -0
- package/latticeai/services/cloud_token_guard.py +84 -0
- package/latticeai/services/command_center.py +2 -1
- package/latticeai/services/folder_watch.py +3 -0
- package/latticeai/services/funnel_metrics.py +3 -1
- package/latticeai/services/hybrid_chat.py +265 -0
- package/latticeai/services/hybrid_context.py +228 -0
- package/latticeai/services/hybrid_policy.py +178 -0
- package/latticeai/services/memory_service.py +1 -1
- package/latticeai/services/model_catalog.py +10 -1
- package/latticeai/services/model_engines.py +35 -14
- package/latticeai/services/model_loading.py +3 -2
- package/latticeai/services/model_runtime.py +68 -17
- package/latticeai/services/multimodal_streaming.py +123 -0
- package/latticeai/services/network_boundary_service.py +154 -0
- package/latticeai/services/openai_compatible_adapter.py +100 -0
- package/latticeai/services/p_reinforce.py +4 -0
- package/latticeai/services/platform_runtime.py +9 -4
- package/latticeai/services/process_audit.py +0 -1
- package/latticeai/services/product_readiness.py +1 -1
- package/latticeai/services/run_executor.py +3 -2
- package/latticeai/services/search_service.py +1 -4
- package/latticeai/services/setup_detection.py +2 -1
- package/latticeai/services/tool_dispatch.py +7 -2
- package/latticeai/services/upload_service.py +2 -1
- package/latticeai/setup/auto_setup.py +10 -7
- package/latticeai/setup/wizard.py +15 -11
- package/latticeai/tools/__init__.py +3 -3
- package/latticeai/tools/commands.py +7 -7
- package/latticeai/tools/computer.py +3 -2
- package/latticeai/tools/documents.py +10 -9
- package/latticeai/tools/filesystem.py +7 -4
- package/latticeai/tools/knowledge.py +2 -0
- package/latticeai/tools/local_files.py +1 -1
- package/latticeai/tools/network.py +2 -1
- package/package.json +6 -4
- package/scripts/bench_agent_smoke.py +0 -1
- package/scripts/bench_models.py +0 -1
- package/scripts/brain_quality_eval.py +7 -2
- package/scripts/bump_version.py +2 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/migrate_brain_storage.py +5 -1
- package/scripts/profile_kg.py +2 -7
- package/scripts/verify_hf_model_registry.py +2 -2
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +37 -37
- package/static/app/assets/Act-CbdGD-2i.js +1 -0
- package/static/app/assets/AdminConsole-LgCkXpnf.js +1 -0
- package/static/app/assets/Brain-CoPGJI1L.js +321 -0
- package/static/app/assets/BrainHome-gVnaxSwp.js +2 -0
- package/static/app/assets/BrainSignals-ChxAYHtj.js +1 -0
- package/static/app/assets/Capture-DBtgkHZg.js +1 -0
- package/static/app/assets/CommandPalette-Ovtv5I0Y.js +1 -0
- package/static/app/assets/Library-CBia2Fvm.js +1 -0
- package/static/app/assets/LivingBrain-CNz-6NSd.js +1 -0
- package/static/app/assets/{ProductFlow-cB3EFinZ.js → ProductFlow-ePX-Y73J.js} +1 -1
- package/static/app/assets/ReviewCard-C4mpvkwH.js +3 -0
- package/static/app/assets/System-BvWNK1zc.js +1 -0
- package/static/app/assets/activity-CiauPV_3.js +1 -0
- package/static/app/assets/{bot-DtKkLfXj.js → bot-Dwct-Q1x.js} +1 -1
- package/static/app/assets/brain-BKDW1F0T.js +1 -0
- package/static/app/assets/{button-BTxZDMFJ.js → button-CCB9Kuw7.js} +1 -1
- package/static/app/assets/{circle-pause--qxF9-EO.js → circle-pause-DNa8WHC5.js} +1 -1
- package/static/app/assets/{circle-play-89x3S6jm.js → circle-play-8jmxn5mf.js} +1 -1
- package/static/app/assets/{cpu-DTUI63vo.js → cpu-mxvF3V1I.js} +1 -1
- package/static/app/assets/{download-EJS5_O0f.js → download--SmCcx0p.js} +1 -1
- package/static/app/assets/{folder-open-BL9zYTnc.js → folder-open-D4Wy5roo.js} +1 -1
- package/static/app/assets/{hard-drive-BFnwi1Lu.js → hard-drive-BwQcSPlS.js} +1 -1
- package/static/app/assets/index-CQWdDU3z.css +2 -0
- package/static/app/assets/index-DDV2YZwM.js +10 -0
- package/static/app/assets/input-DFhSjmLS.js +1 -0
- package/static/app/assets/{network-zKa3jAwl.js → network-Bts7VO94.js} +1 -1
- package/static/app/assets/primitives-BuSMEJY8.js +1 -0
- package/static/app/assets/search-DZzxhWaQ.js +1 -0
- package/static/app/assets/{shield-alert-CpHeCsaF.js → shield-alert-BfTO6X_G.js} +1 -1
- package/static/app/assets/textarea-BjctW1oh.js +1 -0
- package/static/app/assets/{useFocusTrap-58TNCONM.js → useFocusTrap-CE43-LrA.js} +1 -1
- package/static/app/assets/{useQuery-CcVlXlBd.js → useQuery-Bv3ejLL5.js} +1 -1
- package/static/app/assets/{users-C0cFMj6o.js → users-CsNqLZAj.js} +1 -1
- package/static/app/assets/utils-KFFdVG_t.js +7 -0
- package/static/app/assets/workspace-wdCvdyPF.js +1 -0
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/static/app/assets/Act-BFbpl2_Y.js +0 -1
- package/static/app/assets/AdminConsole-DaZPha9Y.js +0 -1
- package/static/app/assets/Brain-DGrV0heZ.js +0 -321
- package/static/app/assets/BrainHome-Re6Zxh_W.js +0 -2
- package/static/app/assets/BrainSignals-BQ11jDpJ.js +0 -1
- package/static/app/assets/Capture-DRaf1zLH.js +0 -1
- package/static/app/assets/CommandPalette-DAKPm4uJ.js +0 -1
- package/static/app/assets/LanguageSwitcher-BgTwHoWv.js +0 -1
- package/static/app/assets/Library-BVtrSt12.js +0 -1
- package/static/app/assets/LivingBrain-7glOmK0R.js +0 -1
- package/static/app/assets/ReviewCard-CShhHS-w.js +0 -3
- package/static/app/assets/System-B4nQDy8a.js +0 -1
- package/static/app/assets/brain-wVV63_1z.js +0 -1
- package/static/app/assets/index-BFtDYI6l.js +0 -10
- package/static/app/assets/index-BY9bpxyx.css +0 -2
- package/static/app/assets/input-DEz5UjBz.js +0 -1
- package/static/app/assets/primitives-jNrZm2O9.js +0 -1
- package/static/app/assets/search-ku6-_6wY.js +0 -1
- package/static/app/assets/textarea-DpcQkn75.js +0 -1
- package/static/app/assets/utils-DYf7pqrR.js +0 -7
- package/static/app/assets/workspace-CjthHsLN.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 .
|
|
28
|
-
|
|
29
|
-
|
|
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 = "9.9.9"
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.2.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
|
+
]
|