omagent 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.
- omagent-0.1.0/LICENSE +29 -0
- omagent-0.1.0/PKG-INFO +213 -0
- omagent-0.1.0/README.md +177 -0
- omagent-0.1.0/omagent/__init__.py +21 -0
- omagent-0.1.0/omagent/errors.py +259 -0
- omagent-0.1.0/omagent/llm.py +96 -0
- omagent-0.1.0/omagent/loop.py +188 -0
- omagent-0.1.0/omagent/results.py +266 -0
- omagent-0.1.0/omagent/runner.py +100 -0
- omagent-0.1.0/omagent/session.py +147 -0
- omagent-0.1.0/omagent/tasks.py +148 -0
- omagent-0.1.0/omagent.egg-info/PKG-INFO +213 -0
- omagent-0.1.0/omagent.egg-info/SOURCES.txt +22 -0
- omagent-0.1.0/omagent.egg-info/dependency_links.txt +1 -0
- omagent-0.1.0/omagent.egg-info/requires.txt +18 -0
- omagent-0.1.0/omagent.egg-info/top_level.txt +1 -0
- omagent-0.1.0/pyproject.toml +44 -0
- omagent-0.1.0/setup.cfg +4 -0
- omagent-0.1.0/tests/test_errors.py +172 -0
- omagent-0.1.0/tests/test_llm.py +82 -0
- omagent-0.1.0/tests/test_loop.py +247 -0
- omagent-0.1.0/tests/test_results.py +277 -0
- omagent-0.1.0/tests/test_session.py +194 -0
- omagent-0.1.0/tests/test_tasks.py +159 -0
omagent-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Masoud Masoumi
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
omagent-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: omagent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LLM-assisted OpenModelica modeling: a tested agentic generate-compile-simulate-verify loop with structured omc diagnostics, quantitative trajectory verification, and a benchmark task ladder.
|
|
5
|
+
Author: Masoud Masoumi
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/MasoudMiM/omeganet
|
|
8
|
+
Project-URL: Issues, https://github.com/MasoudMiM/omeganet/issues
|
|
9
|
+
Keywords: modelica,openmodelica,llm,simulation,agent,modeling
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: omc
|
|
23
|
+
Requires-Dist: OMPython>=3.6; extra == "omc"
|
|
24
|
+
Provides-Extra: results
|
|
25
|
+
Requires-Dist: scipy>=1.10; extra == "results"
|
|
26
|
+
Provides-Extra: llm
|
|
27
|
+
Requires-Dist: anthropic>=0.40; extra == "llm"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: OMPython>=3.6; extra == "all"
|
|
32
|
+
Requires-Dist: scipy>=1.10; extra == "all"
|
|
33
|
+
Requires-Dist: anthropic>=0.40; extra == "all"
|
|
34
|
+
Requires-Dist: pytest>=8; extra == "all"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# omagent
|
|
38
|
+
|
|
39
|
+
**LLM-assisted modeling for OpenModelica** — an open-source, headless Python
|
|
40
|
+
agent that turns a natural-language task into a *verified* Modelica model:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
natural language ──> generate ──> compile (omc) ──> simulate ──> verify physics
|
|
44
|
+
▲ │
|
|
45
|
+
└──── structured error / verifier feedback ──┘
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Unlike a plain code assistant, omagent closes the loop on **physics, not just
|
|
49
|
+
compilation**: quantitative verifiers check trajectories against expected
|
|
50
|
+
behavior (final values, settling windows, bounds, overshoot), and every
|
|
51
|
+
failure — compiler diagnostics or physics complaints — is parsed into
|
|
52
|
+
structured feedback for the next fix attempt.
|
|
53
|
+
|
|
54
|
+
Key capabilities:
|
|
55
|
+
|
|
56
|
+
- **Structured omc diagnostics** — parses `getErrorString()`, simulation
|
|
57
|
+
logs, and OMPython's exception format into records with severity, source
|
|
58
|
+
location, and failure kind (syntax / lookup / type / balance / connect /
|
|
59
|
+
initialization / runtime)
|
|
60
|
+
- **Environment-grounded fix hints** — on `Class X not found`, omagent asks
|
|
61
|
+
omc what the parent package *actually* contains (`getClassNames`) and puts
|
|
62
|
+
near-miss suggestions into the fix prompt. This resolves the dominant
|
|
63
|
+
observed failure mode: stale library knowledge (e.g. MSL 3.2 names such as
|
|
64
|
+
`Basic.EMF` vs. MSL 4.x `Basic.RotationalEMF`)
|
|
65
|
+
- **Quantitative verification** — reads CSV or Dymola-format `.mat` results;
|
|
66
|
+
verifier complaints ("final value of x is 1.93, expected 2.0") drive tuning
|
|
67
|
+
- **Benchmark task ladder** — 5 escalating, auto-gradable tasks with full
|
|
68
|
+
transcript capture, in the format the OpenModelica benchmark discussion
|
|
69
|
+
([OpenModelica#15385](https://github.com/OpenModelica/OpenModelica/issues/15385))
|
|
70
|
+
calls for
|
|
71
|
+
- **LLM-backend-agnostic** — the loop depends on a one-method protocol; an
|
|
72
|
+
Anthropic adapter ships, any provider or local model plugs in
|
|
73
|
+
- **Tested** — 83 unit tests run without OpenModelica installed; 4
|
|
74
|
+
integration tests validate against a live omc
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
Requires Python >= 3.10. The core package has zero hard dependencies;
|
|
79
|
+
features are opt-in extras:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install -e . # parsers + loop only (no omc needed)
|
|
83
|
+
pip install -e ".[omc]" # + OMPython (talk to a real omc)
|
|
84
|
+
pip install -e ".[results]" # + scipy (.mat result files; CSV needs nothing)
|
|
85
|
+
pip install -e ".[llm]" # + anthropic adapter
|
|
86
|
+
pip install -e ".[all]" # everything, including pytest
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
To use it against a real compiler you need
|
|
90
|
+
[OpenModelica](https://openmodelica.org) (tested with 1.26–1.27) with the
|
|
91
|
+
Modelica Standard Library installed for `omc`:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
echo 'installPackage(Modelica); getErrorString();' > /tmp/i.mos && omc /tmp/i.mos
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> Note: OMEdit installs the MSL for itself automatically; headless `omc`
|
|
98
|
+
> sessions do not. If models using `Modelica.*` fail with "Class ... not
|
|
99
|
+
> found", this is why.
|
|
100
|
+
|
|
101
|
+
Verify your setup:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pytest -m "not integration" # unit tests, no omc required
|
|
105
|
+
pytest -m integration # against your live omc (+MSL, scipy for .mat)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Quick start
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from omagent import AgentLoop, OMSession, all_of, expect_bounds, expect_final
|
|
112
|
+
from omagent.llm import ClaudeLLM # or any object with .propose(...)
|
|
113
|
+
|
|
114
|
+
# physics acceptance criteria — complaints feed back into the fix loop
|
|
115
|
+
verifier = all_of(
|
|
116
|
+
expect_bounds("x", lo=-0.105, hi=0.105),
|
|
117
|
+
expect_final("x", 0.0, atol=0.06, rtol=0.0),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
loop = AgentLoop(
|
|
121
|
+
OMSession(), # real omc via OMPython
|
|
122
|
+
ClaudeLLM(), # needs ANTHROPIC_API_KEY
|
|
123
|
+
max_attempts=4,
|
|
124
|
+
simulate_options={"stopTime": 10.0, "outputFormat": "csv"},
|
|
125
|
+
verifier=verifier,
|
|
126
|
+
)
|
|
127
|
+
result = loop.run(
|
|
128
|
+
"A mass-spring-damper: m = 1 kg, c = 100 N/m, d = 1 N.s/m, released "
|
|
129
|
+
"from x = 0.1 m at rest. Name position x and velocity v.")
|
|
130
|
+
|
|
131
|
+
print(result.success, result.model_name)
|
|
132
|
+
print(result.final_code)
|
|
133
|
+
for a in result.attempts:
|
|
134
|
+
print(a.n, a.stage, a.complaint)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Bring your own LLM by implementing one method:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
class MyLLM:
|
|
141
|
+
def propose(self, task, previous_code, error_summary):
|
|
142
|
+
# previous_code/error_summary are None on the first (fresh) call;
|
|
143
|
+
# on retries they contain the failed model and structured feedback.
|
|
144
|
+
return "... complete Modelica model ..."
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Run the benchmark ladder
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
export ANTHROPIC_API_KEY=...
|
|
151
|
+
python examples/run_ladder.py # all 5 tiers
|
|
152
|
+
python examples/run_ladder.py --max-tier 3 # subset by difficulty
|
|
153
|
+
python examples/run_ladder.py --tasks dc_motor --model claude-opus-4-8
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Tiers: (1) pure-equation dynamics, (2) MSL component composition, (3) hybrid
|
|
157
|
+
events, (4) verifier-driven design — the requirement is given, the parameter
|
|
158
|
+
is not, (5) multi-domain electro-mechanical. Per-task JSON transcripts
|
|
159
|
+
(attempt history, diagnostics, code, LLM rounds) land in `transcripts/`,
|
|
160
|
+
with `summary.json` aggregating results.
|
|
161
|
+
|
|
162
|
+
### Use pieces standalone
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from omagent import OMSession, parse_error_string, summarize_for_llm, load_result
|
|
166
|
+
|
|
167
|
+
s = OMSession()
|
|
168
|
+
r = s.load_string(my_modelica_code) # honest success verdict + diagnostics
|
|
169
|
+
print(summarize_for_llm(r.diagnostics)) # deduplicated digest for any prompt
|
|
170
|
+
|
|
171
|
+
sim = s.simulate("MyModel", stopTime=5.0, outputFormat="csv")
|
|
172
|
+
res = load_result(sim.value["resultFile"])
|
|
173
|
+
times, x = res.series("x")
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Project layout
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
omagent/
|
|
180
|
+
errors.py # omc diagnostic parsing + classification
|
|
181
|
+
session.py # OMSession: testable wrapper over OMPython/omc
|
|
182
|
+
loop.py # AgentLoop + lookup-suggestion feedback
|
|
183
|
+
results.py # CSV/.mat readers + quantitative verifiers
|
|
184
|
+
llm.py # Anthropic adapter (protocol: bring your own)
|
|
185
|
+
tasks.py # benchmark task ladder definitions
|
|
186
|
+
runner.py # ladder execution + transcript persistence
|
|
187
|
+
examples/ # first_run.py, run_ladder.py
|
|
188
|
+
tests/ # 83 unit + 4 integration tests
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Design notes
|
|
192
|
+
|
|
193
|
+
- **Testable by construction.** `OMSession` talks to any object with
|
|
194
|
+
`sendExpression()`; tests replay recorded omc output, so the full agent
|
|
195
|
+
loop is unit-tested without a compiler or an API key.
|
|
196
|
+
- **Both OMPython contracts.** Older OMPython returns and lets you read
|
|
197
|
+
`getErrorString()`; newer OMPython raises `OMCSessionException` on
|
|
198
|
+
error-level messages. Both yield identical structured failures.
|
|
199
|
+
- **Environment failures are not model failures.** The ladder runner loads
|
|
200
|
+
the MSL when a task requires it and reports load problems as
|
|
201
|
+
`environment` outcomes with zero attempts charged to the LLM.
|
|
202
|
+
|
|
203
|
+
## Roadmap
|
|
204
|
+
|
|
205
|
+
- Warning-level quality gates (e.g. treat "initial conditions over
|
|
206
|
+
specified" as a verifier complaint)
|
|
207
|
+
- Multi-run variance measurement and cross-model comparison in the runner
|
|
208
|
+
- Optional MCP tool surface, composing with OMEdit's built-in MCP server
|
|
209
|
+
- More ladder tiers targeting thermal/fluid domains and third-party libraries
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
BSD-3-Clause — see [LICENSE](LICENSE).
|
omagent-0.1.0/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# omagent
|
|
2
|
+
|
|
3
|
+
**LLM-assisted modeling for OpenModelica** — an open-source, headless Python
|
|
4
|
+
agent that turns a natural-language task into a *verified* Modelica model:
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
natural language ──> generate ──> compile (omc) ──> simulate ──> verify physics
|
|
8
|
+
▲ │
|
|
9
|
+
└──── structured error / verifier feedback ──┘
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Unlike a plain code assistant, omagent closes the loop on **physics, not just
|
|
13
|
+
compilation**: quantitative verifiers check trajectories against expected
|
|
14
|
+
behavior (final values, settling windows, bounds, overshoot), and every
|
|
15
|
+
failure — compiler diagnostics or physics complaints — is parsed into
|
|
16
|
+
structured feedback for the next fix attempt.
|
|
17
|
+
|
|
18
|
+
Key capabilities:
|
|
19
|
+
|
|
20
|
+
- **Structured omc diagnostics** — parses `getErrorString()`, simulation
|
|
21
|
+
logs, and OMPython's exception format into records with severity, source
|
|
22
|
+
location, and failure kind (syntax / lookup / type / balance / connect /
|
|
23
|
+
initialization / runtime)
|
|
24
|
+
- **Environment-grounded fix hints** — on `Class X not found`, omagent asks
|
|
25
|
+
omc what the parent package *actually* contains (`getClassNames`) and puts
|
|
26
|
+
near-miss suggestions into the fix prompt. This resolves the dominant
|
|
27
|
+
observed failure mode: stale library knowledge (e.g. MSL 3.2 names such as
|
|
28
|
+
`Basic.EMF` vs. MSL 4.x `Basic.RotationalEMF`)
|
|
29
|
+
- **Quantitative verification** — reads CSV or Dymola-format `.mat` results;
|
|
30
|
+
verifier complaints ("final value of x is 1.93, expected 2.0") drive tuning
|
|
31
|
+
- **Benchmark task ladder** — 5 escalating, auto-gradable tasks with full
|
|
32
|
+
transcript capture, in the format the OpenModelica benchmark discussion
|
|
33
|
+
([OpenModelica#15385](https://github.com/OpenModelica/OpenModelica/issues/15385))
|
|
34
|
+
calls for
|
|
35
|
+
- **LLM-backend-agnostic** — the loop depends on a one-method protocol; an
|
|
36
|
+
Anthropic adapter ships, any provider or local model plugs in
|
|
37
|
+
- **Tested** — 83 unit tests run without OpenModelica installed; 4
|
|
38
|
+
integration tests validate against a live omc
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
Requires Python >= 3.10. The core package has zero hard dependencies;
|
|
43
|
+
features are opt-in extras:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install -e . # parsers + loop only (no omc needed)
|
|
47
|
+
pip install -e ".[omc]" # + OMPython (talk to a real omc)
|
|
48
|
+
pip install -e ".[results]" # + scipy (.mat result files; CSV needs nothing)
|
|
49
|
+
pip install -e ".[llm]" # + anthropic adapter
|
|
50
|
+
pip install -e ".[all]" # everything, including pytest
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
To use it against a real compiler you need
|
|
54
|
+
[OpenModelica](https://openmodelica.org) (tested with 1.26–1.27) with the
|
|
55
|
+
Modelica Standard Library installed for `omc`:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
echo 'installPackage(Modelica); getErrorString();' > /tmp/i.mos && omc /tmp/i.mos
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> Note: OMEdit installs the MSL for itself automatically; headless `omc`
|
|
62
|
+
> sessions do not. If models using `Modelica.*` fail with "Class ... not
|
|
63
|
+
> found", this is why.
|
|
64
|
+
|
|
65
|
+
Verify your setup:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pytest -m "not integration" # unit tests, no omc required
|
|
69
|
+
pytest -m integration # against your live omc (+MSL, scipy for .mat)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from omagent import AgentLoop, OMSession, all_of, expect_bounds, expect_final
|
|
76
|
+
from omagent.llm import ClaudeLLM # or any object with .propose(...)
|
|
77
|
+
|
|
78
|
+
# physics acceptance criteria — complaints feed back into the fix loop
|
|
79
|
+
verifier = all_of(
|
|
80
|
+
expect_bounds("x", lo=-0.105, hi=0.105),
|
|
81
|
+
expect_final("x", 0.0, atol=0.06, rtol=0.0),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
loop = AgentLoop(
|
|
85
|
+
OMSession(), # real omc via OMPython
|
|
86
|
+
ClaudeLLM(), # needs ANTHROPIC_API_KEY
|
|
87
|
+
max_attempts=4,
|
|
88
|
+
simulate_options={"stopTime": 10.0, "outputFormat": "csv"},
|
|
89
|
+
verifier=verifier,
|
|
90
|
+
)
|
|
91
|
+
result = loop.run(
|
|
92
|
+
"A mass-spring-damper: m = 1 kg, c = 100 N/m, d = 1 N.s/m, released "
|
|
93
|
+
"from x = 0.1 m at rest. Name position x and velocity v.")
|
|
94
|
+
|
|
95
|
+
print(result.success, result.model_name)
|
|
96
|
+
print(result.final_code)
|
|
97
|
+
for a in result.attempts:
|
|
98
|
+
print(a.n, a.stage, a.complaint)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Bring your own LLM by implementing one method:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
class MyLLM:
|
|
105
|
+
def propose(self, task, previous_code, error_summary):
|
|
106
|
+
# previous_code/error_summary are None on the first (fresh) call;
|
|
107
|
+
# on retries they contain the failed model and structured feedback.
|
|
108
|
+
return "... complete Modelica model ..."
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Run the benchmark ladder
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
export ANTHROPIC_API_KEY=...
|
|
115
|
+
python examples/run_ladder.py # all 5 tiers
|
|
116
|
+
python examples/run_ladder.py --max-tier 3 # subset by difficulty
|
|
117
|
+
python examples/run_ladder.py --tasks dc_motor --model claude-opus-4-8
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Tiers: (1) pure-equation dynamics, (2) MSL component composition, (3) hybrid
|
|
121
|
+
events, (4) verifier-driven design — the requirement is given, the parameter
|
|
122
|
+
is not, (5) multi-domain electro-mechanical. Per-task JSON transcripts
|
|
123
|
+
(attempt history, diagnostics, code, LLM rounds) land in `transcripts/`,
|
|
124
|
+
with `summary.json` aggregating results.
|
|
125
|
+
|
|
126
|
+
### Use pieces standalone
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from omagent import OMSession, parse_error_string, summarize_for_llm, load_result
|
|
130
|
+
|
|
131
|
+
s = OMSession()
|
|
132
|
+
r = s.load_string(my_modelica_code) # honest success verdict + diagnostics
|
|
133
|
+
print(summarize_for_llm(r.diagnostics)) # deduplicated digest for any prompt
|
|
134
|
+
|
|
135
|
+
sim = s.simulate("MyModel", stopTime=5.0, outputFormat="csv")
|
|
136
|
+
res = load_result(sim.value["resultFile"])
|
|
137
|
+
times, x = res.series("x")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Project layout
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
omagent/
|
|
144
|
+
errors.py # omc diagnostic parsing + classification
|
|
145
|
+
session.py # OMSession: testable wrapper over OMPython/omc
|
|
146
|
+
loop.py # AgentLoop + lookup-suggestion feedback
|
|
147
|
+
results.py # CSV/.mat readers + quantitative verifiers
|
|
148
|
+
llm.py # Anthropic adapter (protocol: bring your own)
|
|
149
|
+
tasks.py # benchmark task ladder definitions
|
|
150
|
+
runner.py # ladder execution + transcript persistence
|
|
151
|
+
examples/ # first_run.py, run_ladder.py
|
|
152
|
+
tests/ # 83 unit + 4 integration tests
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Design notes
|
|
156
|
+
|
|
157
|
+
- **Testable by construction.** `OMSession` talks to any object with
|
|
158
|
+
`sendExpression()`; tests replay recorded omc output, so the full agent
|
|
159
|
+
loop is unit-tested without a compiler or an API key.
|
|
160
|
+
- **Both OMPython contracts.** Older OMPython returns and lets you read
|
|
161
|
+
`getErrorString()`; newer OMPython raises `OMCSessionException` on
|
|
162
|
+
error-level messages. Both yield identical structured failures.
|
|
163
|
+
- **Environment failures are not model failures.** The ladder runner loads
|
|
164
|
+
the MSL when a task requires it and reports load problems as
|
|
165
|
+
`environment` outcomes with zero attempts charged to the LLM.
|
|
166
|
+
|
|
167
|
+
## Roadmap
|
|
168
|
+
|
|
169
|
+
- Warning-level quality gates (e.g. treat "initial conditions over
|
|
170
|
+
specified" as a verifier complaint)
|
|
171
|
+
- Multi-run variance measurement and cross-model comparison in the runner
|
|
172
|
+
- Optional MCP tool surface, composing with OMEdit's built-in MCP server
|
|
173
|
+
- More ladder tiers targeting thermal/fluid domains and third-party libraries
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
BSD-3-Clause — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""omagent — testable tooling layer for LLM-assisted OpenModelica workflows."""
|
|
2
|
+
|
|
3
|
+
from .errors import (
|
|
4
|
+
Diagnostic, Kind, Severity,
|
|
5
|
+
classify, parse_error_string, parse_ompython_exception, parse_simulation_messages, summarize_for_llm,
|
|
6
|
+
)
|
|
7
|
+
from .session import Backend, OMSession, OpResult
|
|
8
|
+
from .loop import AgentLoop, Attempt, LLM, LoopResult, Verifier, extract_code, extract_model_name
|
|
9
|
+
from .results import (SimulationResult, all_of, expect_bounds, expect_final,
|
|
10
|
+
expect_value_at, load_result)
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
__all__ = [
|
|
14
|
+
"Diagnostic", "Kind", "Severity", "classify", "parse_error_string",
|
|
15
|
+
"parse_ompython_exception", "parse_simulation_messages", "summarize_for_llm",
|
|
16
|
+
"Backend", "OMSession", "OpResult",
|
|
17
|
+
"AgentLoop", "Attempt", "LLM", "LoopResult", "Verifier",
|
|
18
|
+
"extract_code", "extract_model_name",
|
|
19
|
+
"SimulationResult", "load_result", "expect_final", "expect_value_at",
|
|
20
|
+
"expect_bounds", "all_of",
|
|
21
|
+
]
|