hyperagents 1.2.3rc5.post3__py3-none-any.whl
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.
- agents/__init__.py +31 -0
- agents/background_monitor.py +453 -0
- agents/learning.py +460 -0
- agents/planner.py +421 -0
- agents/transcriber.py +341 -0
- civilization/__init__.py +51 -0
- civilization/api/__init__.py +7 -0
- civilization/api/civilization_api.py +361 -0
- civilization/graph/__init__.py +19 -0
- civilization/graph/knowledge_linker.py +348 -0
- civilization/graph/org_graph.py +348 -0
- civilization/graph/process_graph.py +386 -0
- civilization/ingestion/__init__.py +20 -0
- civilization/ingestion/chunker.py +273 -0
- civilization/ingestion/document_ingestor.py +358 -0
- civilization/ingestion/embedder.py +262 -0
- civilization/ingestion/extractor.py +224 -0
- civilization/interview/__init__.py +19 -0
- civilization/interview/gap_detector.py +380 -0
- civilization/interview/interviewer.py +323 -0
- civilization/interview/questioner.py +363 -0
- civilization/retrieval/__init__.py +17 -0
- civilization/retrieval/civilization_rag.py +316 -0
- civilization/retrieval/context_injector.py +342 -0
- civilization/retrieval/relevance_ranker.py +287 -0
- civilization/schema.py +299 -0
- civilization/store.py +177 -0
- civilization/sync/__init__.py +16 -0
- civilization/sync/confluence_sync.py +317 -0
- civilization/sync/gdrive_sync.py +262 -0
- civilization/sync/notion_sync.py +237 -0
- civilization/versioning/__init__.py +19 -0
- civilization/versioning/diff_engine.py +351 -0
- civilization/versioning/staleness_detector.py +303 -0
- civilization/versioning/version_manager.py +293 -0
- cli/__init__.py +1 -0
- cli/doctor.py +334 -0
- cli/hyperclaw.py +1357 -0
- cli/onboarding.py +469 -0
- core/__init__.py +1 -0
- core/connectors/__init__.py +119 -0
- core/connectors/infrastructure.py +772 -0
- core/connectors/messaging.py +586 -0
- core/connectors/productivity.py +764 -0
- core/connectors/smarthome.py +528 -0
- core/connectors/social.py +730 -0
- core/hyperrouter/__init__.py +23 -0
- core/hyperrouter/bandit.py +218 -0
- core/hyperrouter/fast_loop.py +68 -0
- core/hyperrouter/slow_loop.py +143 -0
- core/hyperstate/__init__.py +24 -0
- core/hyperstate/certifier.py +154 -0
- core/hyperstate/schema.py +160 -0
- core/hyperstate/state_manager.py +103 -0
- core/hyperstate/store.py +163 -0
- core/providers/__init__.py +121 -0
- core/providers/embeddings.py +389 -0
- core/providers/image.py +534 -0
- core/providers/llm.py +1935 -0
- core/providers/search.py +608 -0
- core/providers/voice.py +474 -0
- hyperagents-1.2.3rc5.post3.dist-info/METADATA +469 -0
- hyperagents-1.2.3rc5.post3.dist-info/RECORD +361 -0
- hyperagents-1.2.3rc5.post3.dist-info/WHEEL +5 -0
- hyperagents-1.2.3rc5.post3.dist-info/entry_points.txt +6 -0
- hyperagents-1.2.3rc5.post3.dist-info/licenses/LICENSE +21 -0
- hyperagents-1.2.3rc5.post3.dist-info/top_level.txt +13 -0
- hyperclaw/__init__.py +67 -0
- hyperclaw/__main__.py +220 -0
- hyperclaw/agent.py +775 -0
- hyperclaw/agent_coordinator.py +577 -0
- hyperclaw/anthropic_params.py +225 -0
- hyperclaw/api_utils.py +85 -0
- hyperclaw/approval_telegram.py +209 -0
- hyperclaw/approval_terminal.py +80 -0
- hyperclaw/attachments.py +177 -0
- hyperclaw/branding.py +55 -0
- hyperclaw/brief/__init__.py +11 -0
- hyperclaw/brief/cli.py +204 -0
- hyperclaw/brief/collect.py +146 -0
- hyperclaw/brief/compose.py +333 -0
- hyperclaw/brief/diff.py +110 -0
- hyperclaw/brief/errors.py +99 -0
- hyperclaw/brief/google.py +269 -0
- hyperclaw/brief/google_auth.py +294 -0
- hyperclaw/brief/links.py +124 -0
- hyperclaw/brief/service.py +424 -0
- hyperclaw/brief/store.py +205 -0
- hyperclaw/brief/tasks.py +200 -0
- hyperclaw/chat_scope.py +115 -0
- hyperclaw/cli_tui.py +497 -0
- hyperclaw/client_guard.py +717 -0
- hyperclaw/connection_check.py +113 -0
- hyperclaw/cost_guard.py +1728 -0
- hyperclaw/default_config/agents.yaml +534 -0
- hyperclaw/default_config/hyperclaw.yaml +27 -0
- hyperclaw/default_config/models.yaml +161 -0
- hyperclaw/deployment.py +39 -0
- hyperclaw/digest/__init__.py +9 -0
- hyperclaw/digest/cli.py +117 -0
- hyperclaw/digest/errors.py +100 -0
- hyperclaw/digest/gitlab.py +187 -0
- hyperclaw/digest/http.py +113 -0
- hyperclaw/digest/redact.py +32 -0
- hyperclaw/digest/service.py +271 -0
- hyperclaw/digest/slack.py +223 -0
- hyperclaw/digest/state.py +124 -0
- hyperclaw/digest/summarize.py +198 -0
- hyperclaw/digest/tokens.py +143 -0
- hyperclaw/distribution.py +46 -0
- hyperclaw/documents.py +351 -0
- hyperclaw/feeds.py +339 -0
- hyperclaw/google_workspace/__init__.py +5 -0
- hyperclaw/google_workspace/api.py +151 -0
- hyperclaw/google_workspace/auth.py +397 -0
- hyperclaw/google_workspace/calendar.py +157 -0
- hyperclaw/google_workspace/cli.py +72 -0
- hyperclaw/google_workspace/drive.py +236 -0
- hyperclaw/google_workspace/errors.py +58 -0
- hyperclaw/google_workspace/gmail.py +295 -0
- hyperclaw/google_workspace/meet.py +122 -0
- hyperclaw/google_workspace/tools.py +319 -0
- hyperclaw/hyperspeed.py +57 -0
- hyperclaw/integrations_layer.py +1427 -0
- hyperclaw/live_state.py +188 -0
- hyperclaw/managed_config.py +245 -0
- hyperclaw/media_hub.py +179 -0
- hyperclaw/memory_manager.py +584 -0
- hyperclaw/model_catalog.py +551 -0
- hyperclaw/model_policy.py +211 -0
- hyperclaw/model_router.py +595 -0
- hyperclaw/model_selector.py +72 -0
- hyperclaw/naming.py +284 -0
- hyperclaw/notices.py +65 -0
- hyperclaw/oai_stream.py +106 -0
- hyperclaw/orchestrator.py +591 -0
- hyperclaw/outbox.py +82 -0
- hyperclaw/persona.py +367 -0
- hyperclaw/prometheus.py +219 -0
- hyperclaw/prompt_assembly.py +157 -0
- hyperclaw/provider_setup.py +146 -0
- hyperclaw/providers.py +340 -0
- hyperclaw/qualification.py +341 -0
- hyperclaw/qualification_keys/hyper-d292fd127cef5a3e.pub +1 -0
- hyperclaw/qualification_records/anthropic--claude-sonnet-5-5.json +14 -0
- hyperclaw/reasoning_display.py +35 -0
- hyperclaw/scheduler.py +454 -0
- hyperclaw/server.py +847 -0
- hyperclaw/setup.py +627 -0
- hyperclaw/skills.py +717 -0
- hyperclaw/solomon.py +442 -0
- hyperclaw/swarm.py +533 -0
- hyperclaw/taint.py +832 -0
- hyperclaw/team/__init__.py +28 -0
- hyperclaw/team/dispatcher.py +431 -0
- hyperclaw/team/genesis.py +106 -0
- hyperclaw/team/lead.py +110 -0
- hyperclaw/team/model.py +135 -0
- hyperclaw/team/morning.py +238 -0
- hyperclaw/team/repos.py +66 -0
- hyperclaw/team/roster.py +264 -0
- hyperclaw/team/specialist.py +235 -0
- hyperclaw/team/status.py +163 -0
- hyperclaw/team/watchers.py +112 -0
- hyperclaw/teamsetup/__init__.py +17 -0
- hyperclaw/teamsetup/checks.py +208 -0
- hyperclaw/teamsetup/item.py +391 -0
- hyperclaw/teamsetup/oauth_loopback.py +84 -0
- hyperclaw/teamsetup/onboard.py +550 -0
- hyperclaw/teamsetup/profile.py +82 -0
- hyperclaw/teamsetup/secrets.py +313 -0
- hyperclaw/teamsetup/selfcheck.py +295 -0
- hyperclaw/teamsetup/service.py +495 -0
- hyperclaw/teamsetup/slack_oauth.py +442 -0
- hyperclaw/teamsetup/tty.py +62 -0
- hyperclaw/telegram_bot.py +1106 -0
- hyperclaw/telegram_intake.py +126 -0
- hyperclaw/telegram_pairing.py +360 -0
- hyperclaw/terminal_provider.py +323 -0
- hyperclaw/tools/__init__.py +1 -0
- hyperclaw/tools/approval.py +949 -0
- hyperclaw/tools/args.py +212 -0
- hyperclaw/tools/catalog.py +244 -0
- hyperclaw/tools/classify.py +266 -0
- hyperclaw/tools/effects.py +724 -0
- hyperclaw/tools/egress.py +210 -0
- hyperclaw/tools/envelope.py +188 -0
- hyperclaw/tools/guard.py +367 -0
- hyperclaw/tools/ledger.py +339 -0
- hyperclaw/tools/receipts.py +70 -0
- hyperclaw/tools/registry.py +318 -0
- hyperclaw/tools/service_guard.py +151 -0
- hyperclaw/tools/surfaces.py +54 -0
- hyperclaw/tools/workspace.py +87 -0
- hyperclaw/trading/__init__.py +77 -0
- hyperclaw/truth_guard.py +791 -0
- hyperclaw/tts.py +124 -0
- hyperclaw/tui.py +4255 -0
- hyperclaw/tui_bridge.py +938 -0
- hyperclaw/unattended.py +60 -0
- hyperclaw/updates/__init__.py +54 -0
- hyperclaw/updates/check.py +131 -0
- hyperclaw/updates/index.py +178 -0
- hyperclaw/updates/install.py +110 -0
- hyperclaw/updates/managed.py +161 -0
- hyperclaw/updates/manifest.py +138 -0
- hyperclaw/updates/notices.py +86 -0
- hyperclaw/updates/paths.py +53 -0
- hyperclaw/updates/release.py +146 -0
- hyperclaw/updates/upgrade.py +253 -0
- hyperclaw/updates/versioning.py +104 -0
- hyperclaw/userconfig.py +119 -0
- hyperclaw/xai.py +83 -0
- integrations/__init__.py +31 -0
- integrations/automation/__init__.py +1 -0
- integrations/automation/make.py +87 -0
- integrations/automation/zapier.py +87 -0
- integrations/base.py +476 -0
- integrations/communication/__init__.py +1 -0
- integrations/communication/twilio.py +279 -0
- integrations/communication/zoom.py +290 -0
- integrations/data/__init__.py +1 -0
- integrations/data/google_analytics.py +135 -0
- integrations/data/postgres.py +182 -0
- integrations/data/supabase_connector.py +202 -0
- integrations/data/weather_feeds.py +450 -0
- integrations/developer/__init__.py +9 -0
- integrations/developer/github.py +406 -0
- integrations/developer/gitlab.py +298 -0
- integrations/enterprise/__init__.py +13 -0
- integrations/enterprise/confluence.py +266 -0
- integrations/enterprise/hubspot.py +293 -0
- integrations/enterprise/jira.py +314 -0
- integrations/enterprise/salesforce.py +286 -0
- integrations/finance/__init__.py +1 -0
- integrations/finance/polymarket_client.py +247 -0
- integrations/finance/quickbooks.py +281 -0
- integrations/finance/stripe.py +261 -0
- integrations/gateway.py +238 -0
- integrations/messaging/__init__.py +32 -0
- integrations/messaging/discord.py +159 -0
- integrations/messaging/email.py +401 -0
- integrations/messaging/imessage.py +443 -0
- integrations/messaging/signal.py +175 -0
- integrations/messaging/slack.py +217 -0
- integrations/messaging/sms.py +175 -0
- integrations/messaging/teams.py +208 -0
- integrations/messaging/telegram.py +260 -0
- integrations/messaging/whatsapp.py +203 -0
- integrations/productivity/__init__.py +17 -0
- integrations/productivity/airtable.py +217 -0
- integrations/productivity/asana.py +248 -0
- integrations/productivity/google/__init__.py +19 -0
- integrations/productivity/google/base.py +89 -0
- integrations/productivity/google/calendar.py +272 -0
- integrations/productivity/google/docs.py +202 -0
- integrations/productivity/google/drive.py +268 -0
- integrations/productivity/google/gmail.py +279 -0
- integrations/productivity/google/meet.py +218 -0
- integrations/productivity/google/sheets.py +222 -0
- integrations/productivity/google/tasks.py +199 -0
- integrations/productivity/linear.py +279 -0
- integrations/productivity/microsoft/__init__.py +13 -0
- integrations/productivity/microsoft/base.py +93 -0
- integrations/productivity/microsoft/calendar.py +207 -0
- integrations/productivity/microsoft/onedrive.py +222 -0
- integrations/productivity/microsoft/outlook.py +241 -0
- integrations/productivity/microsoft/sharepoint.py +211 -0
- integrations/productivity/notion.py +243 -0
- integrations/productivity/todoist.py +250 -0
- integrations/productivity/trello.py +244 -0
- integrations/storage/__init__.py +1 -0
- integrations/storage/box.py +279 -0
- integrations/storage/dropbox.py +215 -0
- integrations/telegram_inbound.py +179 -0
- integrations/telegram_poller.py +151 -0
- memory/__init__.py +1 -0
- memory/causal_graph.py +125 -0
- memory/impact_tracker.py +88 -0
- memory/vector_memory.py +436 -0
- models/__init__.py +12 -0
- models/chatjimmy_client.py +210 -0
- models/claude_client.py +235 -0
- models/claude_code_subagent.py +192 -0
- models/openai_client.py +120 -0
- models/router.py +162 -0
- recursive/discovery_loop.py +118 -0
- recursive/optimization_loop.py +135 -0
- recursive/validation_loop.py +38 -0
- security/__init__.py +1 -0
- security/audit_logger.py +106 -0
- security/filesystem_guard.py +100 -0
- security/hypershield.py +99 -0
- security/network_guard.py +97 -0
- security/policy_engine.py +198 -0
- swarm/__init__.py +1 -0
- swarm/agents/__init__.py +0 -0
- swarm/agents/base.py +230 -0
- swarm/agents/business/__init__.py +0 -0
- swarm/agents/business/counsel.py +31 -0
- swarm/agents/business/herald.py +32 -0
- swarm/agents/business/ledger.py +26 -0
- swarm/agents/business/nexus.py +30 -0
- swarm/agents/business/ops.py +30 -0
- swarm/agents/business/pipeline.py +28 -0
- swarm/agents/business/revenue.py +30 -0
- swarm/agents/business/sovereign.py +31 -0
- swarm/agents/business/strategos.py +27 -0
- swarm/agents/business/talent.py +27 -0
- swarm/agents/business/venture.py +32 -0
- swarm/agents/comms/__init__.py +1 -0
- swarm/agents/comms/cipher.py +32 -0
- swarm/agents/comms/echo_comms.py +31 -0
- swarm/agents/comms/envoy.py +31 -0
- swarm/agents/comms/herald_scheduler.py +33 -0
- swarm/agents/comms/pulse.py +29 -0
- swarm/agents/creative/__init__.py +0 -0
- swarm/agents/creative/author.py +27 -0
- swarm/agents/creative/lens.py +25 -0
- swarm/agents/executive/__init__.py +1 -0
- swarm/agents/intelligence/__init__.py +1 -0
- swarm/agents/intelligence/arbiter.py +30 -0
- swarm/agents/intelligence/sentinel.py +30 -0
- swarm/agents/media/__init__.py +0 -0
- swarm/agents/personal/__init__.py +0 -0
- swarm/agents/personal/atlas.py +27 -0
- swarm/agents/personal/hearth.py +26 -0
- swarm/agents/personal/midas.py +27 -0
- swarm/agents/personal/navigator.py +27 -0
- swarm/agents/personal/nourish.py +31 -0
- swarm/agents/personal/vitals.py +33 -0
- swarm/agents/recursive/__init__.py +0 -0
- swarm/agents/recursive/alchemist.py +73 -0
- swarm/agents/recursive/calibrator.py +45 -0
- swarm/agents/recursive/scout.py +97 -0
- swarm/agents/scientific/__init__.py +0 -0
- swarm/agents/scientific/cosmos.py +36 -0
- swarm/agents/scientific/gaia.py +26 -0
- swarm/agents/scientific/medicus.py +33 -0
- swarm/agents/scientific/oracle_agent.py +39 -0
- swarm/agents/scientific/scribe.py +39 -0
- swarm/agents/talent/__init__.py +0 -0
- swarm/agents/talent/deal.py +28 -0
- swarm/agents/talent/roster.py +29 -0
- swarm/agents/talent/scout.py +29 -0
- swarm/agents/talent/stage.py +27 -0
- swarm/agents/tech/__init__.py +0 -0
- swarm/agents/tech/aegis.py +28 -0
- swarm/agents/tech/bridge.py +28 -0
- swarm/agents/tech/forge.py +28 -0
- swarm/agents/trading/__init__.py +1 -0
- swarm/agents/trading/global_prediction_engine.py +611 -0
- swarm/agents/trading/polymarket_trader.py +165 -0
- swarm/agents/trading/prediction_strategist.py +218 -0
- swarm/autogen_bridge.py +68 -0
- swarm/bid_protocol.py +196 -0
- swarm/dispatcher.py +527 -0
- swarm/nexus.py +181 -0
- swarm/registry.py +112 -0
- telegram_listener.py +403 -0
- ui/tui/app.py +214 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified API for the Civilization Knowledge Layer.
|
|
3
|
+
Provides high-level operations for managing organizational knowledge.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
import logging
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Any, Callable
|
|
10
|
+
from uuid import UUID
|
|
11
|
+
|
|
12
|
+
from ..schema import (
|
|
13
|
+
CivilizationNode, NodeType, NodeStatus,
|
|
14
|
+
SOP, Role, Person, Checklist, Runbook, Workflow, OrgChart,
|
|
15
|
+
JobDescription, ClientProfile, Policy, KnowledgeArticle,
|
|
16
|
+
)
|
|
17
|
+
from ..store import CivilizationStore
|
|
18
|
+
from ..ingestion.document_ingestor import DocumentIngestor
|
|
19
|
+
from ..ingestion.embedder import CivilizationEmbedder
|
|
20
|
+
from ..interview.interviewer import Interviewer, InterviewSession
|
|
21
|
+
from ..interview.gap_detector import GapDetector, GapReport
|
|
22
|
+
from ..graph.org_graph import OrgGraph
|
|
23
|
+
from ..graph.process_graph import ProcessGraph
|
|
24
|
+
from ..graph.knowledge_linker import KnowledgeLinker, KnowledgeLink
|
|
25
|
+
from ..versioning.version_manager import VersionManager, NodeVersion
|
|
26
|
+
from ..versioning.staleness_detector import StalenessDetector, StalenessReport
|
|
27
|
+
from ..retrieval.civilization_rag import CivilizationRAG, RAGResult, RAGConfig
|
|
28
|
+
from ..retrieval.context_injector import ContextInjector, InjectionConfig
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class CivilizationStats:
|
|
35
|
+
"""Statistics about the civilization knowledge base."""
|
|
36
|
+
total_nodes: int = 0
|
|
37
|
+
by_type: dict[str, int] = field(default_factory=dict)
|
|
38
|
+
by_status: dict[str, int] = field(default_factory=dict)
|
|
39
|
+
stale_count: int = 0
|
|
40
|
+
unowned_count: int = 0
|
|
41
|
+
freshness_score: float = 0.0
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CivilizationAPI:
|
|
45
|
+
"""
|
|
46
|
+
High-level API for the Civilization Knowledge Layer.
|
|
47
|
+
Orchestrates all civilization components for a unified interface.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
org_id: str,
|
|
53
|
+
store: CivilizationStore | None = None,
|
|
54
|
+
embedder: CivilizationEmbedder | None = None,
|
|
55
|
+
):
|
|
56
|
+
self.org_id = org_id
|
|
57
|
+
self.store = store or CivilizationStore()
|
|
58
|
+
self.embedder = embedder or CivilizationEmbedder()
|
|
59
|
+
|
|
60
|
+
# Initialize components
|
|
61
|
+
self.ingestor = DocumentIngestor(org_id, self.embedder, store=self.store)
|
|
62
|
+
self.rag = CivilizationRAG(org_id, self.store, self.embedder)
|
|
63
|
+
self.context_injector = ContextInjector()
|
|
64
|
+
self.interviewer = Interviewer(org_id, self.store)
|
|
65
|
+
self.gap_detector = GapDetector(org_id, self.store)
|
|
66
|
+
self.version_manager = VersionManager(org_id, self.store)
|
|
67
|
+
self.staleness_detector = StalenessDetector(org_id)
|
|
68
|
+
self.knowledge_linker = KnowledgeLinker(org_id, self.store)
|
|
69
|
+
|
|
70
|
+
self._nodes_cache: dict[UUID, CivilizationNode] = {}
|
|
71
|
+
|
|
72
|
+
# ─── Node CRUD Operations ────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
async def create_node(
|
|
75
|
+
self,
|
|
76
|
+
node: CivilizationNode,
|
|
77
|
+
create_version: bool = True,
|
|
78
|
+
) -> CivilizationNode:
|
|
79
|
+
"""Create a new civilization node."""
|
|
80
|
+
# Generate embedding if not present
|
|
81
|
+
if not node.embedding:
|
|
82
|
+
text = self._get_node_text(node)
|
|
83
|
+
node.embedding = await self.embedder.embed(text)
|
|
84
|
+
|
|
85
|
+
# Save to store
|
|
86
|
+
saved = await self.store.save(node)
|
|
87
|
+
|
|
88
|
+
# Create initial version
|
|
89
|
+
if create_version:
|
|
90
|
+
self.version_manager.create_version(
|
|
91
|
+
saved,
|
|
92
|
+
change_summary="Initial creation",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
self._nodes_cache[saved.id] = saved
|
|
96
|
+
return saved
|
|
97
|
+
|
|
98
|
+
async def get_node(self, node_id: UUID) -> CivilizationNode | None:
|
|
99
|
+
"""Get a node by ID."""
|
|
100
|
+
if node_id in self._nodes_cache:
|
|
101
|
+
return self._nodes_cache[node_id]
|
|
102
|
+
|
|
103
|
+
node = await self.store.get(node_id, self.org_id)
|
|
104
|
+
if node:
|
|
105
|
+
self._nodes_cache[node_id] = node
|
|
106
|
+
return node
|
|
107
|
+
|
|
108
|
+
async def update_node(
|
|
109
|
+
self,
|
|
110
|
+
node: CivilizationNode,
|
|
111
|
+
change_summary: str | None = None,
|
|
112
|
+
bump_type: str = "patch",
|
|
113
|
+
) -> CivilizationNode:
|
|
114
|
+
"""Update an existing node."""
|
|
115
|
+
node.updated_at = datetime.utcnow()
|
|
116
|
+
|
|
117
|
+
# Regenerate embedding
|
|
118
|
+
text = self._get_node_text(node)
|
|
119
|
+
node.embedding = await self.embedder.embed(text)
|
|
120
|
+
|
|
121
|
+
# Create new version if changed
|
|
122
|
+
if self.version_manager.has_changes(node):
|
|
123
|
+
self.version_manager.create_version(
|
|
124
|
+
node,
|
|
125
|
+
bump_type=bump_type,
|
|
126
|
+
change_summary=change_summary,
|
|
127
|
+
)
|
|
128
|
+
node.version = self.version_manager.get_current_version(node.id)
|
|
129
|
+
|
|
130
|
+
# Save
|
|
131
|
+
saved = await self.store.save(node)
|
|
132
|
+
self._nodes_cache[saved.id] = saved
|
|
133
|
+
return saved
|
|
134
|
+
|
|
135
|
+
async def delete_node(self, node_id: UUID) -> bool:
|
|
136
|
+
"""Delete a node."""
|
|
137
|
+
success = await self.store.delete(node_id, self.org_id)
|
|
138
|
+
if success and node_id in self._nodes_cache:
|
|
139
|
+
del self._nodes_cache[node_id]
|
|
140
|
+
return success
|
|
141
|
+
|
|
142
|
+
async def list_nodes(
|
|
143
|
+
self,
|
|
144
|
+
node_type: NodeType | None = None,
|
|
145
|
+
limit: int = 100,
|
|
146
|
+
) -> list[CivilizationNode]:
|
|
147
|
+
"""List nodes, optionally filtered by type."""
|
|
148
|
+
if node_type:
|
|
149
|
+
return await self.store.list_by_type(self.org_id, node_type, limit)
|
|
150
|
+
return await self.store.list_all(self.org_id, limit)
|
|
151
|
+
|
|
152
|
+
# ─── Search & Retrieval ──────────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
async def search(
|
|
155
|
+
self,
|
|
156
|
+
query: str,
|
|
157
|
+
top_k: int = 5,
|
|
158
|
+
node_types: list[NodeType] | None = None,
|
|
159
|
+
) -> RAGResult:
|
|
160
|
+
"""Search for relevant nodes."""
|
|
161
|
+
config = RAGConfig(
|
|
162
|
+
top_k=top_k,
|
|
163
|
+
node_type_filters=node_types,
|
|
164
|
+
)
|
|
165
|
+
return await self.rag.query(query, config)
|
|
166
|
+
|
|
167
|
+
async def get_context_for_task(
|
|
168
|
+
self,
|
|
169
|
+
task_description: str,
|
|
170
|
+
max_tokens: int = 2000,
|
|
171
|
+
) -> str:
|
|
172
|
+
"""Get formatted context for an agent task."""
|
|
173
|
+
result = await self.search(task_description, top_k=5)
|
|
174
|
+
nodes = [rn.node for rn in result.retrieved_nodes]
|
|
175
|
+
|
|
176
|
+
config = InjectionConfig(max_tokens=max_tokens)
|
|
177
|
+
injection = self.context_injector.inject(nodes, config)
|
|
178
|
+
return injection.context
|
|
179
|
+
|
|
180
|
+
async def find_sop(self, task: str) -> list[SOP]:
|
|
181
|
+
"""Find SOPs relevant to a task."""
|
|
182
|
+
result = await self.rag.get_sop_for_task(task)
|
|
183
|
+
return [rn.node for rn in result.retrieved_nodes if isinstance(rn.node, SOP)]
|
|
184
|
+
|
|
185
|
+
async def find_runbook(self, incident: str) -> list[Runbook]:
|
|
186
|
+
"""Find runbooks for an incident."""
|
|
187
|
+
result = await self.rag.get_runbook_for_incident(incident)
|
|
188
|
+
return [rn.node for rn in result.retrieved_nodes if isinstance(rn.node, Runbook)]
|
|
189
|
+
|
|
190
|
+
# ─── Ingestion ───────────────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
async def ingest_document(
|
|
193
|
+
self,
|
|
194
|
+
content: str | bytes,
|
|
195
|
+
filename: str | None = None,
|
|
196
|
+
source: str | None = None,
|
|
197
|
+
source_url: str | None = None,
|
|
198
|
+
node_type: NodeType | None = None,
|
|
199
|
+
) -> CivilizationNode | None:
|
|
200
|
+
"""Ingest a document into the knowledge base."""
|
|
201
|
+
result = await self.ingestor.ingest(
|
|
202
|
+
content=content,
|
|
203
|
+
filename=filename,
|
|
204
|
+
source=source,
|
|
205
|
+
source_url=source_url,
|
|
206
|
+
node_type_hint=node_type,
|
|
207
|
+
)
|
|
208
|
+
if result.success and result.node_id:
|
|
209
|
+
return await self.get_node(result.node_id)
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
# ─── Interviews ──────────────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
def start_interview(
|
|
215
|
+
self,
|
|
216
|
+
node_type: NodeType,
|
|
217
|
+
subject: str,
|
|
218
|
+
) -> InterviewSession:
|
|
219
|
+
"""Start a knowledge elicitation interview."""
|
|
220
|
+
return self.interviewer.start_session(node_type, subject)
|
|
221
|
+
|
|
222
|
+
def submit_interview_response(
|
|
223
|
+
self,
|
|
224
|
+
session_id: UUID,
|
|
225
|
+
response: str,
|
|
226
|
+
) -> dict:
|
|
227
|
+
"""Submit a response to an interview question."""
|
|
228
|
+
return self.interviewer.submit_response(session_id, response)
|
|
229
|
+
|
|
230
|
+
async def complete_interview(
|
|
231
|
+
self,
|
|
232
|
+
session_id: UUID,
|
|
233
|
+
) -> CivilizationNode | None:
|
|
234
|
+
"""Complete an interview and create the node."""
|
|
235
|
+
node = self.interviewer.compile_to_node(session_id)
|
|
236
|
+
if node:
|
|
237
|
+
return await self.create_node(node)
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
# ─── Analysis & Health ───────────────────────────────────────────────────
|
|
241
|
+
|
|
242
|
+
async def analyze_gaps(self) -> GapReport:
|
|
243
|
+
"""Analyze knowledge base for gaps."""
|
|
244
|
+
nodes = await self.list_nodes(limit=1000)
|
|
245
|
+
return await self.gap_detector.analyze(nodes)
|
|
246
|
+
|
|
247
|
+
async def check_staleness(self) -> StalenessReport:
|
|
248
|
+
"""Check for stale content."""
|
|
249
|
+
nodes = await self.list_nodes(limit=1000)
|
|
250
|
+
return self.staleness_detector.check_nodes(nodes)
|
|
251
|
+
|
|
252
|
+
async def get_stats(self) -> CivilizationStats:
|
|
253
|
+
"""Get knowledge base statistics."""
|
|
254
|
+
stats = CivilizationStats()
|
|
255
|
+
|
|
256
|
+
# Count by type
|
|
257
|
+
stats.by_type = await self.store.count_by_type(self.org_id)
|
|
258
|
+
stats.total_nodes = sum(stats.by_type.values())
|
|
259
|
+
|
|
260
|
+
# Check staleness
|
|
261
|
+
nodes = await self.list_nodes(limit=1000)
|
|
262
|
+
staleness = self.staleness_detector.check_nodes(nodes)
|
|
263
|
+
stats.stale_count = staleness.stale_count
|
|
264
|
+
stats.freshness_score = staleness.freshness_score
|
|
265
|
+
|
|
266
|
+
# Count unowned
|
|
267
|
+
stats.unowned_count = sum(1 for n in nodes if not n.owner_id)
|
|
268
|
+
|
|
269
|
+
# Count by status
|
|
270
|
+
for node in nodes:
|
|
271
|
+
status = node.status.value
|
|
272
|
+
stats.by_status[status] = stats.by_status.get(status, 0) + 1
|
|
273
|
+
|
|
274
|
+
return stats
|
|
275
|
+
|
|
276
|
+
# ─── Graphs ──────────────────────────────────────────────────────────────
|
|
277
|
+
|
|
278
|
+
async def build_org_graph(self) -> OrgGraph:
|
|
279
|
+
"""Build organizational graph from person nodes."""
|
|
280
|
+
people = await self.list_nodes(NodeType.PERSON, limit=500)
|
|
281
|
+
return OrgGraph.from_people(self.org_id, [p for p in people if isinstance(p, Person)])
|
|
282
|
+
|
|
283
|
+
async def build_process_graph(self, sop_id: UUID) -> ProcessGraph | None:
|
|
284
|
+
"""Build process graph from an SOP."""
|
|
285
|
+
node = await self.get_node(sop_id)
|
|
286
|
+
if isinstance(node, SOP):
|
|
287
|
+
return ProcessGraph.from_sop(node)
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
async def detect_links(self) -> list[KnowledgeLink]:
|
|
291
|
+
"""Auto-detect links between nodes."""
|
|
292
|
+
nodes = await self.list_nodes(limit=1000)
|
|
293
|
+
links = self.knowledge_linker.detect_links(nodes)
|
|
294
|
+
self.knowledge_linker.bulk_add_links(links)
|
|
295
|
+
return links
|
|
296
|
+
|
|
297
|
+
# ─── Versioning ──────────────────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
def get_node_history(self, node_id: UUID) -> list[dict]:
|
|
300
|
+
"""Get version history for a node."""
|
|
301
|
+
return self.version_manager.get_version_timeline(node_id)
|
|
302
|
+
|
|
303
|
+
async def restore_version(
|
|
304
|
+
self,
|
|
305
|
+
node_id: UUID,
|
|
306
|
+
version: str,
|
|
307
|
+
) -> CivilizationNode | None:
|
|
308
|
+
"""Restore a node to a previous version."""
|
|
309
|
+
node = self.version_manager.restore_version(node_id, version)
|
|
310
|
+
if node:
|
|
311
|
+
return await self.update_node(node, f"Restored to version {version}")
|
|
312
|
+
return None
|
|
313
|
+
|
|
314
|
+
# ─── Helpers ─────────────────────────────────────────────────────────────
|
|
315
|
+
|
|
316
|
+
def _get_node_text(self, node: CivilizationNode) -> str:
|
|
317
|
+
"""Extract text for embedding from a node."""
|
|
318
|
+
parts = [node.title]
|
|
319
|
+
|
|
320
|
+
node_dict = node.model_dump()
|
|
321
|
+
|
|
322
|
+
# Add type-specific content
|
|
323
|
+
if node.node_type == NodeType.SOP:
|
|
324
|
+
parts.append(node_dict.get("purpose", ""))
|
|
325
|
+
parts.append(node_dict.get("scope", ""))
|
|
326
|
+
for step in node_dict.get("steps", []):
|
|
327
|
+
parts.append(step.get("title", ""))
|
|
328
|
+
parts.append(step.get("description", ""))
|
|
329
|
+
|
|
330
|
+
elif node.node_type == NodeType.ROLE:
|
|
331
|
+
parts.extend(node_dict.get("responsibilities", []))
|
|
332
|
+
parts.extend(node_dict.get("accountabilities", []))
|
|
333
|
+
|
|
334
|
+
elif node.node_type == NodeType.JOB_DESCRIPTION:
|
|
335
|
+
parts.append(node_dict.get("summary", ""))
|
|
336
|
+
parts.extend(node_dict.get("responsibilities", []))
|
|
337
|
+
|
|
338
|
+
elif node.node_type == NodeType.CHECKLIST:
|
|
339
|
+
parts.append(node_dict.get("purpose", ""))
|
|
340
|
+
for item in node_dict.get("items", []):
|
|
341
|
+
parts.append(item.get("description", ""))
|
|
342
|
+
|
|
343
|
+
elif node.node_type == NodeType.RUNBOOK:
|
|
344
|
+
parts.append(node_dict.get("scenario", ""))
|
|
345
|
+
for step in node_dict.get("steps", []):
|
|
346
|
+
parts.append(step.get("action", ""))
|
|
347
|
+
|
|
348
|
+
elif node.node_type == NodeType.POLICY:
|
|
349
|
+
parts.append(node_dict.get("summary", ""))
|
|
350
|
+
parts.append(node_dict.get("full_text", "")[:1000])
|
|
351
|
+
|
|
352
|
+
elif node.node_type == NodeType.KNOWLEDGE_ARTICLE:
|
|
353
|
+
parts.append(node_dict.get("summary", ""))
|
|
354
|
+
parts.append(node_dict.get("content", "")[:1500])
|
|
355
|
+
|
|
356
|
+
return " ".join(filter(None, parts))[:3000]
|
|
357
|
+
|
|
358
|
+
def clear_cache(self) -> None:
|
|
359
|
+
"""Clear internal caches."""
|
|
360
|
+
self._nodes_cache.clear()
|
|
361
|
+
self.embedder.clear_cache()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph module for Civilization Knowledge Layer.
|
|
3
|
+
Handles organizational structure, process flows, and knowledge relationships.
|
|
4
|
+
"""
|
|
5
|
+
from .org_graph import OrgGraph, OrgNode, OrgEdge
|
|
6
|
+
from .process_graph import ProcessGraph, ProcessNode, ProcessEdge
|
|
7
|
+
from .knowledge_linker import KnowledgeLinker, LinkType, KnowledgeLink
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"OrgGraph",
|
|
11
|
+
"OrgNode",
|
|
12
|
+
"OrgEdge",
|
|
13
|
+
"ProcessGraph",
|
|
14
|
+
"ProcessNode",
|
|
15
|
+
"ProcessEdge",
|
|
16
|
+
"KnowledgeLinker",
|
|
17
|
+
"LinkType",
|
|
18
|
+
"KnowledgeLink",
|
|
19
|
+
]
|