stated-confidence 0.1.0__tar.gz
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.
- stated_confidence-0.1.0/.gitignore +11 -0
- stated_confidence-0.1.0/LICENSE +21 -0
- stated_confidence-0.1.0/PKG-INFO +129 -0
- stated_confidence-0.1.0/README.md +106 -0
- stated_confidence-0.1.0/pyproject.toml +60 -0
- stated_confidence-0.1.0/src/stated_confidence/__init__.py +41 -0
- stated_confidence-0.1.0/src/stated_confidence/basis.py +260 -0
- stated_confidence-0.1.0/src/stated_confidence/checks.py +84 -0
- stated_confidence-0.1.0/src/stated_confidence/guidance.py +52 -0
- stated_confidence-0.1.0/src/stated_confidence/levels.py +152 -0
- stated_confidence-0.1.0/src/stated_confidence/model.py +107 -0
- stated_confidence-0.1.0/src/stated_confidence/presentation.py +70 -0
- stated_confidence-0.1.0/src/stated_confidence/py.typed +0 -0
- stated_confidence-0.1.0/src/stated_confidence/pydantic_ai.py +47 -0
- stated_confidence-0.1.0/src/stated_confidence/taxonomy.py +57 -0
- stated_confidence-0.1.0/src/stated_confidence/terms.py +19 -0
- stated_confidence-0.1.0/taxonomy.json +196 -0
- stated_confidence-0.1.0/tests/test_basis.py +89 -0
- stated_confidence-0.1.0/tests/test_checks.py +99 -0
- stated_confidence-0.1.0/tests/test_guidance.py +23 -0
- stated_confidence-0.1.0/tests/test_levels.py +72 -0
- stated_confidence-0.1.0/tests/test_model.py +47 -0
- stated_confidence-0.1.0/tests/test_presentation.py +39 -0
- stated_confidence-0.1.0/tests/test_pydantic_ai.py +127 -0
- stated_confidence-0.1.0/tests/test_taxonomy.py +29 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 John Lockwood
|
|
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.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: stated-confidence
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Make LLM agents state the confidence level and the evidential basis behind each claim.
|
|
5
|
+
Project-URL: Homepage, https://github.com/johnwlockwood/stated-confidence
|
|
6
|
+
Author-email: John Lockwood <johnwlockwood@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: agents,confidence,grounding,hallucination,llm,pydantic,pydantic-ai
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: pydantic>=2.5
|
|
20
|
+
Provides-Extra: pydantic-ai
|
|
21
|
+
Requires-Dist: pydantic-ai-slim>=1.0; extra == 'pydantic-ai'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# stated-confidence
|
|
25
|
+
|
|
26
|
+
Make LLM agents say how sure they are, and what that certainty rests on.
|
|
27
|
+
|
|
28
|
+
Ask a model to attach a confidence **level** and an evidential **basis** to
|
|
29
|
+
each claim it produces and it fabricates less. The level alone is common
|
|
30
|
+
practice; the basis is what does the work. Choosing between "documented
|
|
31
|
+
fact", "expert opinion", and "educated guess" forces a provenance check the
|
|
32
|
+
model would otherwise skip, and a claim it cannot back gets labelled as a
|
|
33
|
+
guess or quietly dropped instead of dressed up as a figure.
|
|
34
|
+
|
|
35
|
+
This package is that schema, the vocabulary behind it, prompt guidance for
|
|
36
|
+
filling it, and the consistency checks that send hedging-without-meaning-it
|
|
37
|
+
back to the model. It was extracted from a production knowledge-graph
|
|
38
|
+
generator where it was observed to sharply reduce invented facts and
|
|
39
|
+
figures. The effect is observed, not yet measured; an evaluation harness is
|
|
40
|
+
planned.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install stated-confidence # pydantic only
|
|
46
|
+
pip install "stated-confidence[pydantic-ai]"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## The shape
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from stated_confidence import Confidence, DataAnalysisBasis
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Finding(BaseModel):
|
|
56
|
+
text: str
|
|
57
|
+
confidence: Confidence[DataAnalysisBasis]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
A `Confidence` has:
|
|
61
|
+
|
|
62
|
+
| field | meaning |
|
|
63
|
+
| ----------- | ------------------------------------------------------------------------- |
|
|
64
|
+
| `level` | `HIGH`, `MEDIUM`, `LOW`, or `SPECULATIVE`. Never a number. |
|
|
65
|
+
| `basis` | The kind of evidence, from a basis set chosen for the domain. |
|
|
66
|
+
| `reasoning` | One or two sentences on why that level and basis apply. |
|
|
67
|
+
| `evidence` | What concretely backs the claim: sources, ids, column names, tool results. |
|
|
68
|
+
| `type` | Optional: `FACTUAL`, `CONSENSUS`, `THEORETICAL`, `SPECULATIVE`. |
|
|
69
|
+
| `label` | Optional localized label for display. |
|
|
70
|
+
|
|
71
|
+
`SPECULATIVE` is not the bottom of the scale. It is the level for an idea
|
|
72
|
+
the model is offering rather than a claim it is making: an extension a
|
|
73
|
+
source suggests, a hypothesis, a what-if. A generator that has somewhere
|
|
74
|
+
honest to put an idea does not dress it up as a fact; take that room away
|
|
75
|
+
and the ideas come back as fabricated "facts" or disappear altogether.
|
|
76
|
+
|
|
77
|
+
The level scale is fixed. The **basis set** is the extension point. Three
|
|
78
|
+
ship:
|
|
79
|
+
|
|
80
|
+
- `GeneralKnowledgeBasis` for claims about the world: documented fact,
|
|
81
|
+
scientific consensus, historical record, industry standard, expert
|
|
82
|
+
opinion, theoretical framework, fictional universe, speculation, educated
|
|
83
|
+
guess.
|
|
84
|
+
- `DataAnalysisBasis` for agents reasoning over data they retrieved: query
|
|
85
|
+
result, computed, schema inference, general knowledge, assumption.
|
|
86
|
+
- `DecisionBasis` for recommendations: policy, measured outcome, precedent,
|
|
87
|
+
trade-off analysis, expert judgment, assumption.
|
|
88
|
+
|
|
89
|
+
Define your own by subclassing `BasisEnum` with a `__terms__` table and a
|
|
90
|
+
`__fallback__` value.
|
|
91
|
+
|
|
92
|
+
## Prompting
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from stated_confidence import confidence_instructions
|
|
96
|
+
|
|
97
|
+
system_prompt += confidence_instructions(DataAnalysisBasis, localized=True)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Pydantic AI
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from pydantic_ai import Agent
|
|
104
|
+
from stated_confidence.pydantic_ai import confidence_output_validator
|
|
105
|
+
|
|
106
|
+
agent = Agent("openai:gpt-5", output_type=Report)
|
|
107
|
+
agent.output_validator(confidence_output_validator())
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Every `Confidence` anywhere in the output is checked. A `HIGH` level on a
|
|
111
|
+
basis of `ASSUMPTION`, a `SPECULATIVE` level on a basis of `DOCUMENTED_FACT`,
|
|
112
|
+
or a non-`HIGH` level with empty reasoning comes back to the model as a
|
|
113
|
+
retry listing what to fix. Pass extra `(ctx, output) -> list[str]` callables for rules that
|
|
114
|
+
need run context, such as requiring that evidence names a column the
|
|
115
|
+
agent's query actually returned.
|
|
116
|
+
|
|
117
|
+
## Lenient parsing, strict prompting
|
|
118
|
+
|
|
119
|
+
Models drift. `"High"` parses. `0.9` parses (as `HIGH`). An invented basis
|
|
120
|
+
value parses as the set's fallback and is logged at `WARNING` on the
|
|
121
|
+
`stated_confidence` logger so the set can grow from what models actually
|
|
122
|
+
say.
|
|
123
|
+
|
|
124
|
+
## Display
|
|
125
|
+
|
|
126
|
+
`describe(value)` returns a label and description for any level, type, or
|
|
127
|
+
basis value; `tone(level)` maps to `positive`, `neutral`, `caution`, or
|
|
128
|
+
`warning` with no CSS framework attached. `taxonomy.json` at the package
|
|
129
|
+
root is the same vocabulary as data, for other languages to consume.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# stated-confidence
|
|
2
|
+
|
|
3
|
+
Make LLM agents say how sure they are, and what that certainty rests on.
|
|
4
|
+
|
|
5
|
+
Ask a model to attach a confidence **level** and an evidential **basis** to
|
|
6
|
+
each claim it produces and it fabricates less. The level alone is common
|
|
7
|
+
practice; the basis is what does the work. Choosing between "documented
|
|
8
|
+
fact", "expert opinion", and "educated guess" forces a provenance check the
|
|
9
|
+
model would otherwise skip, and a claim it cannot back gets labelled as a
|
|
10
|
+
guess or quietly dropped instead of dressed up as a figure.
|
|
11
|
+
|
|
12
|
+
This package is that schema, the vocabulary behind it, prompt guidance for
|
|
13
|
+
filling it, and the consistency checks that send hedging-without-meaning-it
|
|
14
|
+
back to the model. It was extracted from a production knowledge-graph
|
|
15
|
+
generator where it was observed to sharply reduce invented facts and
|
|
16
|
+
figures. The effect is observed, not yet measured; an evaluation harness is
|
|
17
|
+
planned.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install stated-confidence # pydantic only
|
|
23
|
+
pip install "stated-confidence[pydantic-ai]"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## The shape
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from stated_confidence import Confidence, DataAnalysisBasis
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Finding(BaseModel):
|
|
33
|
+
text: str
|
|
34
|
+
confidence: Confidence[DataAnalysisBasis]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A `Confidence` has:
|
|
38
|
+
|
|
39
|
+
| field | meaning |
|
|
40
|
+
| ----------- | ------------------------------------------------------------------------- |
|
|
41
|
+
| `level` | `HIGH`, `MEDIUM`, `LOW`, or `SPECULATIVE`. Never a number. |
|
|
42
|
+
| `basis` | The kind of evidence, from a basis set chosen for the domain. |
|
|
43
|
+
| `reasoning` | One or two sentences on why that level and basis apply. |
|
|
44
|
+
| `evidence` | What concretely backs the claim: sources, ids, column names, tool results. |
|
|
45
|
+
| `type` | Optional: `FACTUAL`, `CONSENSUS`, `THEORETICAL`, `SPECULATIVE`. |
|
|
46
|
+
| `label` | Optional localized label for display. |
|
|
47
|
+
|
|
48
|
+
`SPECULATIVE` is not the bottom of the scale. It is the level for an idea
|
|
49
|
+
the model is offering rather than a claim it is making: an extension a
|
|
50
|
+
source suggests, a hypothesis, a what-if. A generator that has somewhere
|
|
51
|
+
honest to put an idea does not dress it up as a fact; take that room away
|
|
52
|
+
and the ideas come back as fabricated "facts" or disappear altogether.
|
|
53
|
+
|
|
54
|
+
The level scale is fixed. The **basis set** is the extension point. Three
|
|
55
|
+
ship:
|
|
56
|
+
|
|
57
|
+
- `GeneralKnowledgeBasis` for claims about the world: documented fact,
|
|
58
|
+
scientific consensus, historical record, industry standard, expert
|
|
59
|
+
opinion, theoretical framework, fictional universe, speculation, educated
|
|
60
|
+
guess.
|
|
61
|
+
- `DataAnalysisBasis` for agents reasoning over data they retrieved: query
|
|
62
|
+
result, computed, schema inference, general knowledge, assumption.
|
|
63
|
+
- `DecisionBasis` for recommendations: policy, measured outcome, precedent,
|
|
64
|
+
trade-off analysis, expert judgment, assumption.
|
|
65
|
+
|
|
66
|
+
Define your own by subclassing `BasisEnum` with a `__terms__` table and a
|
|
67
|
+
`__fallback__` value.
|
|
68
|
+
|
|
69
|
+
## Prompting
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from stated_confidence import confidence_instructions
|
|
73
|
+
|
|
74
|
+
system_prompt += confidence_instructions(DataAnalysisBasis, localized=True)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Pydantic AI
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from pydantic_ai import Agent
|
|
81
|
+
from stated_confidence.pydantic_ai import confidence_output_validator
|
|
82
|
+
|
|
83
|
+
agent = Agent("openai:gpt-5", output_type=Report)
|
|
84
|
+
agent.output_validator(confidence_output_validator())
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Every `Confidence` anywhere in the output is checked. A `HIGH` level on a
|
|
88
|
+
basis of `ASSUMPTION`, a `SPECULATIVE` level on a basis of `DOCUMENTED_FACT`,
|
|
89
|
+
or a non-`HIGH` level with empty reasoning comes back to the model as a
|
|
90
|
+
retry listing what to fix. Pass extra `(ctx, output) -> list[str]` callables for rules that
|
|
91
|
+
need run context, such as requiring that evidence names a column the
|
|
92
|
+
agent's query actually returned.
|
|
93
|
+
|
|
94
|
+
## Lenient parsing, strict prompting
|
|
95
|
+
|
|
96
|
+
Models drift. `"High"` parses. `0.9` parses (as `HIGH`). An invented basis
|
|
97
|
+
value parses as the set's fallback and is logged at `WARNING` on the
|
|
98
|
+
`stated_confidence` logger so the set can grow from what models actually
|
|
99
|
+
say.
|
|
100
|
+
|
|
101
|
+
## Display
|
|
102
|
+
|
|
103
|
+
`describe(value)` returns a label and description for any level, type, or
|
|
104
|
+
basis value; `tone(level)` maps to `positive`, `neutral`, `caution`, or
|
|
105
|
+
`warning` with no CSS framework attached. `taxonomy.json` at the package
|
|
106
|
+
root is the same vocabulary as data, for other languages to consume.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "stated-confidence"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Make LLM agents state the confidence level and the evidential basis behind each claim."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "John Lockwood", email = "johnwlockwood@gmail.com" }]
|
|
13
|
+
requires-python = ">=3.12"
|
|
14
|
+
keywords = ["llm", "agents", "pydantic", "pydantic-ai", "hallucination", "confidence", "grounding"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = ["pydantic>=2.5"]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
pydantic-ai = ["pydantic-ai-slim>=1.0"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/johnwlockwood/stated-confidence"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/stated_confidence"]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.sdist]
|
|
37
|
+
include = ["src/stated_confidence", "tests", "taxonomy.json", "README.md", "LICENSE"]
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=8.4",
|
|
42
|
+
"pytest-asyncio>=1.0",
|
|
43
|
+
"pydantic-ai-slim>=1.0",
|
|
44
|
+
"ruff>=0.12",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
asyncio_mode = "auto"
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
line-length = 79
|
|
53
|
+
target-version = "py312"
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
select = ["E", "W", "F", "I", "B", "C4", "UP"]
|
|
57
|
+
ignore = ["E501"]
|
|
58
|
+
|
|
59
|
+
[tool.ruff.format]
|
|
60
|
+
quote-style = "double"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""stated-confidence: make agents say how sure they are, and on what basis.
|
|
2
|
+
|
|
3
|
+
An LLM asked to attach a confidence *level* and an evidential *basis* to
|
|
4
|
+
each claim it makes tends to fabricate less: naming the kind of evidence
|
|
5
|
+
forces a provenance check the model would otherwise skip. This package is
|
|
6
|
+
that schema, the vocabulary behind it, prompt guidance for filling it, and
|
|
7
|
+
the consistency checks that send hedging-without-meaning-it back to the
|
|
8
|
+
model.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .basis import (
|
|
12
|
+
BasisEnum,
|
|
13
|
+
DataAnalysisBasis,
|
|
14
|
+
DecisionBasis,
|
|
15
|
+
GeneralKnowledgeBasis,
|
|
16
|
+
)
|
|
17
|
+
from .checks import check_all, check_consistency, iter_confidences
|
|
18
|
+
from .guidance import confidence_instructions
|
|
19
|
+
from .levels import ConfidenceLevel, ConfidenceType
|
|
20
|
+
from .model import Confidence
|
|
21
|
+
from .presentation import SCALE_EXPLANATION, Tone, describe, tone
|
|
22
|
+
from .terms import Term
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"SCALE_EXPLANATION",
|
|
26
|
+
"BasisEnum",
|
|
27
|
+
"Confidence",
|
|
28
|
+
"ConfidenceLevel",
|
|
29
|
+
"ConfidenceType",
|
|
30
|
+
"DataAnalysisBasis",
|
|
31
|
+
"DecisionBasis",
|
|
32
|
+
"GeneralKnowledgeBasis",
|
|
33
|
+
"Term",
|
|
34
|
+
"Tone",
|
|
35
|
+
"check_all",
|
|
36
|
+
"check_consistency",
|
|
37
|
+
"confidence_instructions",
|
|
38
|
+
"describe",
|
|
39
|
+
"iter_confidences",
|
|
40
|
+
"tone",
|
|
41
|
+
]
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""Basis vocabularies: *what kind of evidence* stands behind a claim.
|
|
2
|
+
|
|
3
|
+
The level scale is fixed; the basis set is the extension point. A domain
|
|
4
|
+
declares its own by subclassing ``BasisEnum`` and filling ``__terms__``
|
|
5
|
+
and ``__fallback__``. Three sets ship: general knowledge, data analysis,
|
|
6
|
+
and decisions.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from enum import StrEnum
|
|
11
|
+
from typing import ClassVar
|
|
12
|
+
|
|
13
|
+
from .levels import normalize_token
|
|
14
|
+
from .terms import Term
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("stated_confidence")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BasisEnum(StrEnum):
|
|
20
|
+
"""Base class for basis vocabularies.
|
|
21
|
+
|
|
22
|
+
``__terms__`` maps each value to its ``Term``; ``__fallback__`` is the
|
|
23
|
+
value substituted for anything unrecognized. Models occasionally invent
|
|
24
|
+
plausible values (one emitted ``INDUSTRY_STANDARD`` before it existed),
|
|
25
|
+
and one bad string must not fail a whole response. The substitution is
|
|
26
|
+
logged at WARNING on the ``stated_confidence`` logger so a basis set
|
|
27
|
+
can be grown deliberately from what models actually say.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
__terms__: ClassVar[dict[str, Term]] = {}
|
|
31
|
+
__fallback__: ClassVar[str] = ""
|
|
32
|
+
__registry__: ClassVar[list[type["BasisEnum"]]] = []
|
|
33
|
+
|
|
34
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
35
|
+
super().__init_subclass__(**kwargs)
|
|
36
|
+
BasisEnum.__registry__.append(cls)
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def registered(cls) -> "list[type[BasisEnum]]":
|
|
40
|
+
"""Every basis set defined so far, shipped and user-defined."""
|
|
41
|
+
return list(cls.__registry__)
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def _missing_(cls, value: object) -> "BasisEnum | None":
|
|
45
|
+
if not isinstance(value, str):
|
|
46
|
+
return None
|
|
47
|
+
token = normalize_token(value)
|
|
48
|
+
for member in cls:
|
|
49
|
+
if member.value == token:
|
|
50
|
+
return member
|
|
51
|
+
if not cls.__fallback__:
|
|
52
|
+
return None
|
|
53
|
+
logger.warning(
|
|
54
|
+
"Unrecognized %s %r; using %s",
|
|
55
|
+
cls.__name__,
|
|
56
|
+
value,
|
|
57
|
+
cls.__fallback__,
|
|
58
|
+
)
|
|
59
|
+
return cls(cls.__fallback__)
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def fallback(cls) -> "BasisEnum":
|
|
63
|
+
return cls(cls.__fallback__)
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def term(self) -> Term:
|
|
67
|
+
return type(self).__terms__[self.value]
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def strength(self) -> str | None:
|
|
71
|
+
return self.term.strength
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def weakest(cls) -> list["BasisEnum"]:
|
|
75
|
+
return [member for member in cls if member.strength == "weak"]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class GeneralKnowledgeBasis(BasisEnum):
|
|
79
|
+
"""For claims about the world: facts, history, science, fiction."""
|
|
80
|
+
|
|
81
|
+
DOCUMENTED_FACT = "DOCUMENTED_FACT"
|
|
82
|
+
SCIENTIFIC_CONSENSUS = "SCIENTIFIC_CONSENSUS"
|
|
83
|
+
HISTORICAL_RECORD = "HISTORICAL_RECORD"
|
|
84
|
+
INDUSTRY_STANDARD = "INDUSTRY_STANDARD"
|
|
85
|
+
EXPERT_OPINION = "EXPERT_OPINION"
|
|
86
|
+
THEORETICAL_FRAMEWORK = "THEORETICAL_FRAMEWORK"
|
|
87
|
+
FICTIONAL_UNIVERSE = "FICTIONAL_UNIVERSE"
|
|
88
|
+
SPECULATION = "SPECULATION"
|
|
89
|
+
EDUCATED_GUESS = "EDUCATED_GUESS"
|
|
90
|
+
|
|
91
|
+
__fallback__ = "EXPERT_OPINION"
|
|
92
|
+
__terms__ = {
|
|
93
|
+
"DOCUMENTED_FACT": Term(
|
|
94
|
+
label="Documented fact",
|
|
95
|
+
description="Stated directly in recorded, citable sources.",
|
|
96
|
+
guidance="recorded evidence you could cite",
|
|
97
|
+
strength="strong",
|
|
98
|
+
),
|
|
99
|
+
"SCIENTIFIC_CONSENSUS": Term(
|
|
100
|
+
label="Scientific consensus",
|
|
101
|
+
description="Supported by peer-reviewed scientific agreement.",
|
|
102
|
+
guidance="peer-reviewed agreement",
|
|
103
|
+
strength="strong",
|
|
104
|
+
),
|
|
105
|
+
"HISTORICAL_RECORD": Term(
|
|
106
|
+
label="Historical record",
|
|
107
|
+
description="Part of the documented historical record.",
|
|
108
|
+
guidance="documented history",
|
|
109
|
+
strength="strong",
|
|
110
|
+
),
|
|
111
|
+
"INDUSTRY_STANDARD": Term(
|
|
112
|
+
label="Industry standard",
|
|
113
|
+
description=(
|
|
114
|
+
"Established standards or widespread industry practice."
|
|
115
|
+
),
|
|
116
|
+
guidance=(
|
|
117
|
+
"established standards and widespread engineering practice"
|
|
118
|
+
),
|
|
119
|
+
strength="strong",
|
|
120
|
+
),
|
|
121
|
+
"EXPERT_OPINION": Term(
|
|
122
|
+
label="Expert opinion",
|
|
123
|
+
description="Based on the judgment of subject-matter experts.",
|
|
124
|
+
guidance="the judgment of subject-matter experts",
|
|
125
|
+
strength="moderate",
|
|
126
|
+
),
|
|
127
|
+
"THEORETICAL_FRAMEWORK": Term(
|
|
128
|
+
label="Theoretical framework",
|
|
129
|
+
description="Follows from an established theory or model.",
|
|
130
|
+
guidance="an established theory or model",
|
|
131
|
+
strength="moderate",
|
|
132
|
+
),
|
|
133
|
+
"FICTIONAL_UNIVERSE": Term(
|
|
134
|
+
label="Fictional universe",
|
|
135
|
+
description="True within a fictional or creative work.",
|
|
136
|
+
guidance="creative content that is true within its fiction",
|
|
137
|
+
strength="moderate",
|
|
138
|
+
),
|
|
139
|
+
"SPECULATION": Term(
|
|
140
|
+
label="Speculation",
|
|
141
|
+
description="An unverified theory or possibility.",
|
|
142
|
+
guidance="unverified theories",
|
|
143
|
+
strength="weak",
|
|
144
|
+
),
|
|
145
|
+
"EDUCATED_GUESS": Term(
|
|
146
|
+
label="Educated guess",
|
|
147
|
+
description="A plausible inference made without direct evidence.",
|
|
148
|
+
guidance="plausible inference with no direct evidence",
|
|
149
|
+
strength="weak",
|
|
150
|
+
),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class DataAnalysisBasis(BasisEnum):
|
|
155
|
+
"""For claims an agent makes about data it retrieved or computed."""
|
|
156
|
+
|
|
157
|
+
QUERY_RESULT = "QUERY_RESULT"
|
|
158
|
+
COMPUTED = "COMPUTED"
|
|
159
|
+
SCHEMA_INFERENCE = "SCHEMA_INFERENCE"
|
|
160
|
+
GENERAL_KNOWLEDGE = "GENERAL_KNOWLEDGE"
|
|
161
|
+
ASSUMPTION = "ASSUMPTION"
|
|
162
|
+
|
|
163
|
+
__fallback__ = "ASSUMPTION"
|
|
164
|
+
__terms__ = {
|
|
165
|
+
"QUERY_RESULT": Term(
|
|
166
|
+
label="Query result",
|
|
167
|
+
description="Read directly from the rows the query returned.",
|
|
168
|
+
guidance="a value read directly from returned rows",
|
|
169
|
+
strength="strong",
|
|
170
|
+
),
|
|
171
|
+
"COMPUTED": Term(
|
|
172
|
+
label="Computed",
|
|
173
|
+
description=(
|
|
174
|
+
"Arithmetic over the returned rows, such as a ratio, "
|
|
175
|
+
"difference, or trend."
|
|
176
|
+
),
|
|
177
|
+
guidance=(
|
|
178
|
+
"arithmetic you did over returned rows "
|
|
179
|
+
"(a ratio, difference, or trend)"
|
|
180
|
+
),
|
|
181
|
+
strength="strong",
|
|
182
|
+
),
|
|
183
|
+
"SCHEMA_INFERENCE": Term(
|
|
184
|
+
label="Schema inference",
|
|
185
|
+
description=(
|
|
186
|
+
"Inferred from table or column names and the schema, "
|
|
187
|
+
"not verified against data."
|
|
188
|
+
),
|
|
189
|
+
guidance=(
|
|
190
|
+
"something inferred from table or column names "
|
|
191
|
+
"rather than checked against data"
|
|
192
|
+
),
|
|
193
|
+
strength="moderate",
|
|
194
|
+
),
|
|
195
|
+
"GENERAL_KNOWLEDGE": Term(
|
|
196
|
+
label="General knowledge",
|
|
197
|
+
description=(
|
|
198
|
+
"Background knowledge about the domain, not from this data."
|
|
199
|
+
),
|
|
200
|
+
guidance="background knowledge about the domain, not this data",
|
|
201
|
+
strength="moderate",
|
|
202
|
+
),
|
|
203
|
+
"ASSUMPTION": Term(
|
|
204
|
+
label="Assumption",
|
|
205
|
+
description="A premise that was not checked against the data.",
|
|
206
|
+
guidance="a premise you did not check against the data",
|
|
207
|
+
strength="weak",
|
|
208
|
+
),
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class DecisionBasis(BasisEnum):
|
|
213
|
+
"""For recommendations and decisions."""
|
|
214
|
+
|
|
215
|
+
POLICY = "POLICY"
|
|
216
|
+
MEASURED_OUTCOME = "MEASURED_OUTCOME"
|
|
217
|
+
PRECEDENT = "PRECEDENT"
|
|
218
|
+
TRADEOFF_ANALYSIS = "TRADEOFF_ANALYSIS"
|
|
219
|
+
EXPERT_JUDGMENT = "EXPERT_JUDGMENT"
|
|
220
|
+
ASSUMPTION = "ASSUMPTION"
|
|
221
|
+
|
|
222
|
+
__fallback__ = "ASSUMPTION"
|
|
223
|
+
__terms__ = {
|
|
224
|
+
"POLICY": Term(
|
|
225
|
+
label="Policy",
|
|
226
|
+
description="Required by a stated policy, rule, or constraint.",
|
|
227
|
+
guidance="a stated policy, rule, or hard constraint",
|
|
228
|
+
strength="strong",
|
|
229
|
+
),
|
|
230
|
+
"MEASURED_OUTCOME": Term(
|
|
231
|
+
label="Measured outcome",
|
|
232
|
+
description="Observed results from measurement or experiment.",
|
|
233
|
+
guidance="results actually measured or observed",
|
|
234
|
+
strength="strong",
|
|
235
|
+
),
|
|
236
|
+
"PRECEDENT": Term(
|
|
237
|
+
label="Precedent",
|
|
238
|
+
description="What was done in comparable past cases.",
|
|
239
|
+
guidance="what comparable past cases did",
|
|
240
|
+
strength="moderate",
|
|
241
|
+
),
|
|
242
|
+
"TRADEOFF_ANALYSIS": Term(
|
|
243
|
+
label="Trade-off analysis",
|
|
244
|
+
description="Weighing the options against stated criteria.",
|
|
245
|
+
guidance="weighing the options against stated criteria",
|
|
246
|
+
strength="moderate",
|
|
247
|
+
),
|
|
248
|
+
"EXPERT_JUDGMENT": Term(
|
|
249
|
+
label="Expert judgment",
|
|
250
|
+
description="Based on the judgment of subject-matter experts.",
|
|
251
|
+
guidance="the judgment of subject-matter experts",
|
|
252
|
+
strength="moderate",
|
|
253
|
+
),
|
|
254
|
+
"ASSUMPTION": Term(
|
|
255
|
+
label="Assumption",
|
|
256
|
+
description="A premise that was taken as given, not verified.",
|
|
257
|
+
guidance="a premise taken as given without verification",
|
|
258
|
+
strength="weak",
|
|
259
|
+
),
|
|
260
|
+
}
|