engrammic-primitives 0.1.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 (39) hide show
  1. engrammic_primitives-0.1.0.dist-info/METADATA +68 -0
  2. engrammic_primitives-0.1.0.dist-info/RECORD +39 -0
  3. engrammic_primitives-0.1.0.dist-info/WHEEL +4 -0
  4. engrammic_primitives-0.1.0.dist-info/licenses/LICENSE +21 -0
  5. primitives/__init__.py +6 -0
  6. primitives/eag/__init__.py +44 -0
  7. primitives/eag/agents/__init__.py +34 -0
  8. primitives/eag/agents/base.py +135 -0
  9. primitives/eag/agents/tools.py +77 -0
  10. primitives/eag/epistemology/__init__.py +45 -0
  11. primitives/eag/epistemology/confidence.py +138 -0
  12. primitives/eag/epistemology/promotion.py +119 -0
  13. primitives/eag/epistemology/supersession.py +119 -0
  14. primitives/eag/lifecycle.py +127 -0
  15. primitives/eag/queries/__init__.py +113 -0
  16. primitives/eag/queries/cluster.py +125 -0
  17. primitives/eag/queries/ddl.py +82 -0
  18. primitives/eag/queries/finding.py +164 -0
  19. primitives/eag/queries/pass_ledger.py +97 -0
  20. primitives/eag/queries/silo.py +54 -0
  21. primitives/eag/store.py +87 -0
  22. primitives/eag/transitions/__init__.py +11 -0
  23. primitives/eag/transitions/predicates.py +30 -0
  24. primitives/extensions/__init__.py +1 -0
  25. primitives/extensions/code.py +41 -0
  26. primitives/protocols.py +337 -0
  27. primitives/py.typed +0 -0
  28. primitives/schema/__init__.py +65 -0
  29. primitives/schema/edges.py +74 -0
  30. primitives/schema/labels.py +123 -0
  31. primitives/scoring/__init__.py +7 -0
  32. primitives/scoring/decay.py +27 -0
  33. primitives/shared/__init__.py +32 -0
  34. primitives/shared/cypher/__init__.py +17 -0
  35. primitives/shared/cypher/helpers.py +64 -0
  36. primitives/shared/fingerprints.py +87 -0
  37. primitives/shared/validators.py +109 -0
  38. primitives/taxonomy/__init__.py +13 -0
  39. primitives/taxonomy/categories.py +39 -0
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: engrammic-primitives
3
+ Version: 0.1.0
4
+ Summary: EAG schema primitives for epistemic context management
5
+ Author-email: Aliasgar Khimani <aliasgar.khimani@engrammic.ai>
6
+ License: Apache-2.0
7
+ License-File: LICENSE
8
+ Keywords: ai-agents,context-management,graphrag,knowledge-graph
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.13
16
+ Requires-Dist: pydantic>=2.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Engrammic Primitives
20
+
21
+ EAG schema primitives for building epistemic context systems.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install engrammic-primitives
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ from primitives.schema import MemoryNode, KnowledgeNode, WisdomNode
33
+ from primitives.eag import CognitiveTier
34
+
35
+ # Create a memory node
36
+ node = MemoryNode(
37
+ content="User prefers dark mode",
38
+ importance=0.7,
39
+ )
40
+
41
+ # Check cognitive tier
42
+ tier = CognitiveTier.MEMORY
43
+ ```
44
+
45
+ ## When to Use
46
+
47
+ Building your own EAG-compatible system or extending Engrammic.
48
+
49
+ For using Engrammic directly, see:
50
+ - [engrammic-mcp](https://github.com/engrammic/mcp-client) - hosted service
51
+ - [engrammic-engine](https://github.com/engrammic/engine) - local engine
52
+
53
+ ## Learn More
54
+
55
+ - [EAG Manifesto](docs/manifesto.md) - the paradigm explained
56
+
57
+ ## Modules
58
+
59
+ | Module | Purpose |
60
+ |--------|---------|
61
+ | `primitives.schema` | Node and edge type definitions |
62
+ | `primitives.eag` | EAG-specific implementations |
63
+ | `primitives.protocols` | Storage and lifecycle interfaces |
64
+ | `primitives.scoring` | Decay and freshness formulas |
65
+
66
+ ## License
67
+
68
+ Apache 2.0
@@ -0,0 +1,39 @@
1
+ primitives/__init__.py,sha256=nL6wRTqSdfJnkKV_tEf7Pa7M71gTL22Df6r18cbVccc,136
2
+ primitives/protocols.py,sha256=OalpW1jQq3KvWRg8oG2O_JP9Du1oSLdvrqYW2W-ykW0,8383
3
+ primitives/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ primitives/eag/__init__.py,sha256=yIdHFHIdb0bW7CBsBKT-ZN9q1enZNU4WD3bOL_lV2iE,1119
5
+ primitives/eag/lifecycle.py,sha256=qh78xtbQ5UdFF1DzS9JfkT71YK4IHy1rMnKXmO9gtdY,4454
6
+ primitives/eag/store.py,sha256=nLVl4RfxLjN8sIYGjBgGerHbIeR75T5NgTSC6iIaVII,2509
7
+ primitives/eag/agents/__init__.py,sha256=OPTv2TMGrbXBINTgB4lwrzXM6oyy4yHs0cKLMegtusU,712
8
+ primitives/eag/agents/base.py,sha256=FZfQyxRT_OhwgYtddRD9vVAnym-VGFQ14CHwHt_imMk,3223
9
+ primitives/eag/agents/tools.py,sha256=z8QpyMCKRVr_sv1rd9pNwE__xHiMe8FsldWG1yfTvsM,1980
10
+ primitives/eag/epistemology/__init__.py,sha256=5q3C1Gbe-iIRbKltVj9V0D0pAVDIo6sKiNZ6ujkooAc,1071
11
+ primitives/eag/epistemology/confidence.py,sha256=fc5Ye3jMh2LzV6gnAgNhcYa0jOcS84WoiInjOsaY39Q,4177
12
+ primitives/eag/epistemology/promotion.py,sha256=d816t1oPA3DsmCoKuV8glXo4-cQJixF4_T1Ln2ClJzA,3437
13
+ primitives/eag/epistemology/supersession.py,sha256=hPwVSQyJaCfaistSy7BoKo11R1215pBW1QLaeMcqflA,3653
14
+ primitives/eag/queries/__init__.py,sha256=A8UMF_uS8u311WaiyMrwBdlEL7nnVQT9qwEJX4lzJqc,2706
15
+ primitives/eag/queries/cluster.py,sha256=aZRkGmq2Kd614qydtLc5QbwGix8B7XvbQd_HYcodH3U,3301
16
+ primitives/eag/queries/ddl.py,sha256=bavztY-QGWZmOoIITCrjNczC8KiMRxATXaVxtG5QVFU,2512
17
+ primitives/eag/queries/finding.py,sha256=Y5mjKYH0_WmSxcVjAAzWHh1ntidrNNSHCerZ-SBVItg,4948
18
+ primitives/eag/queries/pass_ledger.py,sha256=oereFR-5SNrCR7EjsF-5PraB4l71KhHWz5zOoKz9Kjs,2361
19
+ primitives/eag/queries/silo.py,sha256=yW7hn2eU_941X0b8AP4Ji9_6UTP2S_KAm0VN4uErfbs,1098
20
+ primitives/eag/transitions/__init__.py,sha256=EUWoZxpvZAyX9WKAy9VO0qVhzVmMzqDoalgKyf1a_yk,243
21
+ primitives/eag/transitions/predicates.py,sha256=MpYTo-2NBv6OQnPQt2zUa_lx0I9ToCnDtE1tr05zYoo,787
22
+ primitives/extensions/__init__.py,sha256=prvW-U5XrULsOS4mq-2CXPOAlGWpMEZFwQ6SNc-4U9o,57
23
+ primitives/extensions/code.py,sha256=cSQfJKhDEUBy5ZG5c2_uGfj1MR3pFcyVoQIcB-UkD2A,1001
24
+ primitives/schema/__init__.py,sha256=jrtgvFhruq4XCkioXIqPeODMWNuEgOCb1Jb8hdPRs9M,1348
25
+ primitives/schema/edges.py,sha256=RrdDeDgOK6wmH3W5synfEc-_pQFcClgNRMmqFUpQrKE,1769
26
+ primitives/schema/labels.py,sha256=z5z_01sDU59Q2xpTavJ-RSnx3lLSUO-4nNyS6gEHx_s,3635
27
+ primitives/scoring/__init__.py,sha256=T-3fWDlMGkoo-SPK23eMtIVgkAiKu85bMiZvv9Vnm9c,189
28
+ primitives/scoring/decay.py,sha256=T1UNZ-5tFmwGl-1v0ri9hhLM-yO3m8hqziX4WnccX10,687
29
+ primitives/shared/__init__.py,sha256=zghiwCEcKdwaHdVJIwFBsg9M9_XfBYSKbisDFRnUqSs,796
30
+ primitives/shared/fingerprints.py,sha256=BONc4mKj0MuC-UcAMyOM3OhXBNz_8ZaqJubf4ZWLlnM,2347
31
+ primitives/shared/validators.py,sha256=hkYvoTeNaURGeDUCnjYhDQLr_G4Blc_LQ-p12U37GAY,2946
32
+ primitives/shared/cypher/__init__.py,sha256=gNTqo9P89Ue3uRQzAgRFnWoo7hiijL8FtinY4T52OPw,362
33
+ primitives/shared/cypher/helpers.py,sha256=ciL7AwKXUOklIigRrRA0AC1NKIaVnfY0P3RtbkdV-BA,1558
34
+ primitives/taxonomy/__init__.py,sha256=8EaCStzHThSHkxO-N1X_A3rBmcfUx-p5vVQa-JE_aqE,263
35
+ primitives/taxonomy/categories.py,sha256=44tuSkYTcmwdaYXwUjuonGPwR3k045aJofDneHPjzfM,887
36
+ engrammic_primitives-0.1.0.dist-info/METADATA,sha256=JV-G9b-O1z-B7Q2SpCHSWkcou4iJuvYarR9z52bNoaY,1795
37
+ engrammic_primitives-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
38
+ engrammic_primitives-0.1.0.dist-info/licenses/LICENSE,sha256=esUnW0wDJTg5GnYzhkHmYMUpyPvOfw9Uu1xew_bTn24,1068
39
+ engrammic_primitives-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Delta Prime
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
primitives/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """GraphRAG primitives library.
2
+
3
+ Hot-swappable knowledge management primitives for AI agent context systems.
4
+ """
5
+
6
+ __version__ = "0.1.0"
@@ -0,0 +1,44 @@
1
+ """EAG (Epistemic Augmented Generation) implementation.
2
+
3
+ Four-layer cognitive architecture: Memory -> Knowledge -> Wisdom -> Intelligence.
4
+ Implements the protocol interfaces with EAG-specific semantics.
5
+ """
6
+
7
+ # Epistemology exports
8
+ from primitives.eag.epistemology import (
9
+ ClaimForPromotion,
10
+ ContradictionResult,
11
+ PromotionDecision,
12
+ PromotionRule,
13
+ SourceTier,
14
+ SupersessionDecision,
15
+ combined_confidence,
16
+ detect_contradiction,
17
+ incremental_noisy_or,
18
+ noisy_or_aggregate,
19
+ should_promote_r1,
20
+ should_promote_r2,
21
+ should_supersede,
22
+ )
23
+ from primitives.eag.lifecycle import EAGLifecycleManager
24
+ from primitives.eag.store import EAGKnowledgeStore
25
+
26
+ __all__ = [
27
+ # Epistemology
28
+ "SourceTier",
29
+ "combined_confidence",
30
+ "noisy_or_aggregate",
31
+ "incremental_noisy_or",
32
+ "PromotionRule",
33
+ "ClaimForPromotion",
34
+ "PromotionDecision",
35
+ "should_promote_r1",
36
+ "should_promote_r2",
37
+ "ContradictionResult",
38
+ "detect_contradiction",
39
+ "should_supersede",
40
+ "SupersessionDecision",
41
+ # Implementations
42
+ "EAGKnowledgeStore",
43
+ "EAGLifecycleManager",
44
+ ]
@@ -0,0 +1,34 @@
1
+ """EAG Agent Protocol definitions.
2
+
3
+ Defines abstract interfaces for EAG agents and tools. Implementations
4
+ live in private repositories (context-service); this module provides
5
+ the protocol contract that implementations must follow.
6
+ """
7
+
8
+ from primitives.eag.agents.base import (
9
+ AgentConfig,
10
+ AgentPhase,
11
+ AgentProtocol,
12
+ AgentResult,
13
+ BudgetConfig,
14
+ BudgetStatus,
15
+ DepsProtocol,
16
+ )
17
+ from primitives.eag.agents.tools import (
18
+ ToolDefinition,
19
+ ToolProtocol,
20
+ ToolResult,
21
+ )
22
+
23
+ __all__ = [
24
+ "AgentConfig",
25
+ "AgentPhase",
26
+ "AgentProtocol",
27
+ "AgentResult",
28
+ "BudgetConfig",
29
+ "BudgetStatus",
30
+ "DepsProtocol",
31
+ "ToolDefinition",
32
+ "ToolProtocol",
33
+ "ToolResult",
34
+ ]
@@ -0,0 +1,135 @@
1
+ """Base protocol definitions for EAG agents.
2
+
3
+ Agents in EAG operate in phases (fast, plan, deep, stitch), each with
4
+ distinct output types and budget constraints. This module defines the
5
+ abstract interfaces; implementations are private.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from abc import abstractmethod
11
+ from dataclasses import dataclass, field
12
+ from enum import StrEnum
13
+ from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar, runtime_checkable
14
+
15
+ from pydantic import BaseModel, ConfigDict
16
+
17
+ if TYPE_CHECKING:
18
+ from primitives.eag.agents.tools import ToolProtocol
19
+
20
+
21
+ class AgentPhase(StrEnum):
22
+ """Visit phases for EAG agents."""
23
+
24
+ FAST = "fast"
25
+ PLAN = "plan"
26
+ DEEP = "deep"
27
+ STITCH = "stitch"
28
+
29
+
30
+ class BudgetStatus(BaseModel):
31
+ """Budget state exposed to agents in tool responses."""
32
+
33
+ model_config = ConfigDict(extra="forbid")
34
+
35
+ tokens_remaining: int
36
+ tool_calls_remaining: int
37
+ wrap_up_signal: bool
38
+
39
+
40
+ @dataclass
41
+ class BudgetConfig:
42
+ """Per-phase budget configuration."""
43
+
44
+ nominal_tokens: int
45
+ hard_tokens: int
46
+ tool_calls_limit: int
47
+ request_limit: int
48
+ soft_signal_ratio: float = 0.69
49
+
50
+
51
+ @dataclass
52
+ class AgentConfig:
53
+ """Configuration for an agent instance."""
54
+
55
+ phase: AgentPhase
56
+ model: str
57
+ budget: BudgetConfig
58
+ retries: int = 8
59
+
60
+
61
+ T = TypeVar("T")
62
+ DepsT = TypeVar("DepsT", bound="DepsProtocol")
63
+ OutputT = TypeVar("OutputT")
64
+
65
+
66
+ @runtime_checkable
67
+ class DepsProtocol(Protocol):
68
+ """Minimal interface for per-visit dependencies.
69
+
70
+ Implementations carry org/silo/cluster context, buffer for committed
71
+ artifacts, and infrastructure handles. The protocol defines only the
72
+ fields that tools and result types depend on.
73
+ """
74
+
75
+ org_id: str
76
+ silo_id: str
77
+ cluster_id: str
78
+ pass_id: str
79
+ seen_node_ids: set[str]
80
+ budget: BudgetStatus
81
+ finalized: bool
82
+
83
+ def record_commit(self, event: dict[str, Any]) -> None:
84
+ """Append an event to the commit log."""
85
+ ...
86
+
87
+
88
+ @dataclass
89
+ class AgentResult(Generic[T]):
90
+ """Result from an agent run."""
91
+
92
+ output: T
93
+ finalized: bool
94
+ claims_committed: int
95
+ edges_committed: int
96
+ rejections: int
97
+ tokens_used: int
98
+ tool_calls_used: int
99
+ commit_log: list[dict[str, Any]] = field(default_factory=list)
100
+
101
+
102
+ @runtime_checkable
103
+ class AgentProtocol(Protocol[DepsT, OutputT]):
104
+ """Protocol for EAG agents.
105
+
106
+ An agent encapsulates a model, system prompt, output type, and budget
107
+ constraints. Tools are registered separately via the ToolProtocol.
108
+ """
109
+
110
+ @property
111
+ def phase(self) -> AgentPhase:
112
+ """The phase this agent operates in."""
113
+ ...
114
+
115
+ @property
116
+ def config(self) -> AgentConfig:
117
+ """Agent configuration."""
118
+ ...
119
+
120
+ @abstractmethod
121
+ async def run(
122
+ self,
123
+ deps: DepsT,
124
+ user_prompt: str,
125
+ ) -> AgentResult[OutputT]:
126
+ """Execute the agent with the given dependencies and prompt.
127
+
128
+ The agent runs until it produces an output, calls finalize, or
129
+ exhausts its budget. Tools mutate deps in place.
130
+ """
131
+ ...
132
+
133
+ def register_tool(self, tool: ToolProtocol[DepsT]) -> None:
134
+ """Register a tool on this agent."""
135
+ ...
@@ -0,0 +1,77 @@
1
+ """Tool protocol definitions for EAG agents.
2
+
3
+ Tools are functions that agents call to read state, commit artifacts, or
4
+ signal completion. Each tool call updates the budget and may mutate the
5
+ dependency container.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from abc import abstractmethod
11
+ from typing import Any, Protocol, TypeVar, runtime_checkable
12
+
13
+ from pydantic import BaseModel, ConfigDict
14
+
15
+ from primitives.eag.agents.base import BudgetStatus, DepsProtocol
16
+
17
+ DepsT = TypeVar("DepsT", bound=DepsProtocol)
18
+ ResultT = TypeVar("ResultT")
19
+
20
+
21
+ class ToolResult(BaseModel):
22
+ """Base class for tool results. All results carry budget status."""
23
+
24
+ model_config = ConfigDict(extra="forbid")
25
+
26
+ budget_status: BudgetStatus
27
+
28
+
29
+ class ToolDefinition(BaseModel):
30
+ """Metadata describing a tool for schema generation."""
31
+
32
+ model_config = ConfigDict(extra="forbid")
33
+
34
+ name: str
35
+ description: str
36
+ parameters_schema: dict[str, Any]
37
+ result_schema: dict[str, Any]
38
+
39
+
40
+ @runtime_checkable
41
+ class ToolProtocol(Protocol[DepsT]): # type: ignore[misc]
42
+ """Protocol for EAG agent tools.
43
+
44
+ Tools are async callables that receive a context (containing deps)
45
+ and arguments, returning a result that includes budget status.
46
+ """
47
+
48
+ @property
49
+ def name(self) -> str:
50
+ """Tool name as exposed to the agent."""
51
+ ...
52
+
53
+ @property
54
+ def description(self) -> str:
55
+ """Description shown to the agent."""
56
+ ...
57
+
58
+ @property
59
+ def definition(self) -> ToolDefinition:
60
+ """Full tool definition for schema generation."""
61
+ ...
62
+
63
+ @abstractmethod
64
+ async def __call__(
65
+ self,
66
+ deps: DepsT,
67
+ **kwargs: Any,
68
+ ) -> ToolResult:
69
+ """Execute the tool.
70
+
71
+ Implementations should:
72
+ 1. Perform the operation (read, commit, etc.)
73
+ 2. Update deps.seen_node_ids if nodes were returned
74
+ 3. Rebuild the budget status
75
+ 4. Return a result with the updated budget
76
+ """
77
+ ...
@@ -0,0 +1,45 @@
1
+ """Epistemology primitives: confidence, promotion, supersession.
2
+
3
+ All functions here are pure and deterministic. No LLM calls happen
4
+ at adjudication time.
5
+ """
6
+
7
+ from primitives.eag.epistemology.confidence import (
8
+ SourceTier,
9
+ combined_confidence,
10
+ incremental_noisy_or,
11
+ noisy_or_aggregate,
12
+ partial_confidence,
13
+ )
14
+ from primitives.eag.epistemology.promotion import (
15
+ ClaimForPromotion,
16
+ PromotionDecision,
17
+ PromotionRule,
18
+ should_promote_r1,
19
+ should_promote_r2,
20
+ )
21
+ from primitives.eag.epistemology.supersession import (
22
+ ContradictionResult,
23
+ FactForSupersession,
24
+ SupersessionDecision,
25
+ detect_contradiction,
26
+ should_supersede,
27
+ )
28
+
29
+ __all__ = [
30
+ "SourceTier",
31
+ "combined_confidence",
32
+ "noisy_or_aggregate",
33
+ "incremental_noisy_or",
34
+ "partial_confidence",
35
+ "PromotionRule",
36
+ "ClaimForPromotion",
37
+ "PromotionDecision",
38
+ "should_promote_r1",
39
+ "should_promote_r2",
40
+ "ContradictionResult",
41
+ "FactForSupersession",
42
+ "SupersessionDecision",
43
+ "detect_contradiction",
44
+ "should_supersede",
45
+ ]
@@ -0,0 +1,138 @@
1
+ """Confidence computation primitives.
2
+
3
+ Pure functions for computing claim and aggregate confidence scores.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from enum import StrEnum
9
+ from functools import reduce
10
+
11
+
12
+ class SourceTier(StrEnum):
13
+ """Source credibility tiers with associated weights."""
14
+
15
+ AUTHORITATIVE = "authoritative" # 1.0
16
+ VALIDATED = "validated" # 0.85
17
+ COMMUNITY = "community" # 0.6
18
+ UNKNOWN = "unknown" # 0.4
19
+
20
+ @property
21
+ def weight(self) -> float:
22
+ return _TIER_WEIGHTS[self]
23
+
24
+
25
+ _TIER_WEIGHTS: dict[SourceTier, float] = {
26
+ SourceTier.AUTHORITATIVE: 1.0,
27
+ SourceTier.VALIDATED: 0.85,
28
+ SourceTier.COMMUNITY: 0.6,
29
+ SourceTier.UNKNOWN: 0.4,
30
+ }
31
+
32
+
33
+ def combined_confidence(
34
+ raw_confidence: float,
35
+ source_tier: SourceTier,
36
+ corroboration_factor: float = 1.0,
37
+ method_weight: float = 1.0,
38
+ ) -> float:
39
+ """Compute combined confidence for a single claim.
40
+
41
+ Formula: source_tier * corroboration_factor * method_weight * raw_confidence
42
+
43
+ Args:
44
+ raw_confidence: Base confidence from extraction (0.0 - 1.0)
45
+ source_tier: Credibility tier of the source
46
+ corroboration_factor: Boost from corroborating evidence (default 1.0)
47
+ method_weight: Weight based on extraction method (default 1.0)
48
+
49
+ Returns:
50
+ Combined confidence score (0.0 - 1.0)
51
+ """
52
+ result = source_tier.weight * corroboration_factor * method_weight * raw_confidence
53
+ return min(max(result, 0.0), 1.0)
54
+
55
+
56
+ def noisy_or_aggregate(confidences: list[float], cap: float = 0.99) -> float:
57
+ """Aggregate multiple confidence scores using noisy-OR.
58
+
59
+ Formula: 1 - product(1 - c_i) for each confidence c_i
60
+
61
+ This models independent evidence: each source has a chance of being
62
+ correct, and we want the probability that at least one is correct.
63
+
64
+ Args:
65
+ confidences: List of individual confidence scores
66
+ cap: Maximum return value (default 0.99)
67
+
68
+ Returns:
69
+ Aggregated confidence score, capped at `cap`
70
+ """
71
+ if not confidences:
72
+ return 0.0
73
+
74
+ # 1 - product(1 - c_i)
75
+ complement_product = reduce(lambda acc, c: acc * (1 - c), confidences, 1.0)
76
+ result = 1 - complement_product
77
+
78
+ return min(result, cap)
79
+
80
+
81
+ _EPISTEMIC_DISCOUNT: float = 0.7
82
+ """Discount applied to uncorroborated single-source claims.
83
+
84
+ A claim supported by only one source has inherent uncertainty that
85
+ corroboration resolves. This factor represents the pre-corroboration
86
+ epistemic penalty.
87
+ """
88
+
89
+
90
+ def partial_confidence(
91
+ raw_confidence: float,
92
+ source_reliability: float = 1.0,
93
+ ) -> float:
94
+ """Compute pre-corroboration confidence for a single-source claim.
95
+
96
+ Used when storing a Claim before corroboration has occurred. The result
97
+ is a provisional score; once the claim is corroborated and promoted to
98
+ a Fact, `combined_confidence` should be used to derive the final score.
99
+
100
+ Formula: raw_confidence * source_reliability * EPISTEMIC_DISCOUNT (0.7)
101
+
102
+ The 0.7 epistemic discount reflects that single-source claims carry
103
+ inherent uncertainty regardless of source quality. Corroboration by
104
+ independent sources removes this discount.
105
+
106
+ Args:
107
+ raw_confidence: Base confidence from extraction (0.0 - 1.0).
108
+ source_reliability: Reliability multiplier for the source (0.0 - 1.0,
109
+ default 1.0 for an unqualified source).
110
+
111
+ Returns:
112
+ Provisional confidence score clamped to [0.0, 1.0].
113
+ """
114
+ result = raw_confidence * source_reliability * _EPISTEMIC_DISCOUNT
115
+ return min(max(result, 0.0), 1.0)
116
+
117
+
118
+ def incremental_noisy_or(
119
+ current_aggregate: float,
120
+ new_confidence: float,
121
+ cap: float = 0.99,
122
+ ) -> float:
123
+ """Incrementally update a noisy-OR aggregate with a new confidence.
124
+
125
+ Equivalent to recomputing from scratch but O(1) instead of O(n).
126
+
127
+ Formula: 1 - (1 - current) * (1 - new)
128
+
129
+ Args:
130
+ current_aggregate: Existing aggregated confidence
131
+ new_confidence: New confidence to incorporate
132
+ cap: Maximum return value (default 0.99)
133
+
134
+ Returns:
135
+ Updated aggregated confidence
136
+ """
137
+ result = 1 - (1 - current_aggregate) * (1 - new_confidence)
138
+ return min(result, cap)