engineering-argument-language 3.2.3__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.
- eal/__init__.py +3 -0
- eal/abstractions.py +144 -0
- eal/acquisition_coordination.py +80 -0
- eal/api_load_methods.py +77 -0
- eal/aspic.py +478 -0
- eal/aspic_compiler.py +445 -0
- eal/aspic_export.py +309 -0
- eal/builtin_methods.py +115 -0
- eal/catalogue.py +384 -0
- eal/cli.py +204 -0
- eal/client_transports.py +69 -0
- eal/collection_identity.py +28 -0
- eal/collection_scheduler.py +72 -0
- eal/command_process.py +118 -0
- eal/command_supervisor.py +112 -0
- eal/composition.py +531 -0
- eal/credentials.py +33 -0
- eal/dialectic.py +321 -0
- eal/discovery.py +127 -0
- eal/evaluator.py +619 -0
- eal/expressions.py +404 -0
- eal/extensions.py +38 -0
- eal/formatter.py +156 -0
- eal/generated/EALLexer.py +434 -0
- eal/generated/EALParser.py +6559 -0
- eal/generated/EALVisitor.py +393 -0
- eal/generated/__init__.py +1 -0
- eal/host.py +179 -0
- eal/host_redaction.py +51 -0
- eal/knowledge.py +96 -0
- eal/limits.py +88 -0
- eal/mcp_guard.py +56 -0
- eal/methods.py +463 -0
- eal/model.py +266 -0
- eal/model_context.py +55 -0
- eal/modes.py +121 -0
- eal/observation_reuse.py +128 -0
- eal/operation_contracts.py +25 -0
- eal/operations.py +155 -0
- eal/packets.py +604 -0
- eal/parser.py +407 -0
- eal/planning.py +136 -0
- eal/propositions.py +231 -0
- eal/reachability.py +85 -0
- eal/reasoning/__init__.py +25 -0
- eal/reasoning/abductive.py +45 -0
- eal/reasoning/analogical.py +41 -0
- eal/reasoning/causal.py +46 -0
- eal/reasoning/counterfactual.py +64 -0
- eal/reasoning/deductive.py +72 -0
- eal/reasoning/inductive.py +29 -0
- eal/reasoning/strategy.py +18 -0
- eal/reasoning/structured.py +11 -0
- eal/reasoning/temporal.py +47 -0
- eal/reasoning/validation.py +90 -0
- eal/registered_assessment.py +181 -0
- eal/runtime.py +454 -0
- eal/sampled_negative.py +131 -0
- eal/scope_transfer.py +59 -0
- eal/semantics.py +656 -0
- eal/server.py +79 -0
- eal/server_auth.py +37 -0
- eal/server_settings.py +258 -0
- eal/source_printer.py +129 -0
- eal/store.py +272 -0
- eal/tool_acquisition.py +383 -0
- engineering_argument_language-3.2.3.dist-info/METADATA +188 -0
- engineering_argument_language-3.2.3.dist-info/RECORD +72 -0
- engineering_argument_language-3.2.3.dist-info/WHEEL +5 -0
- engineering_argument_language-3.2.3.dist-info/entry_points.txt +4 -0
- engineering_argument_language-3.2.3.dist-info/licenses/LICENSE +24 -0
- engineering_argument_language-3.2.3.dist-info/top_level.txt +1 -0
eal/operations.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Bind the shared MCP operation catalogue to one EAL application service."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Collection
|
|
6
|
+
from inspect import Parameter, signature
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from .runtime import ReasoningService
|
|
10
|
+
from .catalogue import WorkspaceKnowledgeCatalogue
|
|
11
|
+
from .registered_assessment import RegisteredAssessmentHost
|
|
12
|
+
from .operation_contracts import OPERATION_FIELDS
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_operations(service: ReasoningService, *,
|
|
16
|
+
known_entries: Collection[str] | None = None,
|
|
17
|
+
exposure: str | None = None) -> dict[str, Callable[..., dict[str, Any]]]:
|
|
18
|
+
"""Expose generic language tools or a selected registered-source catalogue."""
|
|
19
|
+
if (known_entries is not None and
|
|
20
|
+
(isinstance(known_entries, (str, bytes)) or
|
|
21
|
+
not isinstance(known_entries, Collection))):
|
|
22
|
+
raise ValueError("Known entries must be a bounded collection of registered IDs")
|
|
23
|
+
selected_known = tuple(known_entries or ())
|
|
24
|
+
if (len(selected_known) > 128
|
|
25
|
+
or any(not isinstance(identifier, str) or not identifier for identifier in selected_known)
|
|
26
|
+
or len(set(selected_known)) != len(selected_known)):
|
|
27
|
+
raise ValueError("Known entries must contain up to 128 unique registered IDs")
|
|
28
|
+
selected_exposure = exposure or ("registered" if selected_known else "operator")
|
|
29
|
+
if selected_exposure not in {"operator", "registered"}:
|
|
30
|
+
raise ValueError("exposure must be operator or registered")
|
|
31
|
+
if selected_exposure == "registered" and not selected_known:
|
|
32
|
+
raise ValueError("Registered exposure requires at least one known entry")
|
|
33
|
+
if selected_exposure == "operator" and selected_known:
|
|
34
|
+
raise ValueError("Operator exposure conflicts with known entries")
|
|
35
|
+
catalogue = WorkspaceKnowledgeCatalogue(service) if selected_known else None
|
|
36
|
+
for identifier in selected_known:
|
|
37
|
+
catalogue.get(identifier)
|
|
38
|
+
known = RegisteredAssessmentHost(service, catalogue) if catalogue else None
|
|
39
|
+
|
|
40
|
+
operations: dict[str, Callable[..., dict[str, Any]]] = {}
|
|
41
|
+
|
|
42
|
+
def register(handler):
|
|
43
|
+
name = handler.__name__
|
|
44
|
+
short_name = name.removeprefix("eal_")
|
|
45
|
+
required, optional = OPERATION_FIELDS[short_name]
|
|
46
|
+
parameters = signature(handler).parameters
|
|
47
|
+
actual_required = {key for key, value in parameters.items() if value.default is Parameter.empty}
|
|
48
|
+
if actual_required != required or set(parameters) != required | optional:
|
|
49
|
+
raise ValueError(f"Operation signature disagrees with its catalogue: {name}")
|
|
50
|
+
operations[name] = handler
|
|
51
|
+
return handler
|
|
52
|
+
|
|
53
|
+
if selected_known:
|
|
54
|
+
def source_summary(entry: dict[str, Any]) -> dict[str, Any]:
|
|
55
|
+
"""Expose discoverable claim metadata without the registered context or source."""
|
|
56
|
+
return {"entry_id": entry["entry_id"], "path": entry["path"],
|
|
57
|
+
"label": entry["label"], "source_digest": entry["source_digest"],
|
|
58
|
+
"claims": entry["claims"], "claim_metadata": entry["claim_metadata"]}
|
|
59
|
+
|
|
60
|
+
@register
|
|
61
|
+
def eal_sources(limit: int = 50, offset: int = 0) -> dict[str, Any]:
|
|
62
|
+
"""List developer-registered EAL sources and their selectable claims."""
|
|
63
|
+
if type(limit) is not int or not 1 <= limit <= 100:
|
|
64
|
+
raise ValueError("limit must be an integer from 1 through 100")
|
|
65
|
+
if type(offset) is not int or not 0 <= offset <= 10_000:
|
|
66
|
+
raise ValueError("offset must be an integer from 0 through 10000")
|
|
67
|
+
visible = sorted((catalogue.get(identifier) for identifier in selected_known),
|
|
68
|
+
key=lambda item: item["path"])
|
|
69
|
+
return {"sources": [source_summary(item) for item in visible[offset:offset + limit]],
|
|
70
|
+
"limit": limit, "offset": offset}
|
|
71
|
+
|
|
72
|
+
@register
|
|
73
|
+
def eal_find_claims(query: str | None = None, claim: str | None = None,
|
|
74
|
+
limit: int = 50) -> dict[str, Any]:
|
|
75
|
+
"""Find registered claim metadata; use an exact entry ID and claim to assess."""
|
|
76
|
+
if type(limit) is not int or not 1 <= limit <= 100:
|
|
77
|
+
raise ValueError("limit must be an integer from 1 through 100")
|
|
78
|
+
matches = []
|
|
79
|
+
for identifier in selected_known:
|
|
80
|
+
entry = catalogue.get(identifier)
|
|
81
|
+
matches.extend(catalogue.find(query, claim=claim, path=entry["path"], limit=1))
|
|
82
|
+
return {"matches": [source_summary(item) for item in
|
|
83
|
+
sorted(matches, key=lambda item: item["path"])[:limit]]}
|
|
84
|
+
|
|
85
|
+
@register
|
|
86
|
+
def eal_assess_known(entry_id: str, claim: str) -> dict[str, Any]:
|
|
87
|
+
"""Reuse compatible observations or collect missing evidence for a registered claim."""
|
|
88
|
+
if entry_id not in selected_known:
|
|
89
|
+
raise ValueError("Registered source is not exposed by this server")
|
|
90
|
+
return known.assess(entry_id, claim)
|
|
91
|
+
|
|
92
|
+
if not selected_known:
|
|
93
|
+
|
|
94
|
+
@register
|
|
95
|
+
def eal_describe() -> dict[str, Any]:
|
|
96
|
+
"""Discover supported language versions, syntax, method contracts and interpretation limits."""
|
|
97
|
+
return service.describe()
|
|
98
|
+
|
|
99
|
+
@register
|
|
100
|
+
def eal_format(source: str) -> dict[str, Any]:
|
|
101
|
+
"""Return canonical checked EAL source; changed source bytes require new collection bindings."""
|
|
102
|
+
return service.format(source)
|
|
103
|
+
|
|
104
|
+
@register
|
|
105
|
+
def eal_validate(source: str) -> dict[str, Any]:
|
|
106
|
+
"""Parse EAL and check names, types and dependency structure without running tools."""
|
|
107
|
+
return service.validate(source)
|
|
108
|
+
|
|
109
|
+
@register
|
|
110
|
+
def eal_plan(source: str, claim: str) -> dict[str, Any]:
|
|
111
|
+
"""Plan all evidence for a claim, including alternative supports and objections."""
|
|
112
|
+
return service.plan(source, claim)
|
|
113
|
+
|
|
114
|
+
@register
|
|
115
|
+
def eal_collect(source: str, context: dict, evidence_ids: list[str] | None = None) -> dict[str, Any]:
|
|
116
|
+
"""Run the configured collectors for selected evidence; return collection_id."""
|
|
117
|
+
return service.collect(source, context, evidence_ids)
|
|
118
|
+
|
|
119
|
+
@register
|
|
120
|
+
def eal_collect_claim(source: str, context: dict, claim: str) -> dict[str, Any]:
|
|
121
|
+
"""Collect the complete declared evidence closure for a claim."""
|
|
122
|
+
return service.collect_claim(source, context, claim)
|
|
123
|
+
|
|
124
|
+
@register
|
|
125
|
+
def eal_reason(source: str, context: dict, collection_id: str | None = None, now: str | None = None) -> dict[str, Any]:
|
|
126
|
+
"""Evaluate declared support and objections at an explicit or current UTC time."""
|
|
127
|
+
return service.reason(source, context, collection_id, now)
|
|
128
|
+
|
|
129
|
+
@register
|
|
130
|
+
def eal_compile_aspic(source: str, context: dict, collection_id: str,
|
|
131
|
+
goal: str, now: str | None = None, semantics: str = 'grounded',
|
|
132
|
+
query_mode: str = 'sceptical', preference: str | None = None) -> dict[str, Any]:
|
|
133
|
+
"""Compile checked EAL routes to an opt-in bounded ASPIC+ snapshot with a source map."""
|
|
134
|
+
return service.compile_aspic(source, context, collection_id, goal, now,
|
|
135
|
+
semantics=semantics, query_mode=query_mode, preference=preference)
|
|
136
|
+
|
|
137
|
+
@register
|
|
138
|
+
def eal_explain(assessment_id: str, claim: str | None = None) -> dict[str, Any]:
|
|
139
|
+
"""Retrieve a persisted reasoning result and its dependency explanations."""
|
|
140
|
+
return service.explain(assessment_id, claim)
|
|
141
|
+
|
|
142
|
+
@register
|
|
143
|
+
def eal_packet(assessment_id: str, claim: str | None = None) -> dict[str, Any]:
|
|
144
|
+
"""Return compact claim results with a reference to the full explanation."""
|
|
145
|
+
return service.packet(assessment_id, claim)
|
|
146
|
+
|
|
147
|
+
@register
|
|
148
|
+
def eal_grounded(arguments: list[str], attacks: list[list[str]]) -> dict[str, Any]:
|
|
149
|
+
"""Compute Dung grounded semantics for an explicitly supplied finite attack graph."""
|
|
150
|
+
from .dialectic import solve_grounded
|
|
151
|
+
from .limits import using_limits
|
|
152
|
+
with using_limits(service.limits):
|
|
153
|
+
return solve_grounded(arguments, attacks)
|
|
154
|
+
|
|
155
|
+
return operations
|