gen3-dataops-toolkit 3.3.0__tar.gz → 3.4.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 (56) hide show
  1. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/PKG-INFO +27 -1
  2. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/README.md +26 -0
  3. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/pyproject.toml +1 -1
  4. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/config_cmds.py +19 -0
  5. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/synth.py +88 -8
  6. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/config.py +35 -2
  7. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/synthetic_data/generate_synth_metadata.sh +16 -10
  8. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/__init__.py +0 -0
  9. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/__init__.py +0 -0
  10. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/_internal/__init__.py +0 -0
  11. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/_internal/dispatch.py +0 -0
  12. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/_internal/registry.py +0 -0
  13. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/_internal/resolve.py +0 -0
  14. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/_internal/runner.py +0 -0
  15. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/_internal/safety.py +0 -0
  16. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/delete_cmds.py +0 -0
  17. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/dict_cmds.py +0 -0
  18. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/ec2_cmds.py +0 -0
  19. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/indexd_cmds.py +0 -0
  20. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/jobs.py +0 -0
  21. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/k8s.py +0 -0
  22. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/main.py +0 -0
  23. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/metadata.py +0 -0
  24. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/pipeline_cmds.py +0 -0
  25. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/cli/release_cmds.py +0 -0
  26. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/indexd/__init__.py +0 -0
  27. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/indexd/file_access.py +0 -0
  28. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/indexd/indexd_registrar.py +0 -0
  29. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/ingest/ingest.py +0 -0
  30. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/resolver.py +0 -0
  31. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/delete/delete_all_metadata_for_project.py +0 -0
  32. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/delete/delete_metadata.sh +0 -0
  33. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/delete/delete_metadata_by_guid.py +0 -0
  34. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/dictionary/deploy_dd.sh +0 -0
  35. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/dictionary/pull_dict.sh +0 -0
  36. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/dictionary/upload_dictionary.py +0 -0
  37. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/indexd/register_indexd.py +0 -0
  38. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/indexd/verify_file_access.py +0 -0
  39. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/k8s_ops/argocd_restart_etl.sh +0 -0
  40. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/k8s_ops/argocd_restart_ms.sh +0 -0
  41. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/k8s_ops/argocd_restart_schema.sh +0 -0
  42. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/k8s_ops/login_to_pod.sh +0 -0
  43. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/k8s_ops/restart_etl_and_ms.sh +0 -0
  44. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/synthetic_data/delete_synth_metadata_sheepdog.py +0 -0
  45. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/synthetic_data/full_deploy_dd_and_synth.sh +0 -0
  46. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/synthetic_data/upload_synth_metadata_sheepdog.py +0 -0
  47. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/upload/metadata/upload_all_studies.sh +0 -0
  48. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/services/upload/metadata/upload_metadata.py +0 -0
  49. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/upload/__init__.py +0 -0
  50. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/upload/metadata_deleter.py +0 -0
  51. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/upload/metadata_submitter.py +0 -0
  52. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/upload/upload_synthdata_s3.py +0 -0
  53. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/utils/athena_utils.py +0 -0
  54. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/utils/dbt_utils.py +0 -0
  55. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/utils/release_writer.py +0 -0
  56. {gen3_dataops_toolkit-3.3.0 → gen3_dataops_toolkit-3.4.0}/src/g3dt/validate/validate.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gen3-dataops-toolkit
3
- Version: 3.3.0
3
+ Version: 3.4.0
4
4
  Summary: Gen3 DataOps toolkit (g3dt): operate SSM-published Gen3 data pipeline environments
5
5
  License: Apache-2.0
6
6
  Author: JoshuaHarris391
@@ -182,6 +182,32 @@ Synthetic data is only schema-valid against the dictionary that generated it, so
182
182
  refuses a batch that doesn't match the version being uploaded (override with
183
183
  `--allow-version-mismatch`).
184
184
 
185
+ ### Synthetic data: LLM configuration
186
+
187
+ `synth generate --llm` and `synth deploy` generate LLM-realistic values with
188
+ [gen3-metadata-simulator](https://github.com/AustralianBioCommons/gen3-metadata-simulator).
189
+ The provider and model resolve with precedence **CLI flags > SSM > default**:
190
+ the CDK config's optional `llm` block publishes `app/llm_provider` /
191
+ `app/llm_model` to SSM, so every operator gets the deployment's values, and
192
+ `--llm-provider` / `--llm-model` override them for one run (e.g. to try a
193
+ model before adding it to the CDK config). Environments deployed without the
194
+ block fall back to provider `anthropic`, and the `--llm` path errors with
195
+ guidance when no model is configured anywhere.
196
+
197
+ Only the API key stays local — as a *path* to the file holding it, never the
198
+ key itself, set once per operator:
199
+
200
+ ```bash
201
+ g3dt config set llm_api_key_file ~/.g3dt/anthropic_api_key
202
+ g3dt synth generate AusDiab_Simulated --llm -n 5 -e test
203
+ ```
204
+
205
+ (or per run with `--llm-api-key-file`; the vendor env var `ANTHROPIC_API_KEY`
206
+ / `OPENAI_API_KEY` also works as a fallback.) The old `~/.g3dt/.env`
207
+ (`LLM_PROVIDER`/`LLM_MODEL`/`LLM_API_KEY_FILE`) is **no longer read**.
208
+ `g3dt config show --env <env>` prints the resolved provider, model, and key
209
+ path.
210
+
185
211
  ## Verifying download access (check-download)
186
212
 
187
213
  Registration alone does not prove a file can be downloaded. Two failure modes
@@ -148,6 +148,32 @@ Synthetic data is only schema-valid against the dictionary that generated it, so
148
148
  refuses a batch that doesn't match the version being uploaded (override with
149
149
  `--allow-version-mismatch`).
150
150
 
151
+ ### Synthetic data: LLM configuration
152
+
153
+ `synth generate --llm` and `synth deploy` generate LLM-realistic values with
154
+ [gen3-metadata-simulator](https://github.com/AustralianBioCommons/gen3-metadata-simulator).
155
+ The provider and model resolve with precedence **CLI flags > SSM > default**:
156
+ the CDK config's optional `llm` block publishes `app/llm_provider` /
157
+ `app/llm_model` to SSM, so every operator gets the deployment's values, and
158
+ `--llm-provider` / `--llm-model` override them for one run (e.g. to try a
159
+ model before adding it to the CDK config). Environments deployed without the
160
+ block fall back to provider `anthropic`, and the `--llm` path errors with
161
+ guidance when no model is configured anywhere.
162
+
163
+ Only the API key stays local — as a *path* to the file holding it, never the
164
+ key itself, set once per operator:
165
+
166
+ ```bash
167
+ g3dt config set llm_api_key_file ~/.g3dt/anthropic_api_key
168
+ g3dt synth generate AusDiab_Simulated --llm -n 5 -e test
169
+ ```
170
+
171
+ (or per run with `--llm-api-key-file`; the vendor env var `ANTHROPIC_API_KEY`
172
+ / `OPENAI_API_KEY` also works as a fallback.) The old `~/.g3dt/.env`
173
+ (`LLM_PROVIDER`/`LLM_MODEL`/`LLM_API_KEY_FILE`) is **no longer read**.
174
+ `g3dt config show --env <env>` prints the resolved provider, model, and key
175
+ path.
176
+
151
177
  ## Verifying download access (check-download)
152
178
 
153
179
  Registration alone does not prove a file can be downloaded. Two failure modes
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "gen3-dataops-toolkit"
3
- version = "3.3.0"
3
+ version = "3.4.0"
4
4
  description = "Gen3 DataOps toolkit (g3dt): operate SSM-published Gen3 data pipeline environments"
5
5
  authors = ["JoshuaHarris391 <harjo391@gmail.com>"]
6
6
  readme = "README.md"
@@ -118,6 +118,11 @@ def show(
118
118
  typer.echo(f" namespace : {e.namespace}")
119
119
  typer.echo(f" cluster_name : {e.cluster_name}")
120
120
  typer.echo(f" ec2_instance_id : {e.ec2_instance_id}")
121
+ # Synthetic-data LLM facts: provider/model from SSM (the CDK's optional
122
+ # llm block); only the key *path* is local, from the marker.
123
+ typer.echo(f" llm_provider : {e.llm_provider}")
124
+ typer.echo(f" llm_model : {e.llm_model or '(not set — pass --llm-model or add the llm block to the CDK config)'}")
125
+ typer.echo(f" llm_api_key_file : {config.llm_api_key_file() or '(not set — g3dt config set llm_api_key_file <path>)'}")
121
126
  if study:
122
127
  s = study_of(study, env)
123
128
  typer.secho(f"Study: {study} -> {s.key}", bold=True)
@@ -199,6 +204,20 @@ def diff(
199
204
  check(f"gen3.{camel}", gen3.get(camel), rc.get(f"app/{leaf}"))
200
205
  check("toolkitVersion", inputs.get("toolkitVersion"), rc.get("meta/toolkitVersion"))
201
206
 
207
+ # Optional inputs: compared only when the file defines them — an absent
208
+ # input legitimately publishes no SSM parameter (or, for the dictionary
209
+ # fields, predates their addition), so absence on both sides is not drift.
210
+ for camel, leaf in {
211
+ "dictionaryBaseUrl": "dictionary_base_url",
212
+ "dictionaryPath": "dictionary_path",
213
+ }.items():
214
+ if camel in gen3:
215
+ check(f"gen3.{camel}", gen3.get(camel), rc.get(f"app/{leaf}"))
216
+ llm = inputs.get("llm") or {}
217
+ for camel, leaf in {"provider": "llm_provider", "model": "llm_model"}.items():
218
+ if camel in llm:
219
+ check(f"llm.{camel}", llm.get(camel), rc.get(f"app/{leaf}"))
220
+
202
221
  if not drift:
203
222
  typer.secho(
204
223
  f"No drift: SSM /{project}/{config.env_base(env)} matches {file}.",
@@ -9,9 +9,14 @@ Every command accepts ``--env``; targeting a **production** environment (any env
9
9
  whose name contains ``prod``) shows a warning and requires typing the env name to
10
10
  confirm — it cannot be bypassed.
11
11
 
12
- Generation defaults to keyless ``random`` data (no API calls). Pass ``--llm`` for
13
- LLM-realistic values, which needs an API key configured in a ``.env`` in the
14
- working directory (``LLM_PROVIDER`` / ``LLM_MODEL`` / ``LLM_API_KEY_FILE``).
12
+ Generation defaults to keyless ``random`` data (no API calls). Pass ``--llm``
13
+ for LLM-realistic values. The LLM provider and model come from the
14
+ environment's SSM tree (the CDK config's optional ``llm`` block, published as
15
+ ``app/llm_provider`` / ``app/llm_model``) and can be overridden per run with
16
+ ``--llm-provider`` / ``--llm-model``. Only the API key stays local: point at
17
+ its file once with ``g3dt config set llm_api_key_file <path>`` (or per run
18
+ with ``--llm-api-key-file``); the vendor env var ``ANTHROPIC_API_KEY`` /
19
+ ``OPENAI_API_KEY`` also works. The old ``~/.g3dt/.env`` is no longer read.
15
20
  """
16
21
  from __future__ import annotations
17
22
 
@@ -21,6 +26,7 @@ from typing import Optional
21
26
 
22
27
  import typer
23
28
 
29
+ from g3dt import config
24
30
  from g3dt.config import (
25
31
  dictionary_filename,
26
32
  dictionary_url,
@@ -38,6 +44,45 @@ app = typer.Typer(
38
44
 
39
45
  SYNTH_DIR = Path("~/.g3dt/synth_metadata").expanduser()
40
46
 
47
+
48
+ def _llm_env_overrides(
49
+ e,
50
+ llm_provider: Optional[str],
51
+ llm_model: Optional[str],
52
+ llm_api_key_file: Optional[Path],
53
+ ) -> dict:
54
+ """Resolve the effective LLM settings for a run: flags > SSM > default.
55
+
56
+ Returns env-var overrides for the generator script, which forwards
57
+ provider/model to gen3-metadata-simulator as CLI flags (the simulator's
58
+ own precedence puts flags first). Exits with guidance when no model is
59
+ configured anywhere; the key-file path is optional — the simulator falls
60
+ back to the vendor env var and raises its own error if neither exists.
61
+ """
62
+ effective_provider = llm_provider or e.llm_provider
63
+ effective_model = llm_model or e.llm_model
64
+ if not effective_model:
65
+ typer.secho(
66
+ "No LLM model configured. Set the llm block in the CDK config "
67
+ "(published to SSM as app/llm_model) and redeploy, or pass "
68
+ "--llm-model for this run.",
69
+ fg=typer.colors.RED,
70
+ err=True,
71
+ )
72
+ raise typer.Exit(1)
73
+ overrides = {
74
+ "G3DT_LLM_PROVIDER": effective_provider,
75
+ "G3DT_LLM_MODEL": effective_model,
76
+ }
77
+ key_file = (
78
+ str(Path(llm_api_key_file).expanduser())
79
+ if llm_api_key_file
80
+ else config.llm_api_key_file()
81
+ )
82
+ if key_file:
83
+ overrides["LLM_API_KEY_FILE"] = key_file
84
+ return overrides
85
+
41
86
  #: Written into each generated batch so `synth upload` can tell which dictionary
42
87
  #: produced it. A batch is only valid against that dictionary, and the directory
43
88
  #: name alone cannot be trusted: --schema and --version are separate options, so
@@ -110,19 +155,35 @@ def deploy(
110
155
  env: str = typer.Option(
111
156
  "test", "--env", "-e", help="Target environment (prod requires typed confirmation)."
112
157
  ),
158
+ llm_provider: Optional[str] = typer.Option(
159
+ None, "--llm-provider",
160
+ help="LLM vendor override (anthropic|openai); default: the env's SSM app/llm_provider.",
161
+ ),
162
+ llm_model: Optional[str] = typer.Option(
163
+ None, "--llm-model",
164
+ help="LLM model override; default: the env's SSM app/llm_model.",
165
+ ),
166
+ llm_api_key_file: Optional[Path] = typer.Option(
167
+ None, "--llm-api-key-file", exists=True, dir_okay=False,
168
+ help="Path to the file holding the LLM API key; default: the marker's "
169
+ "llm_api_key_file (set once: g3dt config set llm_api_key_file <path>).",
170
+ ),
113
171
  ) -> None:
114
172
  """Full end-to-end synthetic deploy (dict + LLM-generate + upload + restarts).
115
173
 
116
174
  Wraps services/synthetic_data/full_deploy_dd_and_synth.sh (LLM-backed
117
- generation). Requires an LLM key configured in .env.
175
+ generation). Provider/model come from the env's SSM tree unless
176
+ overridden; the API key path comes from --llm-api-key-file or the marker.
118
177
  """
119
178
  e = env_of(env)
120
179
  safety.confirm_prod_strict("synthetic full deploy", env)
180
+ env_vars = script_env(e)
181
+ env_vars.update(_llm_env_overrides(e, llm_provider, llm_model, llm_api_key_file))
121
182
  runner.run(
122
183
  runner.bash_script(
123
184
  "services/synthetic_data/full_deploy_dd_and_synth.sh", env
124
185
  ),
125
- env=script_env(e),
186
+ env=env_vars,
126
187
  )
127
188
 
128
189
 
@@ -147,8 +208,22 @@ def generate(
147
208
  llm: bool = typer.Option(
148
209
  False,
149
210
  "--llm",
150
- help="Generate LLM-realistic values; reads LLM config from a .env in the "
151
- "working directory. Default is keyless random data (no API key, no API calls).",
211
+ help="Generate LLM-realistic values; provider/model resolve from the "
212
+ "env's SSM tree (override with --llm-provider/--llm-model). Default is "
213
+ "keyless random data (no API key, no API calls).",
214
+ ),
215
+ llm_provider: Optional[str] = typer.Option(
216
+ None, "--llm-provider",
217
+ help="LLM vendor override (anthropic|openai); default: the env's SSM app/llm_provider.",
218
+ ),
219
+ llm_model: Optional[str] = typer.Option(
220
+ None, "--llm-model",
221
+ help="LLM model override; default: the env's SSM app/llm_model.",
222
+ ),
223
+ llm_api_key_file: Optional[Path] = typer.Option(
224
+ None, "--llm-api-key-file", exists=True, dir_okay=False,
225
+ help="Path to the file holding the LLM API key; default: the marker's "
226
+ "llm_api_key_file (set once: g3dt config set llm_api_key_file <path>).",
152
227
  ),
153
228
  seed: int = typer.Option(None, "--seed", help="RNG seed for reproducible output."),
154
229
  schema: str = typer.Option(
@@ -227,11 +302,16 @@ def generate(
227
302
  args += ["--num-records", num_records]
228
303
  if seed is not None:
229
304
  args += ["--seed", str(seed)]
305
+ env_vars = script_env(e, ver)
306
+ if effective_provider == "llm":
307
+ env_vars.update(
308
+ _llm_env_overrides(e, llm_provider, llm_model, llm_api_key_file)
309
+ )
230
310
  runner.run(
231
311
  runner.bash_script(
232
312
  "services/synthetic_data/generate_synth_metadata.sh", *args
233
313
  ),
234
- env=script_env(e, ver),
314
+ env=env_vars,
235
315
  )
236
316
  # Only after a successful generate: runner.run raises on failure, so a
237
317
  # half-written batch is never stamped as valid.
@@ -50,11 +50,21 @@ DEFAULT_REGION = "ap-southeast-2"
50
50
  DEFAULT_DICT_BASE_URL = "https://raw.githubusercontent.com"
51
51
  DEFAULT_DICT_PATH = "dictionary/prod_dict/acdc_schema.json"
52
52
 
53
+ #: Synthetic-data LLM facts, published by the CDK's OPTIONAL ``llm`` config
54
+ #: block as ``app/llm_provider`` / ``app/llm_model`` and consumed by
55
+ #: gen3-metadata-simulator through ``g3dt synth``. Optional app inputs:
56
+ #: environments deployed without the block fall back to this provider default.
57
+ #: The model deliberately has no default — ``g3dt synth`` errors with guidance
58
+ #: when the ``--llm`` path is used and no model is configured anywhere.
59
+ DEFAULT_LLM_PROVIDER = "anthropic"
60
+
53
61
  #: Marker locations, most specific first.
54
62
  MARKER_PATHS = ("g3dt.yaml", "~/.g3dt/g3dt.yaml", "/etc/g3dt/g3dt.yaml")
55
63
 
56
- #: Marker keys `g3dt config set` may write.
57
- SETTABLE_MARKER_KEYS = ("project", "region", "default_env")
64
+ #: Marker keys `g3dt config set` may write. ``llm_api_key_file`` is the path
65
+ #: to the file holding the synth LLM API key — the one LLM setting that stays
66
+ #: local (the provider and model come from SSM; the key never leaves the box).
67
+ SETTABLE_MARKER_KEYS = ("project", "region", "default_env", "llm_api_key_file")
58
68
 
59
69
  #: Gen3 app facts mirrored to SSM /{project}/{env}/app/* by the CDK.
60
70
  REQUIRED_APP_KEYS = (
@@ -150,6 +160,18 @@ def require_project(marker: Optional[dict] = None) -> str:
150
160
  return project
151
161
 
152
162
 
163
+ def llm_api_key_file(marker: Optional[dict] = None) -> Optional[str]:
164
+ """Path to the file holding the synth LLM API key, from the marker.
165
+
166
+ Set once per operator with ``g3dt config set llm_api_key_file <path>``.
167
+ Returns ``None`` when unset — gen3-metadata-simulator then falls back to
168
+ the vendor's standard env var (``ANTHROPIC_API_KEY`` / ``OPENAI_API_KEY``).
169
+ """
170
+ m = marker if marker is not None else load_marker()
171
+ value = m.get("llm_api_key_file")
172
+ return str(Path(str(value)).expanduser()) if value else None
173
+
174
+
153
175
  def set_marker_value(key: str, value: str) -> Tuple[Optional[str], str, Path]:
154
176
  """Set one bootstrap key in the user's marker file and write it back.
155
177
 
@@ -230,6 +252,11 @@ class EnvConfig:
230
252
  # hand-built EnvConfig still composes a valid URL.
231
253
  dictionary_base_url: str = DEFAULT_DICT_BASE_URL
232
254
  dictionary_path: str = DEFAULT_DICT_PATH
255
+ # Optional synthetic-data LLM inputs (SSM app/llm_provider, app/llm_model).
256
+ # The model has no default on purpose: synth's --llm path checks and errors
257
+ # with guidance rather than silently picking a model.
258
+ llm_provider: str = DEFAULT_LLM_PROVIDER
259
+ llm_model: Optional[str] = None
233
260
 
234
261
 
235
262
  def _app_or_default(rc, leaf: str, default: str) -> str:
@@ -289,6 +316,10 @@ def resolve_env(env: str, project: Optional[str] = None) -> EnvConfig:
289
316
  rc, "dictionary_base_url", DEFAULT_DICT_BASE_URL
290
317
  ),
291
318
  dictionary_path=_app_or_default(rc, "dictionary_path", DEFAULT_DICT_PATH),
319
+ # Same optional-app-fact contract: the CDK publishes these only when
320
+ # the config has an llm block, so absence means "use the defaults".
321
+ llm_provider=_app_or_default(rc, "llm_provider", DEFAULT_LLM_PROVIDER),
322
+ llm_model=(_app_or_default(rc, "llm_model", "") or None),
292
323
  )
293
324
 
294
325
 
@@ -395,6 +426,8 @@ def script_env(e: EnvConfig, version: Optional[str] = None) -> Dict[str, str]:
395
426
  "G3DT_NAMESPACE": e.namespace,
396
427
  "G3DT_CLUSTER_NAME": e.cluster_name,
397
428
  "G3DT_SCHEMA_REPO": e.schema_repo,
429
+ "G3DT_LLM_PROVIDER": e.llm_provider,
430
+ "G3DT_LLM_MODEL": e.llm_model,
398
431
  }
399
432
  env.update({k: v for k, v in values.items() if v is not None})
400
433
  return env
@@ -8,14 +8,13 @@
8
8
  # The tool takes a LOCAL bundled Gen3 schema file (pulled by pull_dict.sh into
9
9
  # ~/.g3dt/schemas/acdc_schema_<version>.json, or $G3DT_SCHEMA_DIR if set). The
10
10
  # default provider is keyless 'random'; pass --provider llm for LLM-realistic
11
- # values, in which case LLM config is read from ~/.g3dt/.env (or $G3DT_ENV_FILE
12
- # if set): LLM_PROVIDER / LLM_MODEL / LLM_API_KEY_FILE.
11
+ # values. The LLM vendor/model arrive as $G3DT_LLM_PROVIDER / $G3DT_LLM_MODEL
12
+ # (resolved by g3dt: CLI flags > SSM app/llm_* > default) and are forwarded to
13
+ # the simulator as flags; the API key file path arrives as $LLM_API_KEY_FILE.
14
+ # The old ~/.g3dt/.env is no longer read.
13
15
 
14
16
  set -euo pipefail
15
17
 
16
- # LLM provider config file (lives outside the installed package).
17
- ENV_FILE="${G3DT_ENV_FILE:-$HOME/.g3dt/.env}"
18
-
19
18
  usage() {
20
19
  cat <<EOF
21
20
  Usage: $(basename "$0") --schema <path> --version <ver> [options]
@@ -32,8 +31,8 @@ Options:
32
31
  --num-records N|n1,n2 Records per study: one number for all, or a comma list
33
32
  (one per study). Default: ${DEFAULT_NUM_RECORDS}
34
33
  --provider random|llm Value strategy. Default: ${DEFAULT_PROVIDER}
35
- 'random' needs no key; 'llm' reads LLM config from
36
- ${ENV_FILE}.
34
+ 'random' needs no key; 'llm' uses \$G3DT_LLM_PROVIDER /
35
+ \$G3DT_LLM_MODEL / \$LLM_API_KEY_FILE (set by g3dt).
37
36
  --seed N RNG seed for reproducible output.
38
37
  --output-root DIR Root output dir. Default: ${DEFAULT_OUTPUT_ROOT}
39
38
  -h, --help Show this help and exit.
@@ -123,9 +122,16 @@ for i in "${!STUDY_ARRAY[@]}"; do
123
122
  --num-records "$N"
124
123
  --provider "$PROVIDER")
125
124
  [[ -n "$SEED" ]] && CMD+=(--seed "$SEED")
126
- # Point the LLM provider at the user-level env file regardless of the caller's CWD.
127
- if [[ "$PROVIDER" == "llm" && -f "${ENV_FILE}" ]]; then
128
- CMD+=(--env-file "${ENV_FILE}")
125
+ if [[ "$PROVIDER" == "llm" ]]; then
126
+ # Vendor/model resolved by g3dt (flags > SSM > default) and forwarded
127
+ # as simulator flags, because the simulator's own precedence puts
128
+ # flags above any .env or environment variable.
129
+ [[ -n "${G3DT_LLM_PROVIDER:-}" ]] && CMD+=(--llm-provider "$G3DT_LLM_PROVIDER")
130
+ [[ -n "${G3DT_LLM_MODEL:-}" ]] && CMD+=(--llm-model "$G3DT_LLM_MODEL")
131
+ # Neutralize any .env in the caller's CWD: /dev/null exists (satisfies
132
+ # the simulator's exists=True check) and dotenv-parses to empty, so
133
+ # only the flags above and the inherited $LLM_API_KEY_FILE apply.
134
+ CMD+=(--env-file /dev/null)
129
135
  fi
130
136
  "${CMD[@]}"
131
137
  done