isynth-ai-data-config 0.8.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.
Files changed (36) hide show
  1. isynth_ai_data_config-0.8.0/PKG-INFO +441 -0
  2. isynth_ai_data_config-0.8.0/README.md +417 -0
  3. isynth_ai_data_config-0.8.0/__init__.py +28 -0
  4. isynth_ai_data_config-0.8.0/bill_of_materials.py +104 -0
  5. isynth_ai_data_config-0.8.0/config.py +159 -0
  6. isynth_ai_data_config-0.8.0/isynth_ai_data_config.egg-info/PKG-INFO +441 -0
  7. isynth_ai_data_config-0.8.0/isynth_ai_data_config.egg-info/SOURCES.txt +60 -0
  8. isynth_ai_data_config-0.8.0/isynth_ai_data_config.egg-info/dependency_links.txt +1 -0
  9. isynth_ai_data_config-0.8.0/isynth_ai_data_config.egg-info/entry_points.txt +2 -0
  10. isynth_ai_data_config-0.8.0/isynth_ai_data_config.egg-info/requires.txt +8 -0
  11. isynth_ai_data_config-0.8.0/isynth_ai_data_config.egg-info/top_level.txt +1 -0
  12. isynth_ai_data_config-0.8.0/llm_helper.py +994 -0
  13. isynth_ai_data_config-0.8.0/logging_setup.py +191 -0
  14. isynth_ai_data_config-0.8.0/mcp_server/__init__.py +9 -0
  15. isynth_ai_data_config-0.8.0/mcp_server/__main__.py +10 -0
  16. isynth_ai_data_config-0.8.0/mcp_server/admin.py +179 -0
  17. isynth_ai_data_config-0.8.0/mcp_server/helpers/__init__.py +5 -0
  18. isynth_ai_data_config-0.8.0/mcp_server/helpers/_loading.py +96 -0
  19. isynth_ai_data_config-0.8.0/mcp_server/helpers/ai_training.py +100 -0
  20. isynth_ai_data_config-0.8.0/mcp_server/helpers/composers.py +95 -0
  21. isynth_ai_data_config-0.8.0/mcp_server/helpers/constellations.py +155 -0
  22. isynth_ai_data_config-0.8.0/mcp_server/helpers/enums.py +47 -0
  23. isynth_ai_data_config-0.8.0/mcp_server/helpers/functions.py +78 -0
  24. isynth_ai_data_config-0.8.0/mcp_server/helpers/object_types.py +412 -0
  25. isynth_ai_data_config-0.8.0/mcp_server/server.py +148 -0
  26. isynth_ai_data_config-0.8.0/mcp_server/tools.py +216 -0
  27. isynth_ai_data_config-0.8.0/mcp_server/validation.py +274 -0
  28. isynth_ai_data_config-0.8.0/pyproject.toml +64 -0
  29. isynth_ai_data_config-0.8.0/requirements.txt +19 -0
  30. isynth_ai_data_config-0.8.0/settings.yml +92 -0
  31. isynth_ai_data_config-0.8.0/setup.cfg +4 -0
  32. isynth_ai_data_config-0.8.0/validation/__init__.py +7 -0
  33. isynth_ai_data_config-0.8.0/validation/config_validator.py +443 -0
  34. isynth_ai_data_config-0.8.0/validation/example_definitions.py +418 -0
  35. isynth_ai_data_config-0.8.0/validation/excel_export.py +281 -0
  36. isynth_ai_data_config-0.8.0/validation/validator_base.py +40 -0
@@ -0,0 +1,441 @@
1
+ Metadata-Version: 2.4
2
+ Name: isynth-ai-data-config
3
+ Version: 0.8.0
4
+ Summary: Generate iSynth data_config test-data definitions from a plain-language request, using an LLM that reads the environment's own metadata.
5
+ Author-email: Markus Herrmann <markus.herrmann@itopia.ch>
6
+ License-Expression: LicenseRef-Proprietary
7
+ Project-URL: Homepage, https://isynth.io
8
+ Keywords: isynth,mcp,llm,data-config,test-data,synthetic-data
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Topic :: Software Development :: Testing
14
+ Requires-Python: >=3.13
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: litellm>=1.0
17
+ Requires-Dist: fastmcp>=4.0
18
+ Requires-Dist: openpyxl>=3.0
19
+ Requires-Dist: python-box>=7.0
20
+ Requires-Dist: python-dotenv>=1.0
21
+ Requires-Dist: httpx>=0.28
22
+ Requires-Dist: PyYAML>=6.0
23
+ Requires-Dist: starlette>=1.0
24
+
25
+ # isynth-ai-data-config
26
+
27
+ Generate iSynth `data_config` files from a request written in plain language, instead
28
+ of hand-writing YAML against a data model you have to memorise first.
29
+
30
+ You describe the test data you want — *"a private client with one account, no
31
+ portfolio, no phone number"* — and you get back a ready `data_config` that iSynth can
32
+ execute:
33
+
34
+ ```yaml
35
+ simple_client:
36
+ based_on: banking.individual_client
37
+ number_of_copies: 1
38
+ parameters:
39
+ number_of_accounts: 1
40
+ number_of_portfolios: 0
41
+ number_of_phone_numbers: 0
42
+ number_of_email_addresses: 0
43
+ composers: []
44
+ ```
45
+
46
+ An LLM writes that file, but it does not guess the vocabulary. `banking.individual_client`,
47
+ `number_of_accounts` and every other name in the output come from **your** environment's
48
+ own metadata, which the model reads through a set of tools while it works. The draft is
49
+ then validated against that same metadata, and anything that does not check out goes
50
+ back to the model for correction before you ever see it.
51
+
52
+ ## Some iSynth vocabulary first
53
+
54
+ If you have not worked with iSynth: it is a platform for generating synthetic test
55
+ data. A few terms show up throughout this document.
56
+
57
+ | Term | What it means |
58
+ |---|---|
59
+ | **env** (environment) | One iSynth project — its own data model, its own directory on disk. This package is installed per env. |
60
+ | **object type** | An entity in that model: `NaturalPerson`, `Account`, `PostalAddress`. |
61
+ | **constellation template** | A reusable bundle of objects that belong together — a client with their accounts and addresses. It is the `based_on` value of a case. |
62
+ | **composer** | A building block that adds objects to a constellation, in a defined order. |
63
+ | **data_config** | The YAML file this package produces: one or more named cases, each saying what to build. iSynth executes it to create the actual data. |
64
+
65
+ Everything above already exists in your env before this package is installed. The
66
+ package only reads it.
67
+
68
+ ## How it works
69
+
70
+ The model is not given a dump of your data model. It gets 14 tools and fetches only
71
+ what it needs:
72
+
73
+ | Tool group | Examples |
74
+ |---|---|
75
+ | Object types | `list_object_types`, `get_object_type` |
76
+ | Composers | `list_composers`, `get_composer`, `get_composer_order` |
77
+ | Constellation templates | `list_constellation_templates`, `get_constellation_template` |
78
+ | Enums and functions | `list_enums`, `get_enum`, `list_functions`, `get_function` |
79
+ | Curated examples | `list_ai_training_examples`, `get_ai_training_example` |
80
+ | Validation | `validate_data_config` |
81
+
82
+ Those tools are plain Python functions in one registry. Generation calls them
83
+ **in-process** — no HTTP, no running server. The same registry is also served over MCP
84
+ (streamable-http) for external clients such as IDE agents; that is optional and covered
85
+ below.
86
+
87
+ LLM access goes through [LiteLLM](https://www.litellm.ai/), so a local model in LM
88
+ Studio and a hosted one are configured the same way. The model must support **native
89
+ tool calling**.
90
+
91
+ ## Requirements
92
+
93
+ - **Python 3.10** or newer.
94
+ - **An iSynth env**, with these already in place:
95
+
96
+ | Path | Where it comes from |
97
+ |---|---|
98
+ | `__generated__/*.json` | the iSynth action **Initialize environment** (object types, composers, enums, functions) |
99
+ | `constellations/__generated__/**/*.json` | generated from the env's constellation modules |
100
+ | `data_configs/ai_training/` | **must exist**, may be empty — otherwise `list_ai_training_examples` raises `FileNotFoundError` |
101
+ | `__generated__/composer_sequence.txt` | written once by the restart plugin, see *Composer order* below |
102
+
103
+ Generation works without training examples, but noticeably worse: they are what the
104
+ model orients itself on.
105
+
106
+ - **A tool-calling LLM** — local (LM Studio) or hosted. It must handle *native*
107
+ function calling over several turns: choose a tool, read the result, choose the next,
108
+ produce valid JSON arguments, and finally answer with a single JSON object. Prompt-
109
+ engineered tool use is not enough. See *LLM settings* below.
110
+
111
+ ## Install
112
+
113
+ ```
114
+ pip install isynth-ai-data-config
115
+ ```
116
+
117
+ Or add `isynth-ai-data-config` to your env's `requirements.txt` and install
118
+ that as usual.
119
+
120
+ Installing gives you the library. It does **not** yet put anything in the iSynth UI —
121
+ that needs the plugin wrappers from *Full integration* below. If you only want the MCP
122
+ tool server, or want to call `generate_data_order()` from your own code, you can stop
123
+ after *Configuration*.
124
+
125
+ ### Alternative: copy the folder
126
+
127
+ The package can also be copied wholesale into an env instead of installed — the way it
128
+ was distributed before it was published, still supported for an env that cannot reach
129
+ the private index. The steps (copying the folder, including its `requirements.txt` from
130
+ the env's own list, the Docker build context and the `.dockerignore` that keeps it
131
+ small) are in `install-by-copying.md`, which ships inside the package.
132
+
133
+ ## Configuration
134
+
135
+ ### Model
136
+
137
+ Defaults ship in the package's own `settings.yml`. To deviate, repeat the same key in
138
+ your **env's** `settings.yml` — the env wins:
139
+
140
+ ```yaml
141
+ LLM_MODEL: "lm_studio/qwen3.8-27b-gguf"
142
+ LLM_API_BASE: "http://192.168.1.100:1234/v1"
143
+ ```
144
+
145
+ `${VARIABLE_NAME}` substitution works as in any iSynth `settings.yml`. You never edit a
146
+ file inside the package, which is what keeps it upgradable.
147
+
148
+ Only keys the package declares are read from the env; an `LLM_*`/`AI_*` key with a typo
149
+ is reported as a warning naming the key. The ones you are most likely to touch:
150
+
151
+ | Key | Default | What it does |
152
+ |---|---|---|
153
+ | `LLM_MODEL` | `openai/gpt-5.6-sol` | any LiteLLM model identifier |
154
+ | `LLM_API_BASE` | — | for local or self-hosted endpoints |
155
+ | `LLM_REQUEST_TIMEOUT` | `1800` | seconds; local models can be slow |
156
+ | `LLM_MAX_OUTPUT_TOKENS` | `10000` | |
157
+ | `AI_MAX_TOOL_TURNS` | `20` | budget for the tool-calling loop |
158
+ | `AI_MAX_VALIDATION_ROUNDS` | `2` | correction rounds; `0` disables validation |
159
+ | `AI_MAX_TRAINING_EXAMPLES` | `3` | how many curated examples may be fetched |
160
+
161
+ The full list, each with a comment explaining it, is in the package's `settings.yml`.
162
+
163
+ ### LLM settings
164
+
165
+ The package sends **no sampling parameters** — no temperature, no top_p. Those come
166
+ from the defaults of whatever serves the model (LM Studio, vLLM, the hosted API). The
167
+ one exception is `LLM_CHAT_TEMPLATE_KWARGS`, which travels with each request. So these
168
+ are settings you make on the server, not here. **A model vendor's own recommendation
169
+ always takes precedence over the table below.**
170
+
171
+ | Setting | Suggested | Why |
172
+ |---|---|---|
173
+ | Reasoning / thinking mode | **off** | Decode dominates the runtime, and thinking tokens are decode. Measured on a local 27B: 85% of all generated tokens went into reasoning. Risk of thinking blocks or empty answers instead of JSON. |
174
+ | Tool / function calling | **on, native** | Mandatory — the tools are passed over the API as `tools=[...]`. |
175
+ | Temperature | 0.1–0.2 to start | Qwen warns against greedy decoding (`0.0` causes repetition loops, it recommends `0.7`); gpt-oss is specified for `1.0`. Start low, raise if you see loops. |
176
+ | Top P | 0.8–0.9 | Keep conservative for structured output. |
177
+ | Top K | 20–40 | Qwen recommends 20. |
178
+ | Repeat penalty | 1.0–1.05 | Higher values corrupt recurring field names. |
179
+ | Context length | 64K | A run including two correction rounds needs ~15–25K tokens. Use 128K only if you need it. |
180
+ | Max response tokens | 2048–4096 | Per assistant turn, tool-call arguments included. The final JSON and the largest tool argument stay under 1K. |
181
+ | Prompt truncation | **disabled** | Set the overflow policy to stop at the limit. The transcript grows over the correction rounds; "truncate middle" would silently cut away rules or examples. |
182
+ | Structured output / JSON schema | use with care | Forcing a schema on every answer can suppress tool calls. `validate_data_config` checks the final JSON anyway. |
183
+ | Quantization | 6–8 bit where memory allows | 4-bit produces measurably less precise tool arguments. Drop to 4-bit only as a memory fallback. |
184
+ | Seed | fixed | Makes a validation run reproducible. |
185
+
186
+ Running locally, pick a model by class rather than by name — a specific ranking dates
187
+ quickly. With 16 GB expect to be limited to a small MoE or an aggressively quantized
188
+ model, and to lose precision in tool arguments; 24–32 GB comfortably runs a mid-size
189
+ MoE with few active parameters at 4-bit; from 64 GB a dense model in the 27–35B range
190
+ at 6–8 bit becomes practical. Mixture-of-experts models with roughly 3–4B active
191
+ parameters give the best interactive latency, because decode speed, not model size, is
192
+ what a run waits on.
193
+
194
+ ### API keys
195
+
196
+ Keys do **not** belong in `settings.yml`. They go in `<env>/.keys`, in dotenv format.
197
+ Anything ending in `_API_KEY` or `_API_BASE` is picked up:
198
+
199
+ ```
200
+ OPENAI_API_KEY=sk-...
201
+ ANTHROPIC_API_KEY=sk-ant-...
202
+ ```
203
+
204
+ A missing file is not an error — an env that sets its keys as real environment
205
+ variables does not need one.
206
+
207
+ ### GitHub Copilot
208
+
209
+ `LLM_MODEL: "github_copilot/<model>"` runs on a Copilot subscription instead of a
210
+ provider API key. There is no key to put in `.keys`: litellm authenticates with a
211
+ GitHub OAuth token that it obtains once through a device flow and then keeps in a
212
+ token directory, as two files.
213
+
214
+ | File | What it is |
215
+ |---|---|
216
+ | `access-token` | the long-lived GitHub token, written by the device flow |
217
+ | `api-key.json` | the short-lived Copilot key, refreshed automatically |
218
+
219
+ The default directory is `~/.config/litellm/github_copilot`, which inside a container
220
+ is lost on the next rebuild. So set the directory **first**, then log in.
221
+
222
+ **1. Point the token directory at the env.** In `<env>/.keys`, next to the other
223
+ credentials:
224
+
225
+ ```
226
+ GITHUB_COPILOT_TOKEN_DIR=/isynth_envs/<env>/.copilot
227
+ ```
228
+
229
+ Every `GITHUB_COPILOT_*` variable in `.keys` is exported, the same way as an
230
+ `_API_KEY`. Add `.copilot/` to the env's `.gitignore` — it holds a credential.
231
+
232
+ **2. Log in once, interactively.** The device flow prints a code and waits for
233
+ someone at a browser, so do it by hand rather than letting it happen inside a plugin
234
+ call. Importing `ai_data_config.llm_helper` is what applies step 1 — with plain
235
+ `import litellm` the token would land in the container's home directory instead:
236
+
237
+ ```bash
238
+ docker exec -it <appserver> sh -c 'cd /isynth_envs/<env> && python3 -c "
239
+ import ai_data_config.llm_helper, litellm
240
+ litellm.completion(model=\"github_copilot/<model>\",
241
+ messages=[{\"role\": \"user\", \"content\": \"hi\"}])
242
+ "'
243
+ ```
244
+
245
+ It prints `Please visit https://github.com/login/device and enter code XXXX-XXXX`.
246
+ Open that page, enter the code, approve. The call then answers normally.
247
+
248
+ **3. Check that both files are there.**
249
+
250
+ ```bash
251
+ docker exec <appserver> ls /isynth_envs/<env>/.copilot
252
+ # access-token api-key.json
253
+ ```
254
+
255
+ **4. Set the model.** In the env's `settings.yml`:
256
+
257
+ ```yaml
258
+ LLM_MODEL: "github_copilot/<model>"
259
+ ```
260
+
261
+ Leave `LLM_API_BASE` empty — litellm resolves `https://api.githubcopilot.com` itself.
262
+ Which models you can name is Copilot's list, not litellm's.
263
+
264
+ **5. Verify**, with the check under *Full integration → Check that it works*. From
265
+ here on nothing is Copilot-specific; generation, the MCP tools and validation runs
266
+ behave as with any other model.
267
+
268
+ Steps 1 and 2 are needed once per env. The `api-key.json` expires regularly and is
269
+ refreshed without asking; the `access-token` survives until it is revoked on GitHub.
270
+
271
+ Two notes on the integration. It is litellm's **provider** integration
272
+ (`docs.litellm.ai/docs/providers/github_copilot`) — not the *tutorial* page of a
273
+ similar name, which points the Copilot IDE extension at a LiteLLM proxy and is the
274
+ opposite direction. And tool calling, which this package depends on, works even
275
+ though that page does not mention it.
276
+
277
+ For a non-default setup the remaining variables also go in `.keys`:
278
+ `_ACCESS_TOKEN_FILE` and `_API_KEY_FILE` rename the two files; `_API_BASE`,
279
+ `_DEVICE_CODE_URL`, `_ACCESS_TOKEN_URL` and `_API_KEY_URL` point at a GitHub
280
+ Enterprise endpoint.
281
+
282
+ ## Using it from Python
283
+
284
+ ```python
285
+ from ai_data_config.llm_helper import generate_data_order
286
+
287
+ data_config = generate_data_order("a private client with one account, no portfolio")
288
+ ```
289
+
290
+ `generate_data_order(prompt, content=None)` builds the messages, runs the tool-calling
291
+ loop, then validates and orders the result. `content` is an existing `data_config` to
292
+ modify rather than start from scratch. It returns a dict, ready to be dumped as YAML.
293
+
294
+ This needs no running MCP server and no iSynth runtime — only the env's generated
295
+ metadata on disk, found via `ENV_HOME`.
296
+
297
+ ---
298
+
299
+ # Full integration
300
+
301
+ The steps that put the package into the iSynth UI. Skip any you do not need.
302
+
303
+ ## 1. Plugin wrappers
304
+
305
+ The four files in `plugins/` are only the iSynth UI; the functionality lives in the
306
+ package. Copy them into your env's `plugins/` folder.
307
+
308
+ Each wrapper needs `base.plugin` (the iSynth plugin API), most also `base.logging`.
309
+ Beyond that:
310
+
311
+ | Wrapper | Calls | Additionally needs |
312
+ |---|---|---|
313
+ | `plugins/ai_data_config.py` | `llm_helper.generate_data_order()` | — |
314
+ | `plugins/validate_ai_prompts.py` | `validation.config_validator.prepare_and_execute_validation_run()` | — |
315
+ | `plugins/restart_mcp_server.py` | `mcp_server.admin.request_restart()` | `base.composers.Composer`, `settings.BASE_DIR` |
316
+ | `plugins/bill_of_materials.py` | `bill_of_materials.calculate_bill_of_materials()` | `base.plugin_pro.ParameterType` |
317
+
318
+ Afterwards run **"Reload plugins"** from the context menu of the `plugins/` folder in
319
+ the UI — the REST API serves new definitions immediately, the UI only after that.
320
+
321
+ ## 2. Composer order (once)
322
+
323
+ `get_composer_order()` reads `__generated__/composer_sequence.txt`. Without that file it
324
+ returns an **empty list**, and the system prompt then fails to tell the model which
325
+ order composer entries have to be in.
326
+
327
+ The restart plugin writes it: run **Restart MCP Server** with the checkbox ticked. It
328
+ fetches the order via `Composer.execution_sequence()` and writes the file *before*
329
+ restarting the server, so it appears even when no MCP server is running yet (the
330
+ restart call then fails, which is fine).
331
+
332
+ Repeat after any model change that adds, removes or reorders composers. The file is
333
+ read at import time, so a running process only picks up a change after a restart.
334
+
335
+ ## 3. MCP server service (optional)
336
+
337
+ Only needed for external MCP clients (IDE agents) and for the **Restart MCP Server**
338
+ plugin. Generation and validation runs do **not** need it — they call the same tools
339
+ in-process and keep working with the service stopped.
340
+
341
+ ```yaml
342
+ i-mcpserver:
343
+ build:
344
+ context: ../
345
+ dockerfile: deployment/Dockerfile
346
+ restart: unless-stopped # safety net, should os.execv fail on restart
347
+ environment:
348
+ - ENV_HOME=/isynth_envs/<env> # must match the mount target below
349
+ - MCP_TRANSPORT=streamable-http
350
+ - MCP_HOST=0.0.0.0
351
+ - MCP_PORT=8010
352
+ - MCP_PATH=/mcp
353
+ - MCP_WAIT_FOR_GENERATED_TIMEOUT=60
354
+ volumes:
355
+ - "../:/isynth_envs/<env>"
356
+ working_dir: /isynth_envs/<env> # so "-m ai_data_config.mcp_server" resolves
357
+ networks: [<the appserver's network>]
358
+ ports:
359
+ - "8010:8010"
360
+ command: "python3 -m ai_data_config.mcp_server"
361
+ ```
362
+
363
+ **The service name is not free.** `mcp_server/admin.py` has
364
+ `DEFAULT_BASE_URL = "http://i-mcpserver:8010"`, which is where the restart plugin looks.
365
+ Either the service is called `i-mcpserver`, or the appserver service sets
366
+ `MCP_SERVER_URL` to the right address.
367
+
368
+ Installed from the index, the package also puts an `ai-data-config-mcp` command on
369
+ `PATH`, equivalent to `python3 -m ai_data_config.mcp_server`.
370
+
371
+ ## 4. Check that it works
372
+
373
+ ```bash
374
+ # package loads, settings arrive, tools answer
375
+ docker exec <appserver> sh -c 'cd /isynth_envs/<env> && python3 -c "
376
+ from ai_data_config import config, llm_helper
377
+ from ai_data_config.mcp_server.tools import TOOLS, call_tool
378
+ print(\"ENV_HOME :\", config.ENV_HOME)
379
+ print(\"LLM_MODEL:\", llm_helper.DEFAULT_MODEL)
380
+ print(\"Tools :\", len(TOOLS))
381
+ print(\"Composer :\", call_tool(\"get_composer_order\", {})[:3], \"...\")
382
+ print(\"Examples :\", len(call_tool(\"list_ai_training_examples\", {})))
383
+ "'
384
+
385
+ # MCP server, if you set one up
386
+ curl -s http://localhost:8010/health
387
+ ```
388
+
389
+ Expected: 14 tools, a **non-empty** composer order, the number of training examples, and
390
+ `{"status":"ok",...}`. An empty composer list means step 2 is missing.
391
+
392
+ # What needs iSynth and what does not
393
+
394
+ `llm_helper` and `mcp_server` import nothing from `base` — generation and the MCP tools
395
+ run in any directory where the dependencies are installed, iSynth or not.
396
+
397
+ Only `bill_of_materials.py` needs the iSynth runtime (`base.constellation_utils`,
398
+ `base.data_config_utils`), and through it the validation run, which compares the bill of
399
+ materials of a generated `data_config` against the case's reference. `base` is part of
400
+ the iSynth image and cannot be installed from an index, so importing that module
401
+ elsewhere raises a `ModuleNotFoundError` saying so.
402
+
403
+ The MCP server container is needed by none of this except `restart_mcp_server`.
404
+
405
+ # Troubleshooting
406
+
407
+ | Symptom | Cause |
408
+ |---|---|
409
+ | `FileNotFoundError: ai_training_dir source not found` | `data_configs/ai_training/` missing — create it, empty is fine |
410
+ | `FileNotFoundError: ... __generated__/...` | **Initialize environment** has not run in the env yet |
411
+ | `ModuleNotFoundError: No module named 'box'` or similar | dependencies not installed — see *Install* |
412
+ | `ModuleNotFoundError: ... needs the iSynth runtime ('base')` | `bill_of_materials` or the validation run is running outside an iSynth env |
413
+ | `MCP server at ... did not answer` | service is not called `i-mcpserver` and `MCP_SERVER_URL` is not set |
414
+ | Plugin does not appear in the UI | run "Reload plugins" from the context menu of the `plugins/` folder |
415
+ | Env override is ignored | key not declared in the package's `settings.yml` — the log warning names it |
416
+ | `get_composer_order()` is empty | `__generated__/composer_sequence.txt` missing — see *Composer order* |
417
+ | Logs are empty | not on STDOUT: the package logs with `propagate=False` into `<env>/logs/*.log` |
418
+
419
+ # Further reading
420
+
421
+ `install-by-copying.md` ships alongside this file: the alternative to installing,
422
+ copying the folder into an env and wiring up its dependencies and the Docker build
423
+ yourself.
424
+
425
+ # Building the package
426
+
427
+ ```bash
428
+ python -m build ai_data_config/ # -> ai_data_config/dist/*.whl and *.tar.gz
429
+ python -m twine upload ai_data_config/dist/* # -> pypi.org
430
+ ```
431
+
432
+ The build runs from inside the package folder, where `pyproject.toml` sits, because the
433
+ folder is meant to travel as one unit. Dependencies are declared only in
434
+ `requirements.txt`; `pyproject.toml` reads them from there via
435
+ `dynamic = ["dependencies"]`, so there is no second list to drift out of sync. The
436
+ package is published on pypi.org; its licence stays proprietary.
437
+
438
+ In CI (`.gitlab-ci.yml` in the repository root) this runs automatically: every change
439
+ under `ai_data_config/` is built and checked, and pushing a tag
440
+ `ai_data_config-v<version>` (matching `version` in `pyproject.toml`) publishes the
441
+ package to the project's GitLab package registry.