clm-kernel 0.0.0__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.
Files changed (333) hide show
  1. clm/__init__.py +230 -0
  2. clm/__main__.py +25 -0
  3. clm/cross_cutting/__init__.py +50 -0
  4. clm/cross_cutting/_test_runner.py +36 -0
  5. clm/cross_cutting/async_utils.py +25 -0
  6. clm/cross_cutting/cel_builder.py +123 -0
  7. clm/cross_cutting/cel_converter.py +697 -0
  8. clm/cross_cutting/cel_engine.py +252 -0
  9. clm/cross_cutting/cel_ops.py +72 -0
  10. clm/cross_cutting/cel_ops_db.py +157 -0
  11. clm/cross_cutting/cel_ops_files.py +99 -0
  12. clm/cross_cutting/cel_ops_state.py +71 -0
  13. clm/cross_cutting/cel_ops_strings.py +64 -0
  14. clm/cross_cutting/cel_resolver.py +63 -0
  15. clm/cross_cutting/cel_slices.py +56 -0
  16. clm/cross_cutting/cel_store.py +330 -0
  17. clm/cross_cutting/clm_logger.py +140 -0
  18. clm/cross_cutting/config/__init__.py +155 -0
  19. clm/cross_cutting/config/config_constants.py +392 -0
  20. clm/cross_cutting/config/env_parameters.py +90 -0
  21. clm/cross_cutting/config/logging.py +378 -0
  22. clm/cross_cutting/config/settings.py +504 -0
  23. clm/cross_cutting/context.py +5 -0
  24. clm/cross_cutting/domain_models.py +55 -0
  25. clm/cross_cutting/domain_types.py +61 -0
  26. clm/cross_cutting/effects.py +67 -0
  27. clm/cross_cutting/errors.py +153 -0
  28. clm/cross_cutting/governance.py +331 -0
  29. clm/cross_cutting/guards.py +41 -0
  30. clm/cross_cutting/mcard.py +321 -0
  31. clm/cross_cutting/native.py +185 -0
  32. clm/cross_cutting/observability.py +289 -0
  33. clm/cross_cutting/pcard.py +434 -0
  34. clm/cross_cutting/registry.py +71 -0
  35. clm/cross_cutting/resources.py +84 -0
  36. clm/cross_cutting/secrets.py +44 -0
  37. clm/cross_cutting/subprocess_utils.py +118 -0
  38. clm/cross_cutting/telemetry.py +164 -0
  39. clm/cross_cutting/testing/__init__.py +8 -0
  40. clm/cross_cutting/testing/comparator.py +187 -0
  41. clm/cross_cutting/testing/datasets.py +87 -0
  42. clm/cross_cutting/timeutil.py +20 -0
  43. clm/cross_cutting/types/new_type_check.py +0 -0
  44. clm/cross_cutting/utils/__init__.py +1 -0
  45. clm/cross_cutting/utils/url_safety.py +50 -0
  46. clm/cross_cutting/vcard.py +560 -0
  47. clm/cross_cutting/writer.py +118 -0
  48. clm/layer0/README.md +50 -0
  49. clm/layer0/__init__.py +223 -0
  50. clm/layer0/algebra.py +60 -0
  51. clm/layer0/algebra_baldwin.py +133 -0
  52. clm/layer0/algebra_baldwin_generators.py +36 -0
  53. clm/layer0/algebra_equivalence.py +262 -0
  54. clm/layer0/algebra_ingest.py +306 -0
  55. clm/layer0/algebra_manifest_io.py +156 -0
  56. clm/layer0/assembler.py +481 -0
  57. clm/layer0/cel/__init__.py +23 -0
  58. clm/layer0/cel_eval.py +491 -0
  59. clm/layer0/codec.py +106 -0
  60. clm/layer0/context.py +122 -0
  61. clm/layer0/db.py +160 -0
  62. clm/layer0/exceptions.py +73 -0
  63. clm/layer0/fibration.py +106 -0
  64. clm/layer0/gates.py +50 -0
  65. clm/layer0/hash.py +80 -0
  66. clm/layer0/loader.py +826 -0
  67. clm/layer0/math_utils.py +163 -0
  68. clm/layer0/mcard.py +96 -0
  69. clm/layer0/model/__init__.py +0 -0
  70. clm/layer0/model/action.py +223 -0
  71. clm/layer0/model/card.py +280 -0
  72. clm/layer0/model/card_triad.py +427 -0
  73. clm/layer0/model/compatibility.py +60 -0
  74. clm/layer0/model/dictionary.py +46 -0
  75. clm/layer0/model/dots.py +331 -0
  76. clm/layer0/model/event_producer.py +88 -0
  77. clm/layer0/model/g_time.py +89 -0
  78. clm/layer0/model/handle.py +163 -0
  79. clm/layer0/model/hash/__init__.py +6 -0
  80. clm/layer0/model/hash/algorithms/__init__.py +3 -0
  81. clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
  82. clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
  83. clm/layer0/model/hash/constants.py +53 -0
  84. clm/layer0/model/hash/enums.py +60 -0
  85. clm/layer0/model/hash/validator.py +307 -0
  86. clm/layer0/model/interpreter.py +275 -0
  87. clm/layer0/model/pagination.py +45 -0
  88. clm/layer0/model/pcard.py +716 -0
  89. clm/layer0/model/schema.py +44 -0
  90. clm/layer0/model/utils/__init__.py +1 -0
  91. clm/layer0/model/utils/content_analyzer.py +152 -0
  92. clm/layer0/model/validators/__init__.py +1 -0
  93. clm/layer0/model/validators/base_validator.py +44 -0
  94. clm/layer0/model/validators/binary_validator.py +66 -0
  95. clm/layer0/model/validators/text_validator.py +82 -0
  96. clm/layer0/model/validators/validation_registry.py +49 -0
  97. clm/layer0/model/vcard.py +823 -0
  98. clm/layer0/model/vcard_ext/__init__.py +39 -0
  99. clm/layer0/model/vcard_ext/core.py +60 -0
  100. clm/layer0/model/vcard_ext/network.py +23 -0
  101. clm/layer0/model/vcard_ext/observability.py +63 -0
  102. clm/layer0/model/vcard_ext/storage.py +60 -0
  103. clm/layer0/model/vcard_ext/vendors.py +211 -0
  104. clm/layer0/model/vcard_sandwich.py +119 -0
  105. clm/layer0/model/vcard_vocabulary.py +463 -0
  106. clm/layer0/model/workflow.py +274 -0
  107. clm/layer0/narrative.py +431 -0
  108. clm/layer0/ontology/collection.py +125 -0
  109. clm/layer0/parser.py +429 -0
  110. clm/layer0/relations.py +73 -0
  111. clm/layer0/rule_evaluator.py +251 -0
  112. clm/layer0/schema/__init__.py +38 -0
  113. clm/layer0/schema/ddl.py +97 -0
  114. clm/layer0/templates/abstract.yaml +99 -0
  115. clm/layer0/templates/balanced.yaml +253 -0
  116. clm/layer0/templates/concrete.yaml +172 -0
  117. clm/layer0/type_registry.py +223 -0
  118. clm/layer0/types.py +204 -0
  119. clm/layer0/utils.py +886 -0
  120. clm/layer0/verifier_core.py +262 -0
  121. clm/layer1/__init__.py +31 -0
  122. clm/layer1/action_dispatcher.py +275 -0
  123. clm/layer1/adapter_registry.py +233 -0
  124. clm/layer1/algebra_baldwin_generators.py +192 -0
  125. clm/layer1/arrow_compiler.py +525 -0
  126. clm/layer1/batch_processor.py +152 -0
  127. clm/layer1/cel/__init__.py +27 -0
  128. clm/layer1/cel/builder.py +173 -0
  129. clm/layer1/engine.py +759 -0
  130. clm/layer1/engine_async.py +89 -0
  131. clm/layer1/eval_callback.py +49 -0
  132. clm/layer1/gate_composer.py +229 -0
  133. clm/layer1/hoare_sandwich.py +298 -0
  134. clm/layer1/identity_guard.py +348 -0
  135. clm/layer1/matrix.py +138 -0
  136. clm/layer1/neural_runtime.py +221 -0
  137. clm/layer1/operations/__init__.py +123 -0
  138. clm/layer1/operations/augment.py +156 -0
  139. clm/layer1/operations/base.py +109 -0
  140. clm/layer1/operations/builtins.py +338 -0
  141. clm/layer1/operations/dispatch.py +144 -0
  142. clm/layer1/operations/exclude.py +107 -0
  143. clm/layer1/operations/handle.py +197 -0
  144. clm/layer1/operations/identity.py +139 -0
  145. clm/layer1/operations/invert.py +66 -0
  146. clm/layer1/operations/loader.py +116 -0
  147. clm/layer1/operations/manipulators/__init__.py +23 -0
  148. clm/layer1/operations/manipulators/document.py +211 -0
  149. clm/layer1/operations/manipulators/media.py +134 -0
  150. clm/layer1/operations/manipulators/structured.py +159 -0
  151. clm/layer1/operations/manipulators/tabular.py +334 -0
  152. clm/layer1/operations/port.py +65 -0
  153. clm/layer1/operations/services.py +529 -0
  154. clm/layer1/operations/split.py +117 -0
  155. clm/layer1/operations/substitute.py +75 -0
  156. clm/layer1/petri.py +1052 -0
  157. clm/layer1/pocketflow_orchestrator.py +408 -0
  158. clm/layer1/pocketflow_scheduler.py +519 -0
  159. clm/layer1/protocols.py +197 -0
  160. clm/layer1/runtime_adapter.py +718 -0
  161. clm/layer1/runtimes/__init__.py +71 -0
  162. clm/layer1/runtimes/_generated_assertions.py +125 -0
  163. clm/layer1/runtimes/_generated_types.py +42 -0
  164. clm/layer1/runtimes/base.py +265 -0
  165. clm/layer1/runtimes/binary.py +101 -0
  166. clm/layer1/runtimes/factory.py +203 -0
  167. clm/layer1/runtimes/javascript.py +321 -0
  168. clm/layer1/runtimes/javascript_runtime.js +33 -0
  169. clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
  170. clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
  171. clm/layer1/runtimes/lambda_calc.py +126 -0
  172. clm/layer1/runtimes/python.py +288 -0
  173. clm/layer1/runtimes/python_runtime.py +41 -0
  174. clm/layer1/runtimes/script.py +114 -0
  175. clm/layer1/sandbox.py +334 -0
  176. clm/layer1/savepoint_guard.py +136 -0
  177. clm/layer1/sparse_net.py +122 -0
  178. clm/layer1/spec_tester.py +165 -0
  179. clm/layer1/store.py +295 -0
  180. clm/layer1/test_runner.py +498 -0
  181. clm/layer1/type_inspector.py +166 -0
  182. clm/layer1/verifier.py +772 -0
  183. clm/layer1/vm.py +91 -0
  184. clm/layer2/__init__.py +78 -0
  185. clm/layer2/card_collection.py +678 -0
  186. clm/layer2/classifier.py +479 -0
  187. clm/layer2/engine/__init__.py +1 -0
  188. clm/layer2/engine/abstract_sql_engine.py +320 -0
  189. clm/layer2/engine/base.py +193 -0
  190. clm/layer2/engine/duckdb_engine.py +576 -0
  191. clm/layer2/engine/sqlite_engine.py +518 -0
  192. clm/layer2/fiber/__init__.py +31 -0
  193. clm/layer2/fiber/context.py +89 -0
  194. clm/layer2/fiber/disposable.py +163 -0
  195. clm/layer2/fiber/fiber.py +125 -0
  196. clm/layer2/fiber/hoare.py +191 -0
  197. clm/layer2/file_io.py +376 -0
  198. clm/layer2/file_registrar.py +77 -0
  199. clm/layer2/ingest.py +202 -0
  200. clm/layer2/lineage.py +322 -0
  201. clm/layer2/mcard_fs.py +262 -0
  202. clm/layer2/merkle.py +11 -0
  203. clm/layer2/mime.py +244 -0
  204. clm/layer2/mime_detector.py +245 -0
  205. clm/layer2/private_collection.py +118 -0
  206. clm/layer2/shared_store.py +11 -0
  207. clm/layer2/storage/__init__.py +190 -0
  208. clm/layer2/storage/db_bitemporal.py +141 -0
  209. clm/layer2/storage/db_driver.py +331 -0
  210. clm/layer2/storage/db_hyperlinks.py +214 -0
  211. clm/layer2/storage/db_pool.py +139 -0
  212. clm/layer2/storage/db_repository.py +229 -0
  213. clm/layer2/storage/savepoint.py +78 -0
  214. clm/layer2/storage/sqlite_wal.py +74 -0
  215. clm/layer2/tridb.py +245 -0
  216. clm/layer2/vcard_receipt.py +71 -0
  217. clm/layer2/vfs.py +17 -0
  218. clm/layer3/__init__.py +141 -0
  219. clm/layer3/agency/__init__.py +19 -0
  220. clm/layer3/agency/config.py +220 -0
  221. clm/layer3/agency/providers/__init__.py +15 -0
  222. clm/layer3/agency/providers/base.py +91 -0
  223. clm/layer3/agency/providers/mlc_llm.py +169 -0
  224. clm/layer3/agency/providers/ollama.py +203 -0
  225. clm/layer3/agency/router.py +71 -0
  226. clm/layer3/agency/runtime.py +524 -0
  227. clm/layer3/gateway.py +353 -0
  228. clm/layer3/open_interpreter_adapter.py +159 -0
  229. clm/layer3/rag/__init__.py +70 -0
  230. clm/layer3/rag/cli.py +228 -0
  231. clm/layer3/rag/config.py +153 -0
  232. clm/layer3/rag/embeddings/__init__.py +16 -0
  233. clm/layer3/rag/embeddings/base.py +79 -0
  234. clm/layer3/rag/embeddings/ollama.py +211 -0
  235. clm/layer3/rag/embeddings/vision.py +290 -0
  236. clm/layer3/rag/engine.py +276 -0
  237. clm/layer3/rag/graph/__init__.py +22 -0
  238. clm/layer3/rag/graph/community.py +198 -0
  239. clm/layer3/rag/graph/engine.py +433 -0
  240. clm/layer3/rag/graph/extractor.py +255 -0
  241. clm/layer3/rag/graph/schema.py +115 -0
  242. clm/layer3/rag/graph/store.py +641 -0
  243. clm/layer3/rag/indexer.py +333 -0
  244. clm/layer3/rag/llm_providers.json +52 -0
  245. clm/layer3/rag/semantic_versioning.py +313 -0
  246. clm/layer3/rag/vector/__init__.py +28 -0
  247. clm/layer3/rag/vector/handle_vector_store.py +749 -0
  248. clm/layer3/rag/vector/schema.py +151 -0
  249. clm/layer3/rag/vector/store.py +632 -0
  250. clm/layer3/reticulum/__init__.py +55 -0
  251. clm/layer3/reticulum/bridge.py +74 -0
  252. clm/layer3/reticulum/daemon.py +88 -0
  253. clm/layer3/reticulum/discovery.py +164 -0
  254. clm/layer3/reticulum/identity.py +107 -0
  255. clm/layer3/reticulum/media.py +148 -0
  256. clm/layer3/reticulum/transport.py +133 -0
  257. clm/layer3/satori/__init__.py +209 -0
  258. clm/layer3/satori/alpha_conversion.py +168 -0
  259. clm/layer3/satori/beta_reduction.py +359 -0
  260. clm/layer3/satori/continuation.py +38 -0
  261. clm/layer3/satori/eta_conversion.py +205 -0
  262. clm/layer3/satori/free_variables.py +163 -0
  263. clm/layer3/satori/io_effects.py +370 -0
  264. clm/layer3/satori/lambda_runtime.py +726 -0
  265. clm/layer3/satori/lambda_term.py +230 -0
  266. clm/layer3/satori/sheaf_audit.py +261 -0
  267. clm/layer3/satori/speech_act.py +279 -0
  268. clm/layer4/README.md +9 -0
  269. clm/layer4/__init__.py +67 -0
  270. clm/layer4/_sovereign_executor.py +580 -0
  271. clm/layer4/action_commands.py +719 -0
  272. clm/layer4/api.py +236 -0
  273. clm/layer4/bootstrap/__init__.py +13 -0
  274. clm/layer4/bootstrap/bootstrapper.py +118 -0
  275. clm/layer4/bootstrap/cleanup.py +44 -0
  276. clm/layer4/bootstrap/clm_hooks.py +49 -0
  277. clm/layer4/bootstrap/genesis.py +77 -0
  278. clm/layer4/bootstrap/injection.py +125 -0
  279. clm/layer4/cli.py +549 -0
  280. clm/layer4/collection_manager.py +553 -0
  281. clm/layer4/commands/__init__.py +81 -0
  282. clm/layer4/commands/action_cmd.py +42 -0
  283. clm/layer4/commands/check_cmd.py +82 -0
  284. clm/layer4/commands/envelope.py +73 -0
  285. clm/layer4/commands/evaluate_cmd.py +224 -0
  286. clm/layer4/commands/mcard_cmd.py +24 -0
  287. clm/layer4/commands/petri_cmd.py +92 -0
  288. clm/layer4/commands/tridb_cmd.py +319 -0
  289. clm/layer4/commands/version_cmd.py +27 -0
  290. clm/layer4/diff_commands.py +167 -0
  291. clm/layer4/eoa_sponsor.py +232 -0
  292. clm/layer4/events.py +69 -0
  293. clm/layer4/flux_gateway.py +133 -0
  294. clm/layer4/gateway.py +91 -0
  295. clm/layer4/loader.py +307 -0
  296. clm/layer4/mcard_commands.py +166 -0
  297. clm/layer4/membrane.py +273 -0
  298. clm/layer4/navigation.py +50 -0
  299. clm/layer4/protocol/protocol_entry_python.py +108 -0
  300. clm/layer4/protocol/python_sync.py +126 -0
  301. clm/layer4/runner.py +150 -0
  302. clm/layer4/satori.py +262 -0
  303. clm/layer4/server/python_sync_client.py +150 -0
  304. clm/layer4/server/python_sync_server.py +139 -0
  305. clm/layer4/server/service_api.py +315 -0
  306. clm/layer4/server/start_servers.py +107 -0
  307. clm/layer4/server/stop_servers.py +24 -0
  308. clm/layer4/simulated_optimization_fix.py +0 -0
  309. clm/layer4/storage.py +463 -0
  310. clm/layer4/tridb_admin.py +268 -0
  311. clm/layer4/websocket/test_ws_client.py +104 -0
  312. clm/layer4/websocket/test_ws_server.py +138 -0
  313. clm/layer4/websocket/ws_server_local.py +160 -0
  314. clm/layer5/__init__.py +51 -0
  315. clm/layer5/async_batch_writer.py +133 -0
  316. clm/layer5/learning.py +276 -0
  317. clm/layer5/telemetry_hook.py +107 -0
  318. clm/layer5/type_lattice.py +238 -0
  319. clm/py.typed +0 -0
  320. clm/schemas/__init__.py +652 -0
  321. clm/schemas/abstract_face_schema.yaml +77 -0
  322. clm/schemas/cel_schema.yaml +416 -0
  323. clm/schemas/lifecycle/__init__.py +45 -0
  324. clm/schemas/lifecycle/models.py +123 -0
  325. clm/schemas/lifecycle/service.py +364 -0
  326. clm/schemas/mcard_schema.sql +192 -0
  327. clm/schemas/mcard_vector_schema.sql +283 -0
  328. clm/schemas/mlp-context-v1.json +91 -0
  329. clm_kernel-0.0.0.dist-info/METADATA +121 -0
  330. clm_kernel-0.0.0.dist-info/RECORD +333 -0
  331. clm_kernel-0.0.0.dist-info/WHEEL +4 -0
  332. clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
  333. clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,255 @@
1
+ """
2
+ Graph Extractor
3
+
4
+ Extracts entities and relationships from MCard content using LLM.
5
+ """
6
+
7
+ import json
8
+ import logging
9
+ import re
10
+ from dataclasses import dataclass, field
11
+ from typing import Any
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ # ─────────────────────────────────────────────────────────────────────────────
17
+ # Data Classes
18
+ # ─────────────────────────────────────────────────────────────────────────────
19
+
20
+
21
+ @dataclass
22
+ class Entity:
23
+ """Represents an entity extracted from text."""
24
+
25
+ name: str
26
+ type: str # CONCEPT, TECHNOLOGY, PERSON, ORGANIZATION, etc.
27
+ description: str = ""
28
+ id: int | None = None
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ return {
32
+ "name": self.name,
33
+ "type": self.type,
34
+ "description": self.description,
35
+ }
36
+
37
+
38
+ @dataclass
39
+ class Relationship:
40
+ """Represents a relationship between two entities."""
41
+
42
+ source: str # Entity name
43
+ target: str # Entity name
44
+ relationship: str # Verb/action connecting them
45
+ description: str = ""
46
+ weight: float = 1.0
47
+
48
+ def to_dict(self) -> dict[str, Any]:
49
+ return {
50
+ "source": self.source,
51
+ "target": self.target,
52
+ "relationship": self.relationship,
53
+ "description": self.description,
54
+ }
55
+
56
+
57
+ @dataclass
58
+ class ExtractionResult:
59
+ """Result from entity/relationship extraction."""
60
+
61
+ entities: list[Entity] = field(default_factory=list)
62
+ relationships: list[Relationship] = field(default_factory=list)
63
+ success: bool = True
64
+ error: str | None = None
65
+
66
+
67
+ # ─────────────────────────────────────────────────────────────────────────────
68
+ # Extraction Prompts
69
+ # ─────────────────────────────────────────────────────────────────────────────
70
+
71
+ EXTRACTION_SYSTEM_PROMPT = """You are an expert at extracting structured information from text.
72
+ Given a text, identify:
73
+ 1. ENTITIES: Named concepts, technologies, people, organizations, or things
74
+ 2. RELATIONSHIPS: How entities relate to each other
75
+
76
+ Respond ONLY with valid JSON in this format:
77
+ {
78
+ "entities": [
79
+ {"name": "EntityName", "type": "CONCEPT|TECHNOLOGY|PERSON|ORGANIZATION|OTHER", "description": "Brief description"}
80
+ ],
81
+ "relationships": [
82
+ {"source": "Entity1", "target": "Entity2", "relationship": "verb phrase", "description": "Optional context"}
83
+ ]
84
+ }
85
+
86
+ Entity types:
87
+ - CONCEPT: Abstract ideas, methodologies, patterns (e.g., "content-addressable storage")
88
+ - TECHNOLOGY: Systems, libraries, frameworks (e.g., "SQLite", "Python")
89
+ - PERSON: People names
90
+ - ORGANIZATION: Companies, groups
91
+ - OTHER: Anything else
92
+
93
+ Keep entity names concise but unique. Use present tense for relationships."""
94
+
95
+
96
+ EXTRACTION_USER_PROMPT = """Extract entities and relationships from this text:
97
+
98
+ ---
99
+ {content}
100
+ ---
101
+
102
+ Remember: Return ONLY valid JSON."""
103
+
104
+
105
+ # ─────────────────────────────────────────────────────────────────────────────
106
+ # Graph Extractor
107
+ # ─────────────────────────────────────────────────────────────────────────────
108
+
109
+
110
+ class GraphExtractor:
111
+ """
112
+ Extracts entities and relationships from text using LLM.
113
+
114
+ Usage:
115
+ extractor = GraphExtractor(model='qwen3:0.6b')
116
+ result = extractor.extract("MCard is a Python library...")
117
+
118
+ for entity in result.entities:
119
+ print(f"{entity.name} ({entity.type})")
120
+
121
+ for rel in result.relationships:
122
+ print(f"{rel.source} --{rel.relationship}-> {rel.target}")
123
+ """
124
+
125
+ def __init__(
126
+ self,
127
+ model: str = "qwen3:0.6b",
128
+ temperature: float = 0.1,
129
+ max_retries: int = 2,
130
+ ):
131
+ """
132
+ Initialize graph extractor.
133
+
134
+ Args:
135
+ model: LLM model to use
136
+ temperature: Low for consistent extraction
137
+ max_retries: Retries on parse failure
138
+ """
139
+ self.model = model
140
+ self.temperature = temperature
141
+ self.max_retries = max_retries
142
+
143
+ def extract(self, content: str) -> ExtractionResult:
144
+ """
145
+ Extract entities and relationships from content.
146
+
147
+ Args:
148
+ content: Text to extract from
149
+
150
+ Returns:
151
+ ExtractionResult with entities and relationships
152
+ """
153
+ if not content or not content.strip():
154
+ return ExtractionResult(success=False, error="Empty content")
155
+
156
+ # Truncate if too long
157
+ max_chars = 6000
158
+ if len(content) > max_chars:
159
+ content = content[:max_chars] + "\n[...truncated...]"
160
+
161
+ # Call LLM for extraction
162
+ for attempt in range(self.max_retries + 1):
163
+ try:
164
+ result = self._call_llm(content)
165
+ parsed = self._parse_response(result)
166
+ if parsed.entities or parsed.relationships:
167
+ return parsed
168
+ except Exception as e:
169
+ logger.warning(f"Extraction attempt {attempt + 1} failed: {e}")
170
+ if attempt == self.max_retries:
171
+ return ExtractionResult(success=False, error=str(e))
172
+
173
+ return ExtractionResult(success=False, error="No entities extracted")
174
+
175
+ def _call_llm(self, content: str) -> str:
176
+ """Call LLM for extraction."""
177
+ from clm.layer3.agency import chat_monad
178
+
179
+ prompt = EXTRACTION_USER_PROMPT.format(content=content)
180
+
181
+ result = chat_monad(
182
+ prompt=prompt,
183
+ system_prompt=EXTRACTION_SYSTEM_PROMPT,
184
+ model=self.model,
185
+ temperature=self.temperature,
186
+ max_tokens=2000,
187
+ ).unsafe_run()
188
+
189
+ if result.is_left():
190
+ raise RuntimeError(f"LLM call failed: {result.value}")
191
+
192
+ return result.value.get("content", str(result.value))
193
+
194
+ def _parse_response(self, response: str) -> ExtractionResult:
195
+ """Parse LLM response into structured data."""
196
+ # Try to extract JSON from response
197
+ json_match = re.search(r"\{[\s\S]*\}", response)
198
+ if not json_match:
199
+ raise ValueError("No JSON found in response")
200
+
201
+ json_str = json_match.group()
202
+
203
+ try:
204
+ data = json.loads(json_str)
205
+ except json.JSONDecodeError:
206
+ # Try to fix common issues
207
+ json_str = self._clean_json(json_str)
208
+ data = json.loads(json_str)
209
+
210
+ entities = []
211
+ for e in data.get("entities", []):
212
+ if isinstance(e, dict) and "name" in e:
213
+ entities.append(
214
+ Entity(
215
+ name=e.get("name", "").strip(),
216
+ type=e.get("type", "OTHER").upper(),
217
+ description=e.get("description", "").strip(),
218
+ )
219
+ )
220
+
221
+ relationships = []
222
+ for r in data.get("relationships", []):
223
+ if isinstance(r, dict) and "source" in r and "target" in r:
224
+ relationships.append(
225
+ Relationship(
226
+ source=r.get("source", "").strip(),
227
+ target=r.get("target", "").strip(),
228
+ relationship=r.get("relationship", "relates_to").strip(),
229
+ description=r.get("description", "").strip(),
230
+ )
231
+ )
232
+
233
+ return ExtractionResult(
234
+ entities=entities, relationships=relationships, success=True
235
+ )
236
+
237
+ def _clean_json(self, json_str: str) -> str:
238
+ """Try to clean up malformed JSON."""
239
+ # Remove trailing commas
240
+ json_str = re.sub(r",\s*([}\]])", r"\1", json_str)
241
+ # Remove control characters
242
+ json_str = re.sub(r"[\x00-\x1f]", "", json_str)
243
+ return json_str
244
+
245
+ def extract_batch(self, contents: list[str]) -> list[ExtractionResult]:
246
+ """
247
+ Extract from multiple texts.
248
+
249
+ Args:
250
+ contents: List of texts
251
+
252
+ Returns:
253
+ List of ExtractionResults
254
+ """
255
+ return [self.extract(content) for content in contents]
@@ -0,0 +1,115 @@
1
+ """
2
+ Graph Database Schema
3
+
4
+ This module provides graph-specific schemas from the unified schema singleton.
5
+
6
+ IMPORTANT: All schemas are loaded from schema/mcard_schema.sql
7
+ This module provides convenient access to graph-related schemas only.
8
+
9
+ Usage:
10
+ from clm.layer3.rag.graph.schema import GRAPH_SCHEMAS
11
+
12
+ Or better, use the singleton directly:
13
+ from clm.schemas import MCardSchema
14
+ schema = MCardSchema.get_instance()
15
+ schema.init_graph_tables(conn)
16
+ """
17
+
18
+ import typing
19
+
20
+ from clm.schemas import MCardSchema
21
+
22
+ if typing.TYPE_CHECKING:
23
+ GRAPH_SCHEMAS: dict
24
+ ENTITY_SCHEMA: str
25
+ ENTITY_INDEX_NAME: str
26
+ ENTITY_INDEX_TYPE: str
27
+ ENTITY_INDEX_SOURCE: str
28
+ RELATIONSHIP_SCHEMA: str
29
+ RELATIONSHIP_INDEX_SOURCE: str
30
+ RELATIONSHIP_INDEX_TARGET: str
31
+ COMMUNITY_SCHEMA: str
32
+ COMMUNITY_INDEX_LEVEL: str
33
+ EXTRACTION_TRACKING_SCHEMA: str
34
+
35
+
36
+ def _get_schema_instance() -> MCardSchema:
37
+ return MCardSchema.get_instance()
38
+
39
+
40
+ def _build_graph_schemas() -> dict:
41
+ """Build GRAPH_SCHEMAS from the unified schema."""
42
+ schema = _get_schema_instance()
43
+ return {
44
+ "entities": schema.get_table("graph_entities"),
45
+ "entity_idx_name": schema.get_index("idx_entity_name"),
46
+ "entity_idx_type": schema.get_index("idx_entity_type"),
47
+ "entity_idx_source": schema.get_index("idx_entity_source"),
48
+ "relationships": schema.get_table("graph_relationships"),
49
+ "rel_idx_source": schema.get_index("idx_rel_source"),
50
+ "rel_idx_target": schema.get_index("idx_rel_target"),
51
+ "communities": schema.get_table("graph_communities"),
52
+ "community_idx_level": schema.get_index("idx_community_level"),
53
+ "extractions": schema.get_table("graph_extractions"),
54
+ }
55
+
56
+
57
+ # Lazy-loaded schema dictionary
58
+ _GRAPH_SCHEMAS = None
59
+
60
+
61
+ def __getattr__(name: str):
62
+ """Lazy loading of schema dictionaries."""
63
+ global _GRAPH_SCHEMAS
64
+
65
+ if name == "GRAPH_SCHEMAS":
66
+ if _GRAPH_SCHEMAS is None:
67
+ _GRAPH_SCHEMAS = _build_graph_schemas()
68
+ return _GRAPH_SCHEMAS
69
+
70
+ elif name == "ENTITY_SCHEMA":
71
+ return _get_schema_instance().get_table("graph_entities")
72
+
73
+ elif name == "ENTITY_INDEX_NAME":
74
+ return _get_schema_instance().get_index("idx_entity_name")
75
+
76
+ elif name == "ENTITY_INDEX_TYPE":
77
+ return _get_schema_instance().get_index("idx_entity_type")
78
+
79
+ elif name == "ENTITY_INDEX_SOURCE":
80
+ return _get_schema_instance().get_index("idx_entity_source")
81
+
82
+ elif name == "RELATIONSHIP_SCHEMA":
83
+ return _get_schema_instance().get_table("graph_relationships")
84
+
85
+ elif name == "RELATIONSHIP_INDEX_SOURCE":
86
+ return _get_schema_instance().get_index("idx_rel_source")
87
+
88
+ elif name == "RELATIONSHIP_INDEX_TARGET":
89
+ return _get_schema_instance().get_index("idx_rel_target")
90
+
91
+ elif name == "COMMUNITY_SCHEMA":
92
+ return _get_schema_instance().get_table("graph_communities")
93
+
94
+ elif name == "COMMUNITY_INDEX_LEVEL":
95
+ return _get_schema_instance().get_index("idx_community_level")
96
+
97
+ elif name == "EXTRACTION_TRACKING_SCHEMA":
98
+ return _get_schema_instance().get_table("graph_extractions")
99
+
100
+ raise AttributeError(f"module 'mcard.rag.graph.schema' has no attribute '{name}'")
101
+
102
+
103
+ __all__ = [
104
+ "GRAPH_SCHEMAS",
105
+ "ENTITY_SCHEMA",
106
+ "ENTITY_INDEX_NAME",
107
+ "ENTITY_INDEX_TYPE",
108
+ "ENTITY_INDEX_SOURCE",
109
+ "RELATIONSHIP_SCHEMA",
110
+ "RELATIONSHIP_INDEX_SOURCE",
111
+ "RELATIONSHIP_INDEX_TARGET",
112
+ "COMMUNITY_SCHEMA",
113
+ "COMMUNITY_INDEX_LEVEL",
114
+ "EXTRACTION_TRACKING_SCHEMA",
115
+ ]