speclogician 0.0.0b1__tar.gz → 0.0.0.dev1__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.
- speclogician-0.0.0.dev1/PKG-INFO +21 -0
- speclogician-0.0.0.dev1/README.md +5 -0
- {speclogician-0.0.0b1 → speclogician-0.0.0.dev1}/pyproject.toml +1 -8
- speclogician-0.0.0.dev1/src/speclogician/agent/funcs.py +29 -0
- speclogician-0.0.0.dev1/src/speclogician/cmd/agent_cmd.py +89 -0
- speclogician-0.0.0.dev1/src/speclogician/cmd/data_cmd.py +24 -0
- speclogician-0.0.0.dev1/src/speclogician/cmd/model_cmd.py +42 -0
- speclogician-0.0.0.dev1/src/speclogician/cmd/overlay_cmd.py +30 -0
- speclogician-0.0.0.dev1/src/speclogician/cmd/scenario_cmd.py +61 -0
- speclogician-0.0.0.dev1/src/speclogician/cmd/state_cmd.py +52 -0
- speclogician-0.0.0.dev1/src/speclogician/data/artifact.py +21 -0
- speclogician-0.0.0.dev1/src/speclogician/data/container.py +36 -0
- {speclogician-0.0.0b1 → speclogician-0.0.0.dev1}/src/speclogician/data/mapping.py +18 -17
- speclogician-0.0.0.dev1/src/speclogician/data/refs.py +25 -0
- speclogician-0.0.0.dev1/src/speclogician/data/reports.py +11 -0
- speclogician-0.0.0.dev1/src/speclogician/data/traces.py +35 -0
- speclogician-0.0.0.dev1/src/speclogician/llms/llmtools.py +102 -0
- speclogician-0.0.0.dev1/src/speclogician/llms/overlay.py +264 -0
- speclogician-0.0.0.dev1/src/speclogician/main.py +73 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/component.py +15 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/conflict.py +12 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/domain.py +162 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/model.py +206 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/predicates.py +57 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/report.py +33 -0
- speclogician-0.0.0.dev1/src/speclogician/modeling/scenario.py +194 -0
- speclogician-0.0.0.dev1/src/speclogician/sl_cmd.py +76 -0
- speclogician-0.0.0.dev1/src/speclogician/state/change.py +148 -0
- speclogician-0.0.0.dev1/src/speclogician/state/state.py +249 -0
- speclogician-0.0.0.dev1/src/speclogician/tui/box.tcss +10 -0
- speclogician-0.0.0.dev1/src/speclogician/tui/tui.py +131 -0
- speclogician-0.0.0.dev1/src/speclogician/utils/__init__.py +9 -0
- speclogician-0.0.0.dev1/src/speclogician/utils/imx.py +195 -0
- speclogician-0.0.0.dev1/src/speclogician/utils/load.py +44 -0
- speclogician-0.0.0.dev1/src/speclogician/utils/prompt.md +1 -0
- speclogician-0.0.0b1/PKG-INFO +0 -116
- speclogician-0.0.0b1/README.md +0 -100
- speclogician-0.0.0b1/src/speclogician/commands/__init__.py +0 -15
- speclogician-0.0.0b1/src/speclogician/commands/cmd_ch.py +0 -616
- speclogician-0.0.0b1/src/speclogician/commands/cmd_find.py +0 -256
- speclogician-0.0.0b1/src/speclogician/commands/cmd_view.py +0 -202
- speclogician-0.0.0b1/src/speclogician/commands/runner.py +0 -149
- speclogician-0.0.0b1/src/speclogician/commands/utils.py +0 -101
- speclogician-0.0.0b1/src/speclogician/data/artifact.py +0 -63
- speclogician-0.0.0b1/src/speclogician/data/container.py +0 -402
- speclogician-0.0.0b1/src/speclogician/data/refs.py +0 -24
- speclogician-0.0.0b1/src/speclogician/data/traces.py +0 -26
- speclogician-0.0.0b1/src/speclogician/demos/.DS_Store +0 -0
- speclogician-0.0.0b1/src/speclogician/demos/cmd_demo.py +0 -278
- speclogician-0.0.0b1/src/speclogician/demos/loader.py +0 -135
- speclogician-0.0.0b1/src/speclogician/demos/model.py +0 -27
- speclogician-0.0.0b1/src/speclogician/demos/runner.py +0 -51
- speclogician-0.0.0b1/src/speclogician/logic/__init__.py +0 -11
- speclogician-0.0.0b1/src/speclogician/logic/api/__init__.py +0 -29
- speclogician-0.0.0b1/src/speclogician/logic/api/client.py +0 -606
- speclogician-0.0.0b1/src/speclogician/logic/api/decomp.py +0 -67
- speclogician-0.0.0b1/src/speclogician/logic/api/scenario.py +0 -102
- speclogician-0.0.0b1/src/speclogician/logic/api/traces.py +0 -59
- speclogician-0.0.0b1/src/speclogician/logic/lib/__init__.py +0 -19
- speclogician-0.0.0b1/src/speclogician/logic/lib/complement.py +0 -107
- speclogician-0.0.0b1/src/speclogician/logic/lib/domain_model.py +0 -59
- speclogician-0.0.0b1/src/speclogician/logic/lib/predicates.py +0 -151
- speclogician-0.0.0b1/src/speclogician/logic/lib/scenarios.py +0 -369
- speclogician-0.0.0b1/src/speclogician/logic/lib/traces.py +0 -114
- speclogician-0.0.0b1/src/speclogician/logic/lib/transitions.py +0 -104
- speclogician-0.0.0b1/src/speclogician/logic/main.py +0 -246
- speclogician-0.0.0b1/src/speclogician/logic/strings.py +0 -194
- speclogician-0.0.0b1/src/speclogician/logic/utils.py +0 -135
- speclogician-0.0.0b1/src/speclogician/main.py +0 -139
- speclogician-0.0.0b1/src/speclogician/modeling/__init__.py +0 -31
- speclogician-0.0.0b1/src/speclogician/modeling/complement.py +0 -104
- speclogician-0.0.0b1/src/speclogician/modeling/component.py +0 -71
- speclogician-0.0.0b1/src/speclogician/modeling/conflict.py +0 -26
- speclogician-0.0.0b1/src/speclogician/modeling/domain.py +0 -349
- speclogician-0.0.0b1/src/speclogician/modeling/predicates.py +0 -59
- speclogician-0.0.0b1/src/speclogician/modeling/scenario.py +0 -162
- speclogician-0.0.0b1/src/speclogician/modeling/spec.py +0 -306
- speclogician-0.0.0b1/src/speclogician/modeling/spec_stats.py +0 -39
- speclogician-0.0.0b1/src/speclogician/presentation/api.py +0 -244
- speclogician-0.0.0b1/src/speclogician/presentation/builders/_links.py +0 -44
- speclogician-0.0.0b1/src/speclogician/presentation/builders/container.py +0 -53
- speclogician-0.0.0b1/src/speclogician/presentation/builders/data_artifact.py +0 -42
- speclogician-0.0.0b1/src/speclogician/presentation/builders/domain.py +0 -54
- speclogician-0.0.0b1/src/speclogician/presentation/builders/instances_list.py +0 -38
- speclogician-0.0.0b1/src/speclogician/presentation/builders/predicate.py +0 -51
- speclogician-0.0.0b1/src/speclogician/presentation/builders/recommendations.py +0 -41
- speclogician-0.0.0b1/src/speclogician/presentation/builders/scenario.py +0 -41
- speclogician-0.0.0b1/src/speclogician/presentation/builders/scenario_complement.py +0 -82
- speclogician-0.0.0b1/src/speclogician/presentation/builders/smart_find.py +0 -39
- speclogician-0.0.0b1/src/speclogician/presentation/builders/spec.py +0 -39
- speclogician-0.0.0b1/src/speclogician/presentation/builders/state_diff.py +0 -150
- speclogician-0.0.0b1/src/speclogician/presentation/builders/state_instance.py +0 -42
- speclogician-0.0.0b1/src/speclogician/presentation/builders/state_instance_summary.py +0 -84
- speclogician-0.0.0b1/src/speclogician/presentation/builders/trace.py +0 -58
- speclogician-0.0.0b1/src/speclogician/presentation/ctx.py +0 -38
- speclogician-0.0.0b1/src/speclogician/presentation/models/container.py +0 -44
- speclogician-0.0.0b1/src/speclogician/presentation/models/data_artifact.py +0 -33
- speclogician-0.0.0b1/src/speclogician/presentation/models/domain.py +0 -50
- speclogician-0.0.0b1/src/speclogician/presentation/models/instances_list.py +0 -23
- speclogician-0.0.0b1/src/speclogician/presentation/models/predicate.py +0 -60
- speclogician-0.0.0b1/src/speclogician/presentation/models/recommendations.py +0 -34
- speclogician-0.0.0b1/src/speclogician/presentation/models/scenario.py +0 -31
- speclogician-0.0.0b1/src/speclogician/presentation/models/scenario_complement.py +0 -40
- speclogician-0.0.0b1/src/speclogician/presentation/models/smart_find.py +0 -34
- speclogician-0.0.0b1/src/speclogician/presentation/models/spec.py +0 -32
- speclogician-0.0.0b1/src/speclogician/presentation/models/state_diff.py +0 -34
- speclogician-0.0.0b1/src/speclogician/presentation/models/state_instance.py +0 -31
- speclogician-0.0.0b1/src/speclogician/presentation/models/state_instance_summary.py +0 -102
- speclogician-0.0.0b1/src/speclogician/presentation/models/trace.py +0 -42
- speclogician-0.0.0b1/src/speclogician/presentation/preview/__init__.py +0 -13
- speclogician-0.0.0b1/src/speclogician/presentation/preview/cli.py +0 -50
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/__init__.py +0 -205
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/artifact_container.py +0 -150
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/data_artifact.py +0 -144
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/domain_model.py +0 -162
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/instances_list.py +0 -162
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/predicate.py +0 -184
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/scenario.py +0 -84
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/scenario_complement.py +0 -81
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/smart_find.py +0 -140
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/spec.py +0 -95
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/state_diff.py +0 -158
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/state_instance.py +0 -128
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/state_instance_summary.py +0 -80
- speclogician-0.0.0b1/src/speclogician/presentation/preview/fixtures/trace.py +0 -206
- speclogician-0.0.0b1/src/speclogician/presentation/preview/registry.py +0 -42
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/__init__.py +0 -24
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/container.py +0 -136
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/data_artifact.py +0 -144
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/domain.py +0 -123
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/instances_list.py +0 -120
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/predicate.py +0 -180
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/recommendations.py +0 -90
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/scenario.py +0 -94
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/scenario_complement.py +0 -59
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/smart_find.py +0 -307
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/spec.py +0 -105
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/state_diff.py +0 -102
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/state_instance.py +0 -82
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/state_instance_summary.py +0 -143
- speclogician-0.0.0b1/src/speclogician/presentation/renderers/trace.py +0 -122
- speclogician-0.0.0b1/src/speclogician/shell/app.py +0 -170
- speclogician-0.0.0b1/src/speclogician/shell/shell_ch.py +0 -263
- speclogician-0.0.0b1/src/speclogician/shell/shell_view.py +0 -153
- speclogician-0.0.0b1/src/speclogician/state/change.py +0 -428
- speclogician-0.0.0b1/src/speclogician/state/change_result.py +0 -32
- speclogician-0.0.0b1/src/speclogician/state/diff.py +0 -191
- speclogician-0.0.0b1/src/speclogician/state/inst.py +0 -574
- speclogician-0.0.0b1/src/speclogician/state/recommendation.py +0 -13
- speclogician-0.0.0b1/src/speclogician/state/recommender.py +0 -577
- speclogician-0.0.0b1/src/speclogician/state/state.py +0 -465
- speclogician-0.0.0b1/src/speclogician/state/state_stats.py +0 -133
- speclogician-0.0.0b1/src/speclogician/tui/app.py +0 -257
- speclogician-0.0.0b1/src/speclogician/tui/app.tcss +0 -160
- speclogician-0.0.0b1/src/speclogician/tui/demo.py +0 -45
- speclogician-0.0.0b1/src/speclogician/tui/images/speclogician-full.png +0 -0
- speclogician-0.0.0b1/src/speclogician/tui/images/speclogician-minimal.png +0 -0
- speclogician-0.0.0b1/src/speclogician/tui/main_screen.py +0 -454
- speclogician-0.0.0b1/src/speclogician/tui/splash_screen.py +0 -51
- speclogician-0.0.0b1/src/speclogician/tui/stats_screen.py +0 -125
- speclogician-0.0.0b1/src/speclogician/utils/__init__.py +0 -78
- speclogician-0.0.0b1/src/speclogician/utils/load.py +0 -166
- speclogician-0.0.0b1/src/speclogician/utils/prompt.md +0 -325
- speclogician-0.0.0b1/src/speclogician/utils/testing.py +0 -151
- {speclogician-0.0.0b1 → speclogician-0.0.0.dev1}/src/speclogician/__init__.py +0 -0
- {speclogician-0.0.0b1/src/speclogician/data → speclogician-0.0.0.dev1/src/speclogician/agent}/__init__.py +0 -0
- {speclogician-0.0.0b1/src/speclogician/presentation → speclogician-0.0.0.dev1/src/speclogician/cmd}/__init__.py +0 -0
- {speclogician-0.0.0b1/src/speclogician/presentation/builders → speclogician-0.0.0.dev1/src/speclogician/data}/__init__.py +0 -0
- {speclogician-0.0.0b1/src/speclogician/presentation/models → speclogician-0.0.0.dev1/src/speclogician/llms}/__init__.py +0 -0
- {speclogician-0.0.0b1/src/speclogician/state → speclogician-0.0.0.dev1/src/speclogician/modeling}/__init__.py +0 -0
- {speclogician-0.0.0b1 → speclogician-0.0.0.dev1}/src/speclogician/py.typed +0 -0
- {speclogician-0.0.0b1/src/speclogician/tui → speclogician-0.0.0.dev1/src/speclogician/state}/__init__.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: speclogician
|
|
3
|
+
Version: 0.0.0.dev1
|
|
4
|
+
Summary: SpecLogicain AI framework for data-driven formal program specification synthesis, verification and analysis
|
|
5
|
+
Author: denis, hongyu
|
|
6
|
+
Author-email: denis <denis@imandra.ai>, hongyu <hongyu@imandra.ai>
|
|
7
|
+
Requires-Dist: imandrax-api-models>=18.0.0
|
|
8
|
+
Requires-Dist: iml-query>=0.5.1
|
|
9
|
+
Requires-Dist: pydantic>=2.12.5
|
|
10
|
+
Requires-Dist: rich>=14.2.0
|
|
11
|
+
Requires-Dist: textual>=6.11.0
|
|
12
|
+
Requires-Dist: typer>=0.20.0
|
|
13
|
+
Requires-Python: >=3.12
|
|
14
|
+
Project-URL: Homepage, https://speclogician.dev/
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# SpecLogician
|
|
18
|
+
SpecLogicain AI framework for data-driven formal program specification synthesis, verification and analysis
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
www.speclogician.dev
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "speclogician"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.0.dev1"
|
|
4
4
|
description = "SpecLogicain AI framework for data-driven formal program specification synthesis, verification and analysis"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -21,12 +21,5 @@ dependencies = [
|
|
|
21
21
|
requires = ["uv_build>=0.8.22,<0.9.0"]
|
|
22
22
|
build-backend = "uv_build"
|
|
23
23
|
|
|
24
|
-
[dependency-groups]
|
|
25
|
-
dev = [
|
|
26
|
-
"dotenv>=0.9.9",
|
|
27
|
-
"pytest>=9.0.2",
|
|
28
|
-
"pytest-asyncio>=1.3.0",
|
|
29
|
-
]
|
|
30
|
-
|
|
31
24
|
[project.urls]
|
|
32
25
|
Homepage = "https://speclogician.dev/"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# agent.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from ..state.state import State
|
|
12
|
+
from ..llms.llmtools import test_formalizer
|
|
13
|
+
from ..llms.overlay import Overlay
|
|
14
|
+
|
|
15
|
+
def process_test_file (
|
|
16
|
+
path : Path,
|
|
17
|
+
state : State,
|
|
18
|
+
overlay : Overlay
|
|
19
|
+
) -> State:
|
|
20
|
+
"""
|
|
21
|
+
Process a file state to the state
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
tf = test_formalizer (str(path), overlay, state)
|
|
26
|
+
except Exception as e:
|
|
27
|
+
raise Exception (f"Failed to process test file: []")
|
|
28
|
+
|
|
29
|
+
return state.add_test_formalization(tf)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# agent_cmd.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Annotated
|
|
11
|
+
|
|
12
|
+
from rich.progress import track
|
|
13
|
+
|
|
14
|
+
from ..llms.overlay import Overlays
|
|
15
|
+
from ..agent.funcs import process_test_file
|
|
16
|
+
from ..state.state import State
|
|
17
|
+
from ..utils import console
|
|
18
|
+
from ..utils.load import load_overlays, load_state
|
|
19
|
+
|
|
20
|
+
app = typer.Typer()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.command(help="Add a single file to the formalization state")
|
|
24
|
+
def proc_test_file (
|
|
25
|
+
filepath : Annotated[str, typer.Argument()],
|
|
26
|
+
overlay_name : Annotated[str, typer.Argument(help="Overlay to use. It should also contain the file extension we'll use")]
|
|
27
|
+
):
|
|
28
|
+
|
|
29
|
+
overlays = load_overlays()
|
|
30
|
+
state = load_state()
|
|
31
|
+
|
|
32
|
+
tgt_path = Path(filepath).parent / filepath
|
|
33
|
+
|
|
34
|
+
overlay = overlays.get(overlay_name)
|
|
35
|
+
if overlay is None:
|
|
36
|
+
console.print(f":warning: Could not find an overlay named {overlay_name}!")
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
process_test_file(tgt_path, state, overlay)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
console.print(f"🛑 Caught an error when adding file: {e}")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
# Add the state definition here
|
|
46
|
+
|
|
47
|
+
typer.secho(f"✅ Successfully added {filepath} to the formalization state!")
|
|
48
|
+
|
|
49
|
+
@app.command(help="Run full cycle formalization for a specified directory")
|
|
50
|
+
def proc_test_dir (
|
|
51
|
+
dirpath : Annotated[str, typer.Argument(help="Target directory with tests that should be formalized")],
|
|
52
|
+
overlay_name : Annotated[str, typer.Argument(help="Overlay to use. It should also contain the file extension we'll use")],
|
|
53
|
+
clean : Annotated[bool, typer.Option(help="Should we override any tests from these files already present in the state?")] = False
|
|
54
|
+
):
|
|
55
|
+
|
|
56
|
+
state = load_state()
|
|
57
|
+
|
|
58
|
+
overlays = load_overlays()
|
|
59
|
+
overlay = overlays.get(overlay_name)
|
|
60
|
+
|
|
61
|
+
if overlay is None:
|
|
62
|
+
typer.secho(f"🛑 Could not find an overlay named {overlay_name}!", err=True)
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
filepaths = os.listdir(dirpath)
|
|
66
|
+
filepaths = list(filter(lambda x: x.endswith(overlay.ext.strip()), filepaths))
|
|
67
|
+
|
|
68
|
+
console.print(f"Identified {len(filepaths)} to process")
|
|
69
|
+
|
|
70
|
+
count = 0
|
|
71
|
+
|
|
72
|
+
for i in track(range(len(filepaths)), description=f"Processing {dirpath}..."):
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
process_test_file(Path(filepaths[i]), state, overlay)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
console.print(f"Failed on {filepaths[i]}: {e}")
|
|
78
|
+
|
|
79
|
+
count += 1
|
|
80
|
+
|
|
81
|
+
console.print(f":robot:Processed {count} files!")
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
state.save(dirpath)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
typer.echo(f"🛑 Caught error when saving the formalization state: {e}")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
typer.secho(f"✅ Successfully saved the formalization state to {dirpath}")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# data_cmd.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
|
|
10
|
+
app = typer.Typer()
|
|
11
|
+
|
|
12
|
+
@app.command(name="list")
|
|
13
|
+
def data_list():
|
|
14
|
+
"""
|
|
15
|
+
List the available data sources
|
|
16
|
+
"""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
tests_app = typer.Typer()
|
|
20
|
+
@tests_app.command(name="tests")
|
|
21
|
+
def list (
|
|
22
|
+
max_num_tests : Annotated[int, typer.Argument(help="Maximum number of tests to displayed")]
|
|
23
|
+
):
|
|
24
|
+
pass
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# model_cmd.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
from rich.syntax import Syntax
|
|
10
|
+
|
|
11
|
+
from ..utils import console
|
|
12
|
+
from ..utils.load import load_state
|
|
13
|
+
|
|
14
|
+
app = typer.Typer()
|
|
15
|
+
|
|
16
|
+
@app.command(name="summary", help="")
|
|
17
|
+
def summary():
|
|
18
|
+
"""
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
state = load_state()
|
|
22
|
+
|
|
23
|
+
console.print(state.curr_state().model.report())
|
|
24
|
+
|
|
25
|
+
@app.command(name="code", help="Generate the IML code for the Domain Model")
|
|
26
|
+
def get_code(
|
|
27
|
+
filepath : Annotated[str|None, typer.Option(help="Output filepath")] = None
|
|
28
|
+
):
|
|
29
|
+
|
|
30
|
+
state = load_state()
|
|
31
|
+
|
|
32
|
+
console.print(Syntax(state.curr_state().model.domain_model.to_iml(), "OCaml"))
|
|
33
|
+
|
|
34
|
+
if filepath is not None:
|
|
35
|
+
try:
|
|
36
|
+
with open(filepath, 'w') as outfile:
|
|
37
|
+
print(state.curr_state().model.domain_model.to_iml(), file=outfile)
|
|
38
|
+
except Exception as e:
|
|
39
|
+
console.print(f"🛑 Failed to write domain model to disk: {e}",)
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
console.print(f"✅ Successfully wrote domain model to disk: {filepath}")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# overlay_cmd.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
from rich import print as printr
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ..utils.load import load_overlays
|
|
12
|
+
|
|
13
|
+
app = typer.Typer()
|
|
14
|
+
|
|
15
|
+
@app.command(name="list", help="list the available overlays")
|
|
16
|
+
def list_():
|
|
17
|
+
overlays = load_overlays()
|
|
18
|
+
overlays.list_overlays()
|
|
19
|
+
|
|
20
|
+
@app.command(name="view", help="View individual template")
|
|
21
|
+
def view(
|
|
22
|
+
name : Annotated[str, typer.Argument(help="Name of the template to view")]
|
|
23
|
+
):
|
|
24
|
+
|
|
25
|
+
overlays = load_overlays()
|
|
26
|
+
if name not in overlays.names():
|
|
27
|
+
typer.secho(f"🛑 No template with name {name} found!", err=True)
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
printr(overlays.get(name))
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# scenario_cmd.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from ..state.state import State
|
|
10
|
+
from ..utils.load import load_state
|
|
11
|
+
|
|
12
|
+
from typing import Annotated
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
app = typer.Typer()
|
|
16
|
+
|
|
17
|
+
@app.command(name="summary", help="Summary of the available scenarios")
|
|
18
|
+
def summary():
|
|
19
|
+
"""
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
state = load_state()
|
|
23
|
+
|
|
24
|
+
@app.command(name="view", help="View a specific scenario")
|
|
25
|
+
def view(
|
|
26
|
+
sc_id : int,
|
|
27
|
+
scenario_name : str
|
|
28
|
+
):
|
|
29
|
+
"""
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
state = load_state()
|
|
33
|
+
|
|
34
|
+
@app.command(name="rm", help="Remove a scenario")
|
|
35
|
+
def rm_scenario():
|
|
36
|
+
"""
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
state = load_state()
|
|
40
|
+
|
|
41
|
+
@app.command(name="add", help="Add a scenario")
|
|
42
|
+
def add_scenario(
|
|
43
|
+
name : Annotated[str, typer.Argument(help="Name to be given to the scenario, must be unique")]
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
"""
|
|
47
|
+
state = load_state()
|
|
48
|
+
|
|
49
|
+
@app.command(name="edit", help="Edit a scenario")
|
|
50
|
+
def edit_scenario():
|
|
51
|
+
"""
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
state = load_state()
|
|
55
|
+
|
|
56
|
+
@app.command(name="search", help="Search for a particular scenario by predicate/transition functions")
|
|
57
|
+
def search(q : str):
|
|
58
|
+
"""
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
state = load_state()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# state_cmd.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Annotated
|
|
10
|
+
|
|
11
|
+
from ..state.state import State
|
|
12
|
+
from ..utils import console
|
|
13
|
+
from ..utils.load import load_state
|
|
14
|
+
|
|
15
|
+
global state
|
|
16
|
+
state : State
|
|
17
|
+
|
|
18
|
+
app = typer.Typer()
|
|
19
|
+
|
|
20
|
+
@app.command(name="list", help="List all state instances")
|
|
21
|
+
def list_states (
|
|
22
|
+
max_num_states : Annotated[int, typer.Argument(help="Maximum number of states")]=10
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
List the state instances
|
|
26
|
+
"""
|
|
27
|
+
state = load_state()
|
|
28
|
+
console.print(state.inst_list())
|
|
29
|
+
|
|
30
|
+
@app.command(name="set", help="Set current state to a specific idx in the list")
|
|
31
|
+
def set (
|
|
32
|
+
state_idx : Annotated[int, typer.Argument(help="")]
|
|
33
|
+
):
|
|
34
|
+
|
|
35
|
+
state = load_state()
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
state.set_curr_state_idx (state_idx)
|
|
39
|
+
except Exception as e:
|
|
40
|
+
console.print(f"Caught error: {e}")
|
|
41
|
+
sys.exit(0)
|
|
42
|
+
|
|
43
|
+
console.print("Update current state idx to {state_idx}")
|
|
44
|
+
|
|
45
|
+
@app.command(name="summary", help="Provide summary of the current state instance")
|
|
46
|
+
def summary():
|
|
47
|
+
"""
|
|
48
|
+
Provide a summary of the current state
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
state : State = load_state()
|
|
52
|
+
console.print(state.curr_state().report())
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# artifact.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import uuid
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
|
|
10
|
+
class Artifact(BaseModel):
|
|
11
|
+
"""
|
|
12
|
+
"""
|
|
13
|
+
art_id : str = Field(default_factory=lambda: str(uuid.uuid4())) # assigned task ID, new one created if not provided
|
|
14
|
+
|
|
15
|
+
class TraceArtifact(Artifact):
|
|
16
|
+
|
|
17
|
+
given : str
|
|
18
|
+
when : str
|
|
19
|
+
then : str
|
|
20
|
+
|
|
21
|
+
valid_iml : bool = False
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# container.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from .traces import TestTrace, LogTrace
|
|
10
|
+
from .refs import DocRef, SrcCodeRef
|
|
11
|
+
|
|
12
|
+
class ArtifactSummaryInfo(BaseModel):
|
|
13
|
+
""" """
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
class ArtifactContainer(BaseModel):
|
|
17
|
+
"""
|
|
18
|
+
Artifact container
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
test_traces : list[TestTrace] = []
|
|
22
|
+
log_traces : list[LogTrace] = []
|
|
23
|
+
doc_ref : list[DocRef] = []
|
|
24
|
+
src_code : list[SrcCodeRef] = []
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def info(self):
|
|
28
|
+
"""
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
return {'hello': 123}
|
|
32
|
+
|
|
33
|
+
def add(self):
|
|
34
|
+
""" """
|
|
35
|
+
pass
|
|
36
|
+
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Imandra Inc.
|
|
3
3
|
#
|
|
4
|
-
#
|
|
4
|
+
# mapping.py
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
-
from pydantic import BaseModel
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from typing import Dict
|
|
8
9
|
|
|
9
10
|
from enum import StrEnum
|
|
10
11
|
|
|
@@ -18,39 +19,39 @@ class ArtifactMap(BaseModel):
|
|
|
18
19
|
handle potentially large datasets (e.g. massive logs)
|
|
19
20
|
"""
|
|
20
21
|
|
|
21
|
-
art_to_comp_map:
|
|
22
|
-
comp_to_art_map:
|
|
22
|
+
art_to_comp_map : Dict[str, list[str]] = {}
|
|
23
|
+
comp_to_art_map : Dict[str, list[str]] = {}
|
|
23
24
|
|
|
24
|
-
def add_connection (self, art_id : str,
|
|
25
|
+
def add_connection (self, art_id : str, comp_id : str):
|
|
25
26
|
"""
|
|
26
27
|
Add a link between artifact and model component
|
|
27
28
|
"""
|
|
28
29
|
if art_id not in self.art_to_comp_map:
|
|
29
30
|
self.art_to_comp_map[art_id] = []
|
|
30
31
|
|
|
31
|
-
if
|
|
32
|
-
self.art_to_comp_map[art_id].append(
|
|
32
|
+
if comp_id not in self.art_to_comp_map[art_id]:
|
|
33
|
+
self.art_to_comp_map[art_id].append(comp_id)
|
|
33
34
|
|
|
34
|
-
if
|
|
35
|
-
self.comp_to_art_map[
|
|
35
|
+
if comp_id not in self.comp_to_art_map:
|
|
36
|
+
self.comp_to_art_map[comp_id] = []
|
|
36
37
|
|
|
37
|
-
if art_id not in self.comp_to_art_map[
|
|
38
|
-
self.comp_to_art_map[
|
|
38
|
+
if art_id not in self.comp_to_art_map[comp_id]:
|
|
39
|
+
self.comp_to_art_map[comp_id].append(art_id)
|
|
39
40
|
|
|
40
|
-
def rem_connection (self, artifact_id : str,
|
|
41
|
+
def rem_connection (self, artifact_id : str, comp_id : str):
|
|
41
42
|
"""
|
|
42
43
|
Remove a connection
|
|
43
44
|
"""
|
|
44
45
|
|
|
45
46
|
if artifact_id in self.art_to_comp_map:
|
|
46
|
-
if
|
|
47
|
-
self.art_to_comp_map[artifact_id].remove(
|
|
47
|
+
if comp_id in self.art_to_comp_map[artifact_id]:
|
|
48
|
+
self.art_to_comp_map[artifact_id].remove(comp_id)
|
|
48
49
|
else:
|
|
49
50
|
return False
|
|
50
51
|
|
|
51
|
-
if
|
|
52
|
-
if artifact_id in self.comp_to_art_map[
|
|
53
|
-
self.comp_to_art_map[
|
|
52
|
+
if comp_id in self.comp_to_art_map:
|
|
53
|
+
if artifact_id in self.comp_to_art_map[comp_id]:
|
|
54
|
+
self.comp_to_art_map[comp_id].remove(artifact_id)
|
|
54
55
|
|
|
55
56
|
def rem_element (self, elem_type : ElementType, str_id : str):
|
|
56
57
|
"""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# refs.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from .artifact import Artifact
|
|
8
|
+
|
|
9
|
+
class DocRef(Artifact):
|
|
10
|
+
"""
|
|
11
|
+
Documentation reference
|
|
12
|
+
"""
|
|
13
|
+
meta : str
|
|
14
|
+
text : str
|
|
15
|
+
|
|
16
|
+
class SrcCodeRef(Artifact):
|
|
17
|
+
"""
|
|
18
|
+
Source code reference
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
meta : str #
|
|
22
|
+
language : str #
|
|
23
|
+
file_path : str #
|
|
24
|
+
src_code : str #
|
|
25
|
+
iml_code : str #
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# trace.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from .artifact import TraceArtifact
|
|
8
|
+
|
|
9
|
+
class TestTrace (TraceArtifact):
|
|
10
|
+
"""
|
|
11
|
+
Test trace formalization
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
name : str # Test case name
|
|
15
|
+
filepath : str # Original test filepath
|
|
16
|
+
language : str # Language of the original source code
|
|
17
|
+
contents : str # Original test contents
|
|
18
|
+
time : str # Time when this done
|
|
19
|
+
|
|
20
|
+
# Contain
|
|
21
|
+
|
|
22
|
+
class LogTrace(TraceArtifact):
|
|
23
|
+
"""
|
|
24
|
+
Log tace formalization
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
filename : str #
|
|
28
|
+
contents : str # Contents of the log entry
|
|
29
|
+
|
|
30
|
+
# Formalized entry
|
|
31
|
+
given : str
|
|
32
|
+
when : str
|
|
33
|
+
then : str
|
|
34
|
+
|
|
35
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# llmtools.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
import datetime, os, dotenv, sys, yaml, typer
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from ..data.reports import TestFormalization
|
|
11
|
+
from llms.overlay import Overlay
|
|
12
|
+
|
|
13
|
+
#from langchain_anthropic import ChatAnthropic
|
|
14
|
+
dotenv.load_dotenv("../.env")
|
|
15
|
+
|
|
16
|
+
llm = None
|
|
17
|
+
|
|
18
|
+
#ChatAnthropic (
|
|
19
|
+
# model_name="claude-sonnet-4-20250514",
|
|
20
|
+
# api_key=os.environ["ANTHROPIC_API_KEY"],
|
|
21
|
+
#)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_formalizer (
|
|
25
|
+
filepath : str,
|
|
26
|
+
overlay : Overlay,
|
|
27
|
+
domain_model : Optional[str] = "N/A",
|
|
28
|
+
) -> TestFormalization:
|
|
29
|
+
"""
|
|
30
|
+
Returns a tuple of the logic and the type model
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
test_case = Path(filepath).read_text()
|
|
34
|
+
try:
|
|
35
|
+
generic_prompt = Path("../prompts/generic.md").read_text()
|
|
36
|
+
except Exception as e:
|
|
37
|
+
print(f"Failed to load in the generic prompt: {e}")
|
|
38
|
+
sys.exit(0)
|
|
39
|
+
|
|
40
|
+
prompt = f"""
|
|
41
|
+
{generic_prompt}
|
|
42
|
+
|
|
43
|
+
{overlay}
|
|
44
|
+
|
|
45
|
+
Domain model:
|
|
46
|
+
----
|
|
47
|
+
{domain_model}
|
|
48
|
+
----
|
|
49
|
+
|
|
50
|
+
Test case:
|
|
51
|
+
----
|
|
52
|
+
{test_case}
|
|
53
|
+
----
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
structured_model = llm.with_structured_output(FormalizationResponse)
|
|
57
|
+
|
|
58
|
+
# Let's call the LLM
|
|
59
|
+
try:
|
|
60
|
+
response : FormalizationResponse = structured_model.invoke(prompt)
|
|
61
|
+
except Exception as e:
|
|
62
|
+
typer.secho(f"Failed to make the LLM call: {e}", err=True)
|
|
63
|
+
sys.exit(0)
|
|
64
|
+
|
|
65
|
+
tf = TestFormalization(
|
|
66
|
+
name = response.test_name_str,
|
|
67
|
+
language = overlay.language,
|
|
68
|
+
filepath = filepath,
|
|
69
|
+
contents = test_case,
|
|
70
|
+
time = str(datetime.datetime.now()),
|
|
71
|
+
scenarios = response.scenarios,
|
|
72
|
+
domain_model = response.domain_model,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return tf
|
|
76
|
+
|
|
77
|
+
def retry_test_formalization (
|
|
78
|
+
tf : TestFormalization,
|
|
79
|
+
model_response : str,
|
|
80
|
+
) -> TestFormalization:
|
|
81
|
+
"""
|
|
82
|
+
Make the call again to
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
return tf
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
|
|
89
|
+
base_dir = "../data/gherkin"
|
|
90
|
+
paths = os.listdir(base_dir)
|
|
91
|
+
overlay = Overlay.from_file("../overlays/gherkin.yaml")
|
|
92
|
+
domain_model : str = "N/A"
|
|
93
|
+
|
|
94
|
+
responses : list[LLMResponse] = []
|
|
95
|
+
|
|
96
|
+
for path in paths:
|
|
97
|
+
r = test_formalizer(os.path.join(base_dir, paths[0]), overlay, domain_model)
|
|
98
|
+
responses.append(r)
|
|
99
|
+
domain_model = r.domain_model
|
|
100
|
+
|
|
101
|
+
for r in responses:
|
|
102
|
+
print (yaml.dump(r, default_flow_style=False))
|