sysmlv2copilot 0.2.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.
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - split the public package into a client-only SDK and CLI boundary
6
+ - added PyPI-ready metadata, MIT licensing, and release workflow docs
7
+ - added a repair workflow across the API, SDK, and CLI
8
+ - added packaging, CI, and smoke-test improvements
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chance LaVoie
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,17 @@
1
+ include LICENSE
2
+ include README.md
3
+ recursive-include sysmlv2copilot *.py
4
+ recursive-include examples *.py *.md *.txt
5
+ include CHANGELOG.md
6
+ prune app
7
+ prune alembic
8
+ prune context
9
+ prune docker
10
+ prune docs
11
+ prune infra
12
+ prune scripts
13
+ prune sysmlv2copilot_admin
14
+ prune tests
15
+ exclude alembic.ini
16
+ exclude Dockerfile
17
+ exclude prompt.txt
@@ -0,0 +1,432 @@
1
+ Metadata-Version: 2.4
2
+ Name: sysmlv2copilot
3
+ Version: 0.2.0
4
+ Summary: Python client SDK and CLI for the SysML refinement API
5
+ Author: Chance LaVoie
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/cmuchancel/sysmlv2copilot
8
+ Project-URL: Repository, https://github.com/cmuchancel/sysmlv2copilot
9
+ Project-URL: Issues, https://github.com/cmuchancel/sysmlv2copilot/issues
10
+ Project-URL: Documentation, https://github.com/cmuchancel/sysmlv2copilot/tree/main/docs
11
+ Keywords: sysml,sysmlv2,api-client,sdk,llm
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: httpx<1,>=0.28
22
+ Requires-Dist: pydantic<3,>=2.7
23
+ Provides-Extra: server
24
+ Requires-Dist: alembic<2,>=1.14; extra == "server"
25
+ Requires-Dist: anthropic<1,>=0.84; extra == "server"
26
+ Requires-Dist: fastapi<1,>=0.116; extra == "server"
27
+ Requires-Dist: openai<2,>=1.0; extra == "server"
28
+ Requires-Dist: psycopg[binary]<4,>=3.2; extra == "server"
29
+ Requires-Dist: pydantic-settings<3,>=2.7; extra == "server"
30
+ Requires-Dist: python-dotenv<2,>=1.0; extra == "server"
31
+ Requires-Dist: sqlalchemy<3,>=2.0; extra == "server"
32
+ Requires-Dist: uvicorn<1,>=0.35; extra == "server"
33
+ Provides-Extra: admin
34
+ Requires-Dist: pandas<3,>=2.2; extra == "admin"
35
+ Requires-Dist: streamlit<2,>=1.45; extra == "admin"
36
+ Provides-Extra: dev
37
+ Requires-Dist: build<2,>=1.2; extra == "dev"
38
+ Requires-Dist: pytest<9,>=8.3; extra == "dev"
39
+ Requires-Dist: twine<7,>=5; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # SysML Refinement API
43
+
44
+ This repository contains two distinct products:
45
+ - a public Python SDK and CLI, published as `sysmlv2copilot`
46
+ - an internal server/admin implementation that stays hosted and black-box
47
+
48
+ ## Repo Split
49
+
50
+ The repository is now organized into two explicit halves:
51
+ - `api/`: index for the service/SDK/admin side
52
+ - `finetune/`: local dataset generation, repair corpus, and fine-tuning assets
53
+
54
+ To avoid breaking runtime imports in one large move, the API code still currently lives in the root-owned paths such as `app/`, `alembic/`, `sysmlv2copilot/`, `sysmlv2copilot_admin/`, and the main `scripts/` directory. The fine-tuning assets now live directly under `finetune/`.
55
+
56
+ The hosted service accepts either natural-language requirements or SysML input, runs the compiler-in-the-loop workflow, returns SysML plus structured metadata, and stores each request with a single persisted artifact bundle.
57
+
58
+ The service itself is intentionally narrow:
59
+ - internal-only
60
+ - one user, one API key
61
+ - plain text in, SysML text out
62
+ - FastAPI HTTP layer
63
+ - Postgres-compatible metadata storage
64
+ - filesystem artifact storage by default
65
+ - admin operations through CLI scripts, not public admin routes
66
+
67
+ ## Public SDK
68
+
69
+ The public package is client-only. It does not ship the backend, migrations, deployment code, or admin console.
70
+
71
+ Install from PyPI:
72
+
73
+ ```bash
74
+ python -m pip install sysmlv2copilot
75
+ ```
76
+
77
+ Basic generation:
78
+
79
+ ```python
80
+ from sysmlv2copilot import SysMLCopilot
81
+
82
+ with SysMLCopilot(
83
+ api_key="sysml_live_...",
84
+ base_url="https://your-deployment.example.com",
85
+ ) as client:
86
+ response = client.responses.create(
87
+ input="Design a compact warehouse inspection drone that can hover for 15 minutes.",
88
+ provider="openai",
89
+ )
90
+ print(response.id)
91
+ print(response.output_text)
92
+ ```
93
+
94
+ Basic repair:
95
+
96
+ ```python
97
+ from sysmlv2copilot import SysMLCopilot
98
+
99
+ broken_sysml = """package Example {
100
+ public import ScalarValues::*;
101
+ requirement def R { text = "Missing semicolon" }
102
+ }
103
+ """
104
+
105
+ with SysMLCopilot(
106
+ api_key="sysml_live_...",
107
+ base_url="https://your-deployment.example.com",
108
+ ) as client:
109
+ repaired = client.repairs.create(input=broken_sysml, provider="openai")
110
+ print(repaired.compiler_passed)
111
+ print(repaired.output_text)
112
+ ```
113
+
114
+ CLI examples:
115
+
116
+ ```bash
117
+ sysmlv2copilot --api-key sysml_live_... \
118
+ --base-url https://your-deployment.example.com \
119
+ responses create \
120
+ --input "Design a compact warehouse inspection drone that can hover for 15 minutes."
121
+
122
+ sysmlv2copilot --api-key sysml_live_... \
123
+ --base-url https://your-deployment.example.com \
124
+ repairs create \
125
+ --input-file ./broken.sysml
126
+ ```
127
+
128
+ SDK details:
129
+ - [docs/PYTHON_SDK.md](/Users/chancelavoie/Desktop/sysmlv2copilot/docs/PYTHON_SDK.md)
130
+ - [docs/PYPI_RELEASE.md](/Users/chancelavoie/Desktop/sysmlv2copilot/docs/PYPI_RELEASE.md)
131
+
132
+ ## What It Solves
133
+
134
+ The upstream pipeline already knows how to:
135
+ - build the iterative refinement prompt
136
+ - call the OpenAI Responses API
137
+ - write every iteration prompt and candidate SysML file
138
+ - run `syside check`
139
+ - capture compiler diagnostics
140
+ - stop on success or refinement limits
141
+
142
+ This service wraps that exact behavior in an authenticated API with request tracking and persistent artifacts so an internal team can use it immediately.
143
+
144
+ The refinement loop now supports either upstream provider:
145
+ - OpenAI via the Responses API
146
+ - Anthropic via the Messages API
147
+
148
+ The public API surface stays narrow and OpenAI-style. Provider choice is an internal runtime option exposed as an extra request field.
149
+
150
+ ## Repo Layout
151
+
152
+ - `app/`: FastAPI app, auth, DB models, storage, and upstream wrapper
153
+ - `app/upstream/refine_sysml.py`: vendored upstream refiner used as the behavior source of truth
154
+ - `context/upstream/`: tight context package copied from the upstream repo
155
+ - `scripts/`: admin CLI for user creation, API key reset, and usage reporting
156
+ - `alembic/`: schema migrations
157
+ - `sysmlv2copilot/`: public client SDK and CLI package
158
+ - `sysmlv2copilot_admin/`: internal Streamlit admin console
159
+ - `tests/`: API, CLI, and config coverage
160
+
161
+ ## Internal Repo Setup
162
+
163
+ If you are working on the hosted backend from this repo, install the internal extras:
164
+
165
+ 1. Create a virtual environment and install dependencies:
166
+
167
+ ```bash
168
+ python3 -m venv .venv
169
+ source .venv/bin/activate
170
+ python -m pip install --upgrade pip
171
+ python -m pip install -e ".[server,admin,dev]"
172
+ ```
173
+
174
+ 2. Create `.env`:
175
+
176
+ ```bash
177
+ cp .env.example .env
178
+ ```
179
+
180
+ 3. Fill in at least:
181
+ - one or both of `OPENAI_API_KEY` / `ANTHROPIC_API_KEY`
182
+ - one of `SYSIDE_VENV_PATH` or `SYSIDE_EXECUTABLE_PATH`
183
+ - `API_KEY_HASH_PEPPER`
184
+ - optionally a PostgreSQL `DATABASE_URL`
185
+
186
+ SQLite works for local development. PostgreSQL or Supabase Postgres is preferred for shared environments.
187
+ For PostgreSQL or Supabase, install/runtime support now includes `psycopg`.
188
+
189
+ ## Migrations
190
+
191
+ Run the schema migration before starting the service:
192
+
193
+ ```bash
194
+ alembic upgrade head
195
+ ```
196
+
197
+ ## Start The Service
198
+
199
+ ```bash
200
+ uvicorn app.main:app --reload
201
+ ```
202
+
203
+ The default address is `http://127.0.0.1:8000`.
204
+
205
+ ## Create A User And API Key
206
+
207
+ Create a user and print the plaintext key once:
208
+
209
+ ```bash
210
+ python scripts/create_user.py --email engineer@example.com --name "Internal Engineer"
211
+ ```
212
+
213
+ Reset the single API key for an existing user:
214
+
215
+ ```bash
216
+ python scripts/reset_api_key.py --email engineer@example.com
217
+ ```
218
+
219
+ List usage:
220
+
221
+ ```bash
222
+ python scripts/list_usage.py --email engineer@example.com --from-date 2026-03-01 --to-date 2026-03-31
223
+ ```
224
+
225
+ ## Call The API
226
+
227
+ ```bash
228
+ curl -s http://127.0.0.1:8000/v1/responses \
229
+ -H "Authorization: Bearer sysml_live_..." \
230
+ -H "Content-Type: application/json" \
231
+ -d '{
232
+ "input": "Design a compact battery-powered inspection drone that fits in a 30 cm cube and flies for 20 minutes.",
233
+ "model": "refine-sysml-v1",
234
+ "provider": "openai",
235
+ "max_iters": 10,
236
+ "max_total_tokens": 40000,
237
+ "temperature": null
238
+ }'
239
+ ```
240
+
241
+ Example successful response:
242
+
243
+ ```json
244
+ {
245
+ "id": "resp_20260312_161200_abcd",
246
+ "object": "response",
247
+ "status": "completed",
248
+ "model": "refine-sysml-v1",
249
+ "output_text": "package RequirementsOnly { ... }",
250
+ "compiler_passed": true,
251
+ "iterations_completed": 4,
252
+ "started_at": "2026-03-12T16:12:00Z",
253
+ "finished_at": "2026-03-12T16:12:22Z",
254
+ "duration_ms": 22014,
255
+ "request_user_id": "usr_1234",
256
+ "metadata": {
257
+ "provider": "openai",
258
+ "upstream_model": "gpt-5-mini",
259
+ "run_id": "run_20260312_161200_abcd",
260
+ "artifact_paths": {
261
+ "request_artifact": "/abs/path/request_artifact.json"
262
+ }
263
+ },
264
+ "error": null
265
+ }
266
+ ```
267
+
268
+ Repair request example:
269
+
270
+ ```bash
271
+ curl -s http://127.0.0.1:8000/v1/repairs \
272
+ -H "Authorization: Bearer sysml_live_..." \
273
+ -H "Content-Type: application/json" \
274
+ -d '{
275
+ "input": "package Example { requirement def R { text = \"Missing semicolon\" } }",
276
+ "model": "refine-sysml-v1",
277
+ "provider": "openai"
278
+ }'
279
+ ```
280
+
281
+ Anthropic request example:
282
+
283
+ ```bash
284
+ curl -s http://127.0.0.1:8000/v1/responses \
285
+ -H "Authorization: Bearer sysml_live_..." \
286
+ -H "Content-Type: application/json" \
287
+ -d '{
288
+ "input": "Design a compact battery-powered inspection drone that fits in a 30 cm cube and flies for 20 minutes.",
289
+ "model": "refine-sysml-v1",
290
+ "provider": "anthropic",
291
+ "upstream_model": "claude-sonnet-4-5-20250929"
292
+ }'
293
+ ```
294
+
295
+ Check a stored request:
296
+
297
+ ```bash
298
+ curl -s http://127.0.0.1:8000/v1/requests/resp_20260312_161200_abcd \
299
+ -H "Authorization: Bearer sysml_live_..."
300
+ ```
301
+
302
+ Health check:
303
+
304
+ ```bash
305
+ curl -s http://127.0.0.1:8000/healthz
306
+ ```
307
+
308
+ ## Repair Workflow
309
+
310
+ The hosted API now supports a repair-oriented workflow:
311
+ - accept raw SysML text
312
+ - run SysIDE immediately
313
+ - if the model already passes, return it unchanged with `iterations_completed = 0`
314
+ - if it fails, feed the broken SysML plus real compiler diagnostics into the repair loop
315
+ - persist the same request tracking and single-artifact bundle used by generation requests
316
+
317
+ Repair metadata includes:
318
+ - `metadata.operation = "repair"`
319
+ - `metadata.initial_compiler_passed`
320
+ - `metadata.diagnostics_summary`
321
+
322
+ Design note:
323
+ - [docs/ITERATION_STALL_POLICY.md](/Users/chancelavoie/Desktop/sysmlv2copilot/docs/ITERATION_STALL_POLICY.md)
324
+
325
+ ## Admin Frontend
326
+
327
+ Run the Streamlit admin console:
328
+
329
+ ```bash
330
+ streamlit run sysmlv2copilot_admin/app.py
331
+ ```
332
+
333
+ It uses the real configured database and supports:
334
+ - create users and issue API keys
335
+ - rotate existing keys
336
+ - inspect per-user usage totals
337
+ - inspect overall usage and compiler performance
338
+ - browse recent request activity
339
+ - check live API health against a configured base URL
340
+
341
+ More detail:
342
+ - [docs/ADMIN_FRONTEND.md](/Users/chancelavoie/Desktop/sysmlv2copilot/docs/ADMIN_FRONTEND.md)
343
+ - [docs/PYPI_RELEASE.md](/Users/chancelavoie/Desktop/sysmlv2copilot/docs/PYPI_RELEASE.md)
344
+
345
+ ## Artifact Storage
346
+
347
+ Artifacts are stored under `ARTIFACT_ROOT`, defaulting to `./data/artifacts`. Each request gets a run directory with a single persisted artifact:
348
+ - `request_artifact.json`
349
+
350
+ That JSON bundle stores:
351
+ - the original input text
352
+ - the final SysML output
353
+ - request statistics such as tokens, chars, duration, and iterations
354
+ - provider/model metadata and any terminal error
355
+
356
+ Each request registers exactly one row in the `artifacts` table. Temporary iteration files used during SysIDE checks are removed before persistence.
357
+
358
+ ## Tests
359
+
360
+ Run the test suite with:
361
+
362
+ ```bash
363
+ pytest
364
+ ```
365
+
366
+ The tests mock the expensive upstream generation path and cover auth, request tracking, repair flow, artifacts, CLI operations, health reporting, packaging boundaries, and config validation.
367
+
368
+ ## Docker
369
+
370
+ Build:
371
+
372
+ ```bash
373
+ docker build \
374
+ --build-arg SYSIDE_PIP_SPEC='syside==<your-version>' \
375
+ --build-arg REQUIRE_SYSIDE=1 \
376
+ -t sysml-refinement-api .
377
+ ```
378
+
379
+ Run:
380
+
381
+ ```bash
382
+ docker run --rm -p 8000:8000 --env-file .env sysml-refinement-api
383
+ ```
384
+
385
+ The container runs `alembic upgrade head` before starting `uvicorn`.
386
+
387
+ ## Azure And Supabase
388
+
389
+ The repo is now prepared for:
390
+ - Azure Container Apps for compute
391
+ - Azure Container Registry for the private image
392
+ - Azure Files for persistent artifacts
393
+ - Supabase Postgres for metadata
394
+
395
+ Relevant files:
396
+ - [docs/AZURE_CONTAINER_APPS.md](/Users/chancelavoie/Desktop/sysmlv2copilot/docs/AZURE_CONTAINER_APPS.md)
397
+ - [scripts/deploy_azure_container_app.sh](/Users/chancelavoie/Desktop/sysmlv2copilot/scripts/deploy_azure_container_app.sh)
398
+ - [scripts/build_database_url.py](/Users/chancelavoie/Desktop/sysmlv2copilot/scripts/build_database_url.py)
399
+ - [scripts/render_azure_containerapp_yaml.py](/Users/chancelavoie/Desktop/sysmlv2copilot/scripts/render_azure_containerapp_yaml.py)
400
+ - [infra/supabase/create_service_role.sql](/Users/chancelavoie/Desktop/sysmlv2copilot/infra/supabase/create_service_role.sql)
401
+
402
+ To build a Supabase-compatible SQLAlchemy URL:
403
+
404
+ ```bash
405
+ python scripts/build_database_url.py \
406
+ --host db.<project-ref>.supabase.co \
407
+ --port 5432 \
408
+ --database postgres \
409
+ --user sysml_api_service \
410
+ --password 'replace-me'
411
+ ```
412
+
413
+ To deploy to Azure Container Apps:
414
+
415
+ ```bash
416
+ export BUILD_MODE=local-docker
417
+ bash scripts/deploy_azure_container_app.sh
418
+ ```
419
+
420
+ ## Upstream Context
421
+
422
+ The copied upstream context package lives in:
423
+ - `context/upstream/refine_sysml.py`
424
+ - `context/upstream/setup_pipeline_env.sh`
425
+ - `context/upstream/pipeline_README.md`
426
+ - `context/upstream/pipeline_HELP.md`
427
+ - `context/upstream/env.example`
428
+ - `context/examples/example_prompt.txt`
429
+ - `context/examples/example_output.sysml`
430
+ - `context/examples/example_run_log.json`
431
+
432
+ That context is intentionally tight and keeps the original refinement flow visible without copying the whole older repository.