parseforge 0.2.10__tar.gz → 0.3.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 (63) hide show
  1. {parseforge-0.2.10/parseforge.egg-info → parseforge-0.3.0}/PKG-INFO +121 -37
  2. {parseforge-0.2.10 → parseforge-0.3.0}/README.md +93 -20
  3. {parseforge-0.2.10 → parseforge-0.3.0}/SPEC.md +2 -2
  4. parseforge-0.3.0/parseforge/__init__.py +96 -0
  5. parseforge-0.3.0/parseforge/api.py +127 -0
  6. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/cli/config.py +50 -4
  7. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/cli/main.py +302 -19
  8. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/generation.py +0 -2
  9. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/__init__.py +6 -0
  10. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/llm.py +0 -1
  11. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/__init__.py +6 -0
  12. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/anthropic.py +1 -11
  13. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/azure.py +1 -16
  14. parseforge-0.3.0/parseforge/naming/providers/bedrock.py +166 -0
  15. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/cerebras.py +1 -11
  16. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/cohere.py +1 -11
  17. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/deepseek.py +1 -11
  18. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/fireworks.py +1 -11
  19. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/gemini.py +1 -11
  20. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/groq.py +1 -11
  21. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/mistral.py +1 -11
  22. parseforge-0.3.0/parseforge/naming/providers/models.py +17 -0
  23. parseforge-0.3.0/parseforge/naming/providers/models.yaml +30 -0
  24. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/moonshot.py +1 -11
  25. parseforge-0.3.0/parseforge/naming/providers/oci.py +200 -0
  26. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/openai.py +1 -11
  27. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/openrouter.py +1 -11
  28. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/perplexity.py +1 -11
  29. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/together.py +1 -11
  30. parseforge-0.3.0/parseforge/naming/providers/vertexai.py +181 -0
  31. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/xai.py +1 -11
  32. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/pipeline.py +60 -4
  33. {parseforge-0.2.10 → parseforge-0.3.0/parseforge.egg-info}/PKG-INFO +121 -37
  34. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge.egg-info/SOURCES.txt +4 -1
  35. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge.egg-info/requires.txt +30 -16
  36. {parseforge-0.2.10 → parseforge-0.3.0}/pyproject.toml +46 -21
  37. parseforge-0.2.10/parseforge/__init__.py +0 -1
  38. parseforge-0.2.10/parseforge/naming/providers/cost.py +0 -29
  39. parseforge-0.2.10/parseforge/naming/providers/models.py +0 -26
  40. parseforge-0.2.10/parseforge/naming/providers/models.yaml +0 -143
  41. {parseforge-0.2.10 → parseforge-0.3.0}/LICENSE +0 -0
  42. {parseforge-0.2.10 → parseforge-0.3.0}/MANIFEST.in +0 -0
  43. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/cli/__init__.py +0 -0
  44. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/drift.py +0 -0
  45. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/integration.py +0 -0
  46. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/assemble.py +0 -0
  47. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/cache.py +0 -0
  48. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/prompts.py +0 -0
  49. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/prompts.yaml +0 -0
  50. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/errors.py +0 -0
  51. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/providers/text.py +0 -0
  52. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/naming/resolver.py +0 -0
  53. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/paths.py +0 -0
  54. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/promotion.py +0 -0
  55. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/sampling/__init__.py +0 -0
  56. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/sampling/backends/__init__.py +0 -0
  57. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/sampling/backends/netmiko.py +0 -0
  58. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/sampling/core.py +0 -0
  59. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge/validation.py +0 -0
  60. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge.egg-info/dependency_links.txt +0 -0
  61. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge.egg-info/entry_points.txt +0 -0
  62. {parseforge-0.2.10 → parseforge-0.3.0}/parseforge.egg-info/top_level.txt +0 -0
  63. {parseforge-0.2.10 → parseforge-0.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: parseforge
3
- Version: 0.2.10
3
+ Version: 0.3.0
4
4
  Summary: LLM-driven pipeline that forges, validates, and promotes TextFSM templates from network CLI output
5
5
  Author-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
6
6
  Maintainer-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
@@ -26,52 +26,61 @@ License-File: LICENSE
26
26
  Requires-Dist: click>=8.1
27
27
  Requires-Dist: PyYAML>=6.0
28
28
  Requires-Dist: textfsm>=1.1.0
29
- Requires-Dist: textfsm-ai>=0.6.1
29
+ Requires-Dist: textfsm-ai>=0.7.1
30
30
  Provides-Extra: anthropic
31
31
  Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
32
- Requires-Dist: textfsm-ai[anthropic]>=0.6.1; extra == "anthropic"
32
+ Requires-Dist: textfsm-ai[anthropic]>=0.7.1; extra == "anthropic"
33
33
  Provides-Extra: deepseek
34
34
  Requires-Dist: openai>=1.0.0; extra == "deepseek"
35
- Requires-Dist: textfsm-ai[deepseek]>=0.6.1; extra == "deepseek"
35
+ Requires-Dist: textfsm-ai[deepseek]>=0.7.1; extra == "deepseek"
36
36
  Provides-Extra: openai
37
37
  Requires-Dist: openai>=1.0.0; extra == "openai"
38
- Requires-Dist: textfsm-ai[openai]>=0.6.1; extra == "openai"
38
+ Requires-Dist: textfsm-ai[openai]>=0.7.1; extra == "openai"
39
39
  Provides-Extra: groq
40
40
  Requires-Dist: openai>=1.0.0; extra == "groq"
41
- Requires-Dist: textfsm-ai[groq]>=0.6.1; extra == "groq"
41
+ Requires-Dist: textfsm-ai[groq]>=0.7.1; extra == "groq"
42
42
  Provides-Extra: xai
43
43
  Requires-Dist: openai>=1.0.0; extra == "xai"
44
- Requires-Dist: textfsm-ai[xai]>=0.6.1; extra == "xai"
44
+ Requires-Dist: textfsm-ai[xai]>=0.7.1; extra == "xai"
45
45
  Provides-Extra: together
46
46
  Requires-Dist: openai>=1.0.0; extra == "together"
47
- Requires-Dist: textfsm-ai[together]>=0.6.1; extra == "together"
47
+ Requires-Dist: textfsm-ai[together]>=0.7.1; extra == "together"
48
48
  Provides-Extra: fireworks
49
49
  Requires-Dist: openai>=1.0.0; extra == "fireworks"
50
- Requires-Dist: textfsm-ai[fireworks]>=0.6.1; extra == "fireworks"
50
+ Requires-Dist: textfsm-ai[fireworks]>=0.7.1; extra == "fireworks"
51
51
  Provides-Extra: perplexity
52
52
  Requires-Dist: openai>=1.0.0; extra == "perplexity"
53
- Requires-Dist: textfsm-ai[perplexity]>=0.6.1; extra == "perplexity"
53
+ Requires-Dist: textfsm-ai[perplexity]>=0.7.1; extra == "perplexity"
54
54
  Provides-Extra: openrouter
55
55
  Requires-Dist: openai>=1.0.0; extra == "openrouter"
56
- Requires-Dist: textfsm-ai[openrouter]>=0.6.1; extra == "openrouter"
56
+ Requires-Dist: textfsm-ai[openrouter]>=0.7.1; extra == "openrouter"
57
57
  Provides-Extra: moonshot
58
58
  Requires-Dist: openai>=1.0.0; extra == "moonshot"
59
- Requires-Dist: textfsm-ai[moonshot]>=0.6.1; extra == "moonshot"
59
+ Requires-Dist: textfsm-ai[moonshot]>=0.7.1; extra == "moonshot"
60
60
  Provides-Extra: cerebras
61
61
  Requires-Dist: openai>=1.0.0; extra == "cerebras"
62
- Requires-Dist: textfsm-ai[cerebras]>=0.6.1; extra == "cerebras"
62
+ Requires-Dist: textfsm-ai[cerebras]>=0.7.1; extra == "cerebras"
63
63
  Provides-Extra: mistral
64
64
  Requires-Dist: mistralai==1.10.0; extra == "mistral"
65
- Requires-Dist: textfsm-ai[mistral]>=0.6.1; extra == "mistral"
65
+ Requires-Dist: textfsm-ai[mistral]>=0.7.1; extra == "mistral"
66
66
  Provides-Extra: cohere
67
67
  Requires-Dist: cohere==5.21.1; extra == "cohere"
68
- Requires-Dist: textfsm-ai[cohere]>=0.6.1; extra == "cohere"
68
+ Requires-Dist: textfsm-ai[cohere]>=0.7.1; extra == "cohere"
69
69
  Provides-Extra: azure
70
70
  Requires-Dist: azure-ai-inference>=1.0.0b9; extra == "azure"
71
- Requires-Dist: textfsm-ai[azure]>=0.6.1; extra == "azure"
71
+ Requires-Dist: textfsm-ai[azure]>=0.7.1; extra == "azure"
72
72
  Provides-Extra: gemini
73
73
  Requires-Dist: google-genai>=0.2.0; extra == "gemini"
74
- Requires-Dist: textfsm-ai[gemini]>=0.6.1; extra == "gemini"
74
+ Requires-Dist: textfsm-ai[gemini]>=0.7.1; extra == "gemini"
75
+ Provides-Extra: vertexai
76
+ Requires-Dist: google-genai>=0.2.0; extra == "vertexai"
77
+ Requires-Dist: textfsm-ai[vertexai]>=0.7.1; extra == "vertexai"
78
+ Provides-Extra: bedrock
79
+ Requires-Dist: boto3==1.42.97; extra == "bedrock"
80
+ Requires-Dist: textfsm-ai[bedrock]>=0.7.1; extra == "bedrock"
81
+ Provides-Extra: oci
82
+ Requires-Dist: oci==2.182.0; extra == "oci"
83
+ Requires-Dist: textfsm-ai[oci]>=0.7.1; extra == "oci"
75
84
  Provides-Extra: sampling
76
85
  Requires-Dist: netmiko>=4.0; extra == "sampling"
77
86
  Provides-Extra: dev
@@ -86,6 +95,8 @@ Requires-Dist: mistralai==1.10.0; extra == "dev"
86
95
  Requires-Dist: cohere==5.21.1; extra == "dev"
87
96
  Requires-Dist: azure-ai-inference>=1.0.0b9; extra == "dev"
88
97
  Requires-Dist: google-genai>=0.2.0; extra == "dev"
98
+ Requires-Dist: boto3==1.42.97; extra == "dev"
99
+ Requires-Dist: oci==2.182.0; extra == "dev"
89
100
  Provides-Extra: release
90
101
  Requires-Dist: bump2version; extra == "release"
91
102
  Requires-Dist: build; extra == "release"
@@ -128,11 +139,12 @@ command that's pure local processing (`canonical`/`readable`/`recognizers`,
128
139
  LLM (`name`, `check --provider`, `run`, `generate-template`, `trial`) needs the
129
140
  extra for whichever provider it uses: `anthropic`, `openai`, `deepseek`,
130
141
  `groq`, `xai`, `together`, `fireworks`, `perplexity`, `openrouter`,
131
- `moonshot`, `cerebras`, `mistral`, `cohere`, `azure`, or `gemini`.
132
- `--provider` defaults to `anthropic` wherever it isn't required, so that's
133
- the one most setups need. `pip install parseforge[sampling]` adds Netmiko
134
- for live device sampling; combine extras as needed, e.g.
135
- `pip install parseforge[anthropic,openai,deepseek,groq,xai,together,fireworks,perplexity,openrouter,moonshot,cerebras,mistral,cohere,azure,gemini,sampling]`.
142
+ `moonshot`, `cerebras`, `mistral`, `cohere`, `azure`, `gemini`, `vertexai`,
143
+ `bedrock`, or `oci`. `--provider` defaults to `anthropic` wherever it isn't
144
+ required, so that's the one most setups need. `pip install
145
+ parseforge[sampling]` adds Netmiko for live device sampling; combine
146
+ extras as needed, e.g.
147
+ `pip install parseforge[anthropic,openai,deepseek,groq,xai,together,fireworks,perplexity,openrouter,moonshot,cerebras,mistral,cohere,azure,gemini,vertexai,bedrock,oci,sampling]`.
136
148
 
137
149
  ## Development
138
150
 
@@ -141,12 +153,26 @@ pip install -e ".[dev,sampling]"
141
153
  pytest
142
154
  ```
143
155
  `dev` already includes the `anthropic`, `openai`, `mistralai`, `cohere`,
144
- `azure-ai-inference`, and `google-genai` SDKs (tests exercise all fifteen
145
- providers — `anthropic`, `openai`, `deepseek`, `groq`, `xai`, `together`,
146
- `fireworks`, `perplexity`, `openrouter`, `moonshot`, `cerebras` share just
147
- the first two packages, and `mistral`/`cohere`/`azure`/`gemini` each need
148
- their own SDK and never silently skip)add the specific `,<provider>`
149
- extra explicitly only if installing outside of `dev`.
156
+ `azure-ai-inference`, `google-genai`, `boto3`, and `oci` SDKs (tests exercise
157
+ all eighteen providers — `anthropic`, `openai`, `deepseek`, `groq`, `xai`,
158
+ `together`, `fireworks`, `perplexity`, `openrouter`, `moonshot`, `cerebras`
159
+ share just the first two packages, `mistral`/`cohere`/`azure`/`bedrock`/`oci`
160
+ each need their own SDK, and `gemini`/`vertexai` share `google-genai`and
161
+ never silently skip) add the specific `,<provider>` extra explicitly only
162
+ if installing outside of `dev`.
163
+
164
+ For tooling that expects plain `requirements.txt` files instead of pip
165
+ extras (Docker layers, offline pins, etc), `requirements/` has one
166
+ `requirements-<provider>.txt` per provider whose SDK isn't already
167
+ pinned by a shared package (`anthropic`/`openai`/`azure`/`bedrock`/`oci`/
168
+ `cohere`/`mistral`/`gemini`/`vertexai`) — each mirrors the matching
169
+ `pyproject.toml` extra exactly (`-e .` plus that provider's SDK pin), so
170
+ `pip install -r requirements/requirements-oci.txt` is equivalent to
171
+ `pip install -e ".[oci]"`. To also run that provider's tests, use the
172
+ matching `dev-<provider>.txt` instead — it layers `pytest`/`pytest-cov`
173
+ on top via `-r requirements-<provider>.txt`, so cloning the repo and
174
+ running `pip install -r requirements/dev-oci.txt` is enough on its own,
175
+ no separate install step needed.
150
176
 
151
177
  Linting/formatting/type-checking/docs run through tox instead of extras — see
152
178
  `tox.ini` (`tox -e lint`/`format`/`typecheck`/`docs`), each installing its own
@@ -171,11 +197,23 @@ and `--api-key` falls back to that provider's own env var (`ANTHROPIC_API_KEY`/
171
197
  `OPENAI_API_KEY`/`DEEPSEEK_API_KEY`/etc.). A cache hit (a command already seen
172
198
  before) never touches the LLM, so no key is needed at all in that case.
173
199
 
174
- `--provider azure` is the one exception to the usual `--api-key`/`--model` shape —
175
- Azure has no fixed base_url or model catalog, so it also needs `--endpoint`
200
+ `--provider azure`/`--provider vertexai`/`--provider bedrock`/`--provider oci`
201
+ are the four exceptions to the usual `--api-key`/`--model` shape. Azure has
202
+ no fixed base_url or model catalog, so it also needs `--endpoint`
176
203
  (`AZURE_ENDPOINT`), `--api-version` (`AZURE_API_VERSION`), and `--deployment`
177
- (`AZURE_DEPLOYMENT`, replacing `--model`). Same three options exist on
178
- `check --provider`, `run`, and `generate-template` below.
204
+ (`AZURE_DEPLOYMENT`, replacing `--model`). Vertex AI has no API key at all —
205
+ it authenticates via GCP's own Application Default Credentials — so
206
+ `--api-key`/`AZURE_API_KEY`-style env vars don't apply; it needs
207
+ `--gcp-project` (`VERTEXAI_PROJECT`) and `--gcp-location` (`VERTEXAI_REGION`)
208
+ instead. Bedrock likewise has no API key at all — it authenticates via AWS's
209
+ own credential chain — and just needs `--region` (`BEDROCK_REGION`, then
210
+ `BEDROCK_DEFAULT_REGION`). OCI also has no API key at all — it signs each
211
+ request cryptographically against local credentials in `~/.oci/config`
212
+ (DEFAULT profile) — and needs both `--region` (`OCI_REGION`, then whatever
213
+ region is already set in `~/.oci/config`) and `--compartment-id`
214
+ (`OCI_COMPARTMENT_ID`, the OCID of the compartment/tenancy to bill and scope
215
+ requests to). Same options exist on `check --provider`, `run`, and
216
+ `generate-template` below.
179
217
 
180
218
  **`check`** — validate a connector or provider before spending time/tokens on a real
181
219
  run. With neither `--env` nor explicit connection flags, prints what a connector needs
@@ -216,14 +254,21 @@ parseforge run --vendor cisco --family catalyst9200 --os ios-xe --version 17.9.1
216
254
  --model claude-haiku-4-5-20251001 \
217
255
  show clock
218
256
  ```
219
- `--provider`/`--api-key`/`--model` are for generation. Naming has its own separate
257
+ `--provider`/`--api-key`/`--model` are for generation (`--api-key` isn't
258
+ required for `--provider vertexai`/`--provider bedrock`/`--provider oci`).
259
+ Naming has its own separate
220
260
  `--naming-provider`/`--naming-api-key`/`--naming-model`, defaulting independently
221
261
  (`--naming-provider` defaults to `anthropic`; the other two fall back to that
222
262
  provider's own env var/default model) — set them explicitly if naming needs a
223
263
  different provider than generation. `--provider azure`/`--naming-provider azure`
224
264
  each get their own `--endpoint`/`--api-version`/`--deployment` (generation) and
225
- `--naming-endpoint`/`--naming-api-version`/`--naming-deployment` (naming) — see
226
- the `name` section above for what they're for.
265
+ `--naming-endpoint`/`--naming-api-version`/`--naming-deployment` (naming);
266
+ `--provider vertexai`/`--naming-provider vertexai` similarly get
267
+ `--gcp-project`/`--gcp-location` and `--naming-gcp-project`/
268
+ `--naming-gcp-location`; `--provider bedrock`/`--naming-provider bedrock` get
269
+ `--region` and `--naming-region`; `--provider oci`/`--naming-provider oci` get
270
+ `--region`/`--compartment-id` and `--naming-region`/`--naming-compartment-id`
271
+ — see the `name` section above for what they're for.
227
272
 
228
273
  **`init-trial-config`** — write a placeholder `trial.yaml` to fill in, instead of
229
274
  writing one by hand:
@@ -257,8 +302,15 @@ workers: 1
257
302
  `provider`/`api_key`/`model` are one shared LLM source used for both naming and
258
303
  generation. Use the `run` command's separate `--naming-*`/`--generation-*` flags
259
304
  instead if a trial actually needs two different providers. For `provider: azure`,
260
- also set `endpoint`/`api_version`/`deployment` (`deployment` replaces `model`)
261
- see `parseforge init-trial-config`'s generated placeholder for the exact keys.
305
+ also set `endpoint`/`api_version`/`deployment` (`deployment` replaces `model`).
306
+ For `provider: vertexai`, set `project`/`location` instead `api_key` can be
307
+ omitted entirely (Vertex AI authenticates via GCP's own Application Default
308
+ Credentials). For `provider: bedrock`, set `region` instead — `api_key` can
309
+ likewise be omitted entirely (Bedrock authenticates via AWS's own credential
310
+ chain). For `provider: oci`, set `region`/`compartment_id` instead —
311
+ `api_key` can likewise be omitted entirely (OCI authenticates via local
312
+ request-signing credentials in `~/.oci/config`). See
313
+ `parseforge init-trial-config`'s generated placeholder for the exact keys.
262
314
 
263
315
  **`integration`** — rebuild `integration/` for every case under `trials/` (SPEC §5
264
316
  step 8):
@@ -294,6 +346,38 @@ evaluating any gate — so running `promotion` alone after a `trial` run is enou
294
346
  pick up new evidence; a separate `integration` run is only useful if you want to
295
347
  inspect `reference-summary.json` without also promoting.
296
348
 
349
+ ## Python API
350
+
351
+ Everything the CLI does is also a plain Python call — `parseforge/api.py` is the
352
+ single supported place to import from (also re-exported at the package root):
353
+
354
+ ```python
355
+ from parseforge import CliContext, LLMProviderConfig, run_command_pipeline
356
+ from parseforge.naming import AnthropicRegexBuilder
357
+ from parseforge.sampling.backends import NetmikoSampler
358
+ from parseforge.sampling import DeviceConnection
359
+
360
+ result = run_command_pipeline(
361
+ "show clock",
362
+ CliContext(vendor="cisco", family="catalyst9200", os="ios-xe", version="17.9.1"),
363
+ DeviceConnection(host="10.0.0.1", username="admin", password="secret", device_type="cisco_ios"),
364
+ AnthropicRegexBuilder(api_key="sk-..."),
365
+ NetmikoSampler(),
366
+ LLMProviderConfig(provider="anthropic", api_key="sk-...", model="claude-haiku-4-5-20251001"),
367
+ )
368
+ print(result.cli_name, result.passed, result.total_usage)
369
+ ```
370
+
371
+ One function per pipeline stage (SPEC.md §5): `cli_name`/`resolve_cli_name` (naming),
372
+ `sample` (sampling), `generate` (generation), `parse` (self-validation),
373
+ `run_command_pipeline` (steps 1-7 in one call), `build_integration`/
374
+ `write_reference_summary` (integration), `promote_auto`/`promote_user_reviewed`
375
+ (promotion), `check_drift` (drift monitoring) — plus the dataclasses/enums each one
376
+ returns or accepts. Provider-specific naming builders (`AnthropicRegexBuilder`,
377
+ `OCIRegexBuilder`, ...) aren't re-exported at the root — import them from
378
+ `parseforge.naming` directly. Anything not in `parseforge.api.__all__` is internal
379
+ and may change without notice.
380
+
297
381
  ## Reference
298
382
 
299
383
  - [Documentation site](https://geeks-trident-llc.github.io/parseforge/) ([source](./docs/index.md))
@@ -35,11 +35,12 @@ command that's pure local processing (`canonical`/`readable`/`recognizers`,
35
35
  LLM (`name`, `check --provider`, `run`, `generate-template`, `trial`) needs the
36
36
  extra for whichever provider it uses: `anthropic`, `openai`, `deepseek`,
37
37
  `groq`, `xai`, `together`, `fireworks`, `perplexity`, `openrouter`,
38
- `moonshot`, `cerebras`, `mistral`, `cohere`, `azure`, or `gemini`.
39
- `--provider` defaults to `anthropic` wherever it isn't required, so that's
40
- the one most setups need. `pip install parseforge[sampling]` adds Netmiko
41
- for live device sampling; combine extras as needed, e.g.
42
- `pip install parseforge[anthropic,openai,deepseek,groq,xai,together,fireworks,perplexity,openrouter,moonshot,cerebras,mistral,cohere,azure,gemini,sampling]`.
38
+ `moonshot`, `cerebras`, `mistral`, `cohere`, `azure`, `gemini`, `vertexai`,
39
+ `bedrock`, or `oci`. `--provider` defaults to `anthropic` wherever it isn't
40
+ required, so that's the one most setups need. `pip install
41
+ parseforge[sampling]` adds Netmiko for live device sampling; combine
42
+ extras as needed, e.g.
43
+ `pip install parseforge[anthropic,openai,deepseek,groq,xai,together,fireworks,perplexity,openrouter,moonshot,cerebras,mistral,cohere,azure,gemini,vertexai,bedrock,oci,sampling]`.
43
44
 
44
45
  ## Development
45
46
 
@@ -48,12 +49,26 @@ pip install -e ".[dev,sampling]"
48
49
  pytest
49
50
  ```
50
51
  `dev` already includes the `anthropic`, `openai`, `mistralai`, `cohere`,
51
- `azure-ai-inference`, and `google-genai` SDKs (tests exercise all fifteen
52
- providers — `anthropic`, `openai`, `deepseek`, `groq`, `xai`, `together`,
53
- `fireworks`, `perplexity`, `openrouter`, `moonshot`, `cerebras` share just
54
- the first two packages, and `mistral`/`cohere`/`azure`/`gemini` each need
55
- their own SDK and never silently skip)add the specific `,<provider>`
56
- extra explicitly only if installing outside of `dev`.
52
+ `azure-ai-inference`, `google-genai`, `boto3`, and `oci` SDKs (tests exercise
53
+ all eighteen providers — `anthropic`, `openai`, `deepseek`, `groq`, `xai`,
54
+ `together`, `fireworks`, `perplexity`, `openrouter`, `moonshot`, `cerebras`
55
+ share just the first two packages, `mistral`/`cohere`/`azure`/`bedrock`/`oci`
56
+ each need their own SDK, and `gemini`/`vertexai` share `google-genai`and
57
+ never silently skip) add the specific `,<provider>` extra explicitly only
58
+ if installing outside of `dev`.
59
+
60
+ For tooling that expects plain `requirements.txt` files instead of pip
61
+ extras (Docker layers, offline pins, etc), `requirements/` has one
62
+ `requirements-<provider>.txt` per provider whose SDK isn't already
63
+ pinned by a shared package (`anthropic`/`openai`/`azure`/`bedrock`/`oci`/
64
+ `cohere`/`mistral`/`gemini`/`vertexai`) — each mirrors the matching
65
+ `pyproject.toml` extra exactly (`-e .` plus that provider's SDK pin), so
66
+ `pip install -r requirements/requirements-oci.txt` is equivalent to
67
+ `pip install -e ".[oci]"`. To also run that provider's tests, use the
68
+ matching `dev-<provider>.txt` instead — it layers `pytest`/`pytest-cov`
69
+ on top via `-r requirements-<provider>.txt`, so cloning the repo and
70
+ running `pip install -r requirements/dev-oci.txt` is enough on its own,
71
+ no separate install step needed.
57
72
 
58
73
  Linting/formatting/type-checking/docs run through tox instead of extras — see
59
74
  `tox.ini` (`tox -e lint`/`format`/`typecheck`/`docs`), each installing its own
@@ -78,11 +93,23 @@ and `--api-key` falls back to that provider's own env var (`ANTHROPIC_API_KEY`/
78
93
  `OPENAI_API_KEY`/`DEEPSEEK_API_KEY`/etc.). A cache hit (a command already seen
79
94
  before) never touches the LLM, so no key is needed at all in that case.
80
95
 
81
- `--provider azure` is the one exception to the usual `--api-key`/`--model` shape —
82
- Azure has no fixed base_url or model catalog, so it also needs `--endpoint`
96
+ `--provider azure`/`--provider vertexai`/`--provider bedrock`/`--provider oci`
97
+ are the four exceptions to the usual `--api-key`/`--model` shape. Azure has
98
+ no fixed base_url or model catalog, so it also needs `--endpoint`
83
99
  (`AZURE_ENDPOINT`), `--api-version` (`AZURE_API_VERSION`), and `--deployment`
84
- (`AZURE_DEPLOYMENT`, replacing `--model`). Same three options exist on
85
- `check --provider`, `run`, and `generate-template` below.
100
+ (`AZURE_DEPLOYMENT`, replacing `--model`). Vertex AI has no API key at all —
101
+ it authenticates via GCP's own Application Default Credentials — so
102
+ `--api-key`/`AZURE_API_KEY`-style env vars don't apply; it needs
103
+ `--gcp-project` (`VERTEXAI_PROJECT`) and `--gcp-location` (`VERTEXAI_REGION`)
104
+ instead. Bedrock likewise has no API key at all — it authenticates via AWS's
105
+ own credential chain — and just needs `--region` (`BEDROCK_REGION`, then
106
+ `BEDROCK_DEFAULT_REGION`). OCI also has no API key at all — it signs each
107
+ request cryptographically against local credentials in `~/.oci/config`
108
+ (DEFAULT profile) — and needs both `--region` (`OCI_REGION`, then whatever
109
+ region is already set in `~/.oci/config`) and `--compartment-id`
110
+ (`OCI_COMPARTMENT_ID`, the OCID of the compartment/tenancy to bill and scope
111
+ requests to). Same options exist on `check --provider`, `run`, and
112
+ `generate-template` below.
86
113
 
87
114
  **`check`** — validate a connector or provider before spending time/tokens on a real
88
115
  run. With neither `--env` nor explicit connection flags, prints what a connector needs
@@ -123,14 +150,21 @@ parseforge run --vendor cisco --family catalyst9200 --os ios-xe --version 17.9.1
123
150
  --model claude-haiku-4-5-20251001 \
124
151
  show clock
125
152
  ```
126
- `--provider`/`--api-key`/`--model` are for generation. Naming has its own separate
153
+ `--provider`/`--api-key`/`--model` are for generation (`--api-key` isn't
154
+ required for `--provider vertexai`/`--provider bedrock`/`--provider oci`).
155
+ Naming has its own separate
127
156
  `--naming-provider`/`--naming-api-key`/`--naming-model`, defaulting independently
128
157
  (`--naming-provider` defaults to `anthropic`; the other two fall back to that
129
158
  provider's own env var/default model) — set them explicitly if naming needs a
130
159
  different provider than generation. `--provider azure`/`--naming-provider azure`
131
160
  each get their own `--endpoint`/`--api-version`/`--deployment` (generation) and
132
- `--naming-endpoint`/`--naming-api-version`/`--naming-deployment` (naming) — see
133
- the `name` section above for what they're for.
161
+ `--naming-endpoint`/`--naming-api-version`/`--naming-deployment` (naming);
162
+ `--provider vertexai`/`--naming-provider vertexai` similarly get
163
+ `--gcp-project`/`--gcp-location` and `--naming-gcp-project`/
164
+ `--naming-gcp-location`; `--provider bedrock`/`--naming-provider bedrock` get
165
+ `--region` and `--naming-region`; `--provider oci`/`--naming-provider oci` get
166
+ `--region`/`--compartment-id` and `--naming-region`/`--naming-compartment-id`
167
+ — see the `name` section above for what they're for.
134
168
 
135
169
  **`init-trial-config`** — write a placeholder `trial.yaml` to fill in, instead of
136
170
  writing one by hand:
@@ -164,8 +198,15 @@ workers: 1
164
198
  `provider`/`api_key`/`model` are one shared LLM source used for both naming and
165
199
  generation. Use the `run` command's separate `--naming-*`/`--generation-*` flags
166
200
  instead if a trial actually needs two different providers. For `provider: azure`,
167
- also set `endpoint`/`api_version`/`deployment` (`deployment` replaces `model`)
168
- see `parseforge init-trial-config`'s generated placeholder for the exact keys.
201
+ also set `endpoint`/`api_version`/`deployment` (`deployment` replaces `model`).
202
+ For `provider: vertexai`, set `project`/`location` instead `api_key` can be
203
+ omitted entirely (Vertex AI authenticates via GCP's own Application Default
204
+ Credentials). For `provider: bedrock`, set `region` instead — `api_key` can
205
+ likewise be omitted entirely (Bedrock authenticates via AWS's own credential
206
+ chain). For `provider: oci`, set `region`/`compartment_id` instead —
207
+ `api_key` can likewise be omitted entirely (OCI authenticates via local
208
+ request-signing credentials in `~/.oci/config`). See
209
+ `parseforge init-trial-config`'s generated placeholder for the exact keys.
169
210
 
170
211
  **`integration`** — rebuild `integration/` for every case under `trials/` (SPEC §5
171
212
  step 8):
@@ -201,6 +242,38 @@ evaluating any gate — so running `promotion` alone after a `trial` run is enou
201
242
  pick up new evidence; a separate `integration` run is only useful if you want to
202
243
  inspect `reference-summary.json` without also promoting.
203
244
 
245
+ ## Python API
246
+
247
+ Everything the CLI does is also a plain Python call — `parseforge/api.py` is the
248
+ single supported place to import from (also re-exported at the package root):
249
+
250
+ ```python
251
+ from parseforge import CliContext, LLMProviderConfig, run_command_pipeline
252
+ from parseforge.naming import AnthropicRegexBuilder
253
+ from parseforge.sampling.backends import NetmikoSampler
254
+ from parseforge.sampling import DeviceConnection
255
+
256
+ result = run_command_pipeline(
257
+ "show clock",
258
+ CliContext(vendor="cisco", family="catalyst9200", os="ios-xe", version="17.9.1"),
259
+ DeviceConnection(host="10.0.0.1", username="admin", password="secret", device_type="cisco_ios"),
260
+ AnthropicRegexBuilder(api_key="sk-..."),
261
+ NetmikoSampler(),
262
+ LLMProviderConfig(provider="anthropic", api_key="sk-...", model="claude-haiku-4-5-20251001"),
263
+ )
264
+ print(result.cli_name, result.passed, result.total_usage)
265
+ ```
266
+
267
+ One function per pipeline stage (SPEC.md §5): `cli_name`/`resolve_cli_name` (naming),
268
+ `sample` (sampling), `generate` (generation), `parse` (self-validation),
269
+ `run_command_pipeline` (steps 1-7 in one call), `build_integration`/
270
+ `write_reference_summary` (integration), `promote_auto`/`promote_user_reviewed`
271
+ (promotion), `check_drift` (drift monitoring) — plus the dataclasses/enums each one
272
+ returns or accepts. Provider-specific naming builders (`AnthropicRegexBuilder`,
273
+ `OCIRegexBuilder`, ...) aren't re-exported at the root — import them from
274
+ `parseforge.naming` directly. Anything not in `parseforge.api.__all__` is internal
275
+ and may change without notice.
276
+
204
277
  ## Reference
205
278
 
206
279
  - [Documentation site](https://geeks-trident-llc.github.io/parseforge/) ([source](./docs/index.md))
@@ -79,7 +79,7 @@ Keep the timestamp+shortid directories (not `result1..N`) — chronological orde
79
79
  | `derive/template.textfsm` | Cleaned, DSL-compiled TextFSM template candidate (`.textfsm` extension — recognized by TextFSM tooling/linters, unlike `textfsm.template`) |
80
80
  | `derive/readable-dsl.txt` | Human-readable description of what the template captures |
81
81
  | `derive/recognizers.txt` | Heuristics/signatures for detecting this output type at runtime |
82
- | `summary.json` | Everything else about the run: `created_at`/`ended_at`/`duration_ms`, `passed`, `error` (when `passed` is false), `metadata` (project/username/email/description), `command_info` (vendor/family/os/version/device_type/command), `usage` (naming + generation token counts/cost), and `provider_info` (the generation provider/model) |
82
+ | `summary.json` | Everything else about the run: `created_at`/`ended_at`/`duration_ms`, `passed`, `error` (when `passed` is false), `metadata` (project/username/email/description), `command_info` (vendor/family/os/version/device_type/command), `usage` (naming + generation token counts), and `provider_info` (the generation provider/model) |
83
83
 
84
84
  ### 3.2 `integration/` (no human review yet)
85
85
 
@@ -180,4 +180,4 @@ Where a fourth tier is tempting but better handled as **metadata instead of a ne
180
180
  - Do you want a **registry/index file** (e.g. `catalog.json`) at the repo root listing every `<vendor>/<family>/<os>/<cli-name>` combination that exists, plus its authoritative status, for fast lookup without walking the filesystem?
181
181
  - What **confidence threshold** (match-rate %, sample count minimum) should gate auto-promotion vs. human review in step 9 — worth making this configurable per-project rather than hardcoded?
182
182
  - Should `recognizers.txt` support **one-of-many matching** from day one (per the multi-variant note in §6), or is that a v2 concern?
183
- - What's the **LLM provider/model** for generation — worth pinning per-project so `summary.json`'s usage costs are comparable across runs?
183
+ - What's the **LLM provider/model** for generation — worth pinning per-project so `summary.json`'s token usage is comparable across runs?
@@ -0,0 +1,96 @@
1
+ __version__ = "0.3.0"
2
+ version = __version__
3
+
4
+ from .api import ( # noqa: E402
5
+ DEFAULT_STORE_ROOT,
6
+ CliContext,
7
+ DeviceConnection,
8
+ DeviceKey,
9
+ DriftCheckResult,
10
+ DriftGate,
11
+ GenerationResult,
12
+ GenerationTokenUsage,
13
+ GroupEvaluation,
14
+ LLMCLIResponse,
15
+ LLMProviderConfig,
16
+ Mode,
17
+ NamingResolution,
18
+ NamingTokenUsage,
19
+ ParseResult,
20
+ PromotionDecision,
21
+ PromotionGate,
22
+ PromotionMetadata,
23
+ PromotionMode,
24
+ PromotionRunResult,
25
+ Reference,
26
+ ReferenceGroup,
27
+ ReferenceVariant,
28
+ RegexBuilder,
29
+ Sampler,
30
+ TrialMetadata,
31
+ TrialResult,
32
+ UserReviewedRequest,
33
+ build_integration,
34
+ build_reference_summary,
35
+ check_drift,
36
+ cli_name,
37
+ decide_promotion,
38
+ discover_device_keys,
39
+ evaluate_cases,
40
+ generate,
41
+ parse,
42
+ promote_auto,
43
+ promote_user_reviewed,
44
+ resolve_cli_name,
45
+ run_command_pipeline,
46
+ sample,
47
+ write_reference_summary,
48
+ )
49
+
50
+ __all__ = [
51
+ "version",
52
+ "__version__",
53
+ "cli_name",
54
+ "resolve_cli_name",
55
+ "NamingResolution",
56
+ "CliContext",
57
+ "RegexBuilder",
58
+ "LLMCLIResponse",
59
+ "NamingTokenUsage",
60
+ "sample",
61
+ "DeviceConnection",
62
+ "Sampler",
63
+ "generate",
64
+ "GenerationResult",
65
+ "GenerationTokenUsage",
66
+ "parse",
67
+ "ParseResult",
68
+ "run_command_pipeline",
69
+ "LLMProviderConfig",
70
+ "TrialMetadata",
71
+ "TrialResult",
72
+ "Mode",
73
+ "build_integration",
74
+ "build_reference_summary",
75
+ "write_reference_summary",
76
+ "Reference",
77
+ "ReferenceGroup",
78
+ "ReferenceVariant",
79
+ "promote_auto",
80
+ "promote_user_reviewed",
81
+ "decide_promotion",
82
+ "evaluate_cases",
83
+ "PromotionGate",
84
+ "PromotionMetadata",
85
+ "UserReviewedRequest",
86
+ "GroupEvaluation",
87
+ "PromotionRunResult",
88
+ "PromotionDecision",
89
+ "PromotionMode",
90
+ "check_drift",
91
+ "DriftGate",
92
+ "DriftCheckResult",
93
+ "DEFAULT_STORE_ROOT",
94
+ "DeviceKey",
95
+ "discover_device_keys",
96
+ ]
@@ -0,0 +1,127 @@
1
+ """Public Python API — the single place to import parseforge's stable,
2
+ supported surface from. Mirrors textfsm-ai's own api.py convention
3
+ (https://github.com/Geeks-Trident-LLC/textfsm-ai): one entry point per
4
+ pipeline stage (SPEC.md §5), plus the types each one returns or accepts.
5
+
6
+ Provider-specific naming builders (``AnthropicRegexBuilder``,
7
+ ``OCIRegexBuilder``, ...) aren't re-exported here — they're already a
8
+ clean, documented import path via :mod:`parseforge.naming` directly, and
9
+ listing all eighteen here would bloat this module without adding
10
+ anything. Anything not listed in ``__all__`` (module-internal helpers,
11
+ provider implementation details, CLI plumbing) isn't part of the public
12
+ API and may change without notice.
13
+
14
+ ``naming``'s and ``generation``'s ``TokenUsage`` classes are separate
15
+ types that happen to share a name (naming makes one call per cache
16
+ miss; generation's is already accumulated across every LLM call in its
17
+ own pipeline, see ``GenerationResult.usage``) — aliased here as
18
+ ``NamingTokenUsage``/``GenerationTokenUsage`` to avoid the collision,
19
+ the same convention this package's own test suite already uses.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from .drift import DriftCheckResult, DriftGate, check_drift
25
+ from .generation import GenerationResult, generate
26
+ from .generation import TokenUsage as GenerationTokenUsage
27
+ from .integration import (
28
+ Reference,
29
+ ReferenceGroup,
30
+ ReferenceVariant,
31
+ build_integration,
32
+ build_reference_summary,
33
+ write_reference_summary,
34
+ )
35
+ from .naming import (
36
+ CliContext,
37
+ LLMCLIResponse,
38
+ NamingResolution,
39
+ RegexBuilder,
40
+ cli_name,
41
+ resolve_cli_name,
42
+ )
43
+ from .naming import TokenUsage as NamingTokenUsage
44
+ from .paths import DEFAULT_STORE_ROOT, DeviceKey, discover_device_keys
45
+ from .pipeline import (
46
+ LLMProviderConfig,
47
+ Mode,
48
+ TrialMetadata,
49
+ TrialResult,
50
+ run_command_pipeline,
51
+ )
52
+ from .promotion import (
53
+ GroupEvaluation,
54
+ PromotionDecision,
55
+ PromotionGate,
56
+ PromotionMetadata,
57
+ PromotionMode,
58
+ PromotionRunResult,
59
+ UserReviewedRequest,
60
+ decide_promotion,
61
+ evaluate_cases,
62
+ promote_auto,
63
+ promote_user_reviewed,
64
+ )
65
+ from .sampling import DeviceConnection, Sampler, sample
66
+ from .validation import ParseResult, parse
67
+
68
+ __all__ = [
69
+ # Naming (SPEC.md §2) — resolve a raw CLI command to its canonical
70
+ # cli-name, cached after the first LLM call.
71
+ "cli_name",
72
+ "resolve_cli_name",
73
+ "NamingResolution",
74
+ "CliContext",
75
+ "RegexBuilder",
76
+ "LLMCLIResponse",
77
+ "NamingTokenUsage",
78
+ # Sampling (SPEC.md §3) — capture raw command output from a device.
79
+ "sample",
80
+ "DeviceConnection",
81
+ "Sampler",
82
+ # Generation (SPEC.md §5 steps 5-6) — sample -> candidate TextFSM
83
+ # template, via textfsm-ai's delivery pipeline.
84
+ "generate",
85
+ "GenerationResult",
86
+ "GenerationTokenUsage",
87
+ # Validation (SPEC.md §5 step 7) — self-validate a template against
88
+ # its own sample.
89
+ "parse",
90
+ "ParseResult",
91
+ # Pipeline orchestration (SPEC.md §5) — one call runs steps 1-7
92
+ # (naming -> sampling -> generation -> validation) for a single trial.
93
+ "run_command_pipeline",
94
+ "LLMProviderConfig",
95
+ "TrialMetadata",
96
+ "TrialResult",
97
+ "Mode",
98
+ # Integration (SPEC.md §5 step 8) — cluster trials by output schema.
99
+ "build_integration",
100
+ "build_reference_summary",
101
+ "write_reference_summary",
102
+ "Reference",
103
+ "ReferenceGroup",
104
+ "ReferenceVariant",
105
+ # Promotion (SPEC.md §5 step 9) — auto-promote groups that clear
106
+ # their gate; queue everything else for human review.
107
+ "promote_auto",
108
+ "promote_user_reviewed",
109
+ "decide_promotion",
110
+ "evaluate_cases",
111
+ "PromotionGate",
112
+ "PromotionMetadata",
113
+ "UserReviewedRequest",
114
+ "GroupEvaluation",
115
+ "PromotionRunResult",
116
+ "PromotionDecision",
117
+ "PromotionMode",
118
+ # Drift monitoring (SPEC.md §5 step 11) — check an authoritative
119
+ # template against new production samples.
120
+ "check_drift",
121
+ "DriftGate",
122
+ "DriftCheckResult",
123
+ # Store-root layout helpers.
124
+ "DEFAULT_STORE_ROOT",
125
+ "DeviceKey",
126
+ "discover_device_keys",
127
+ ]