metergraph-core 0.4.0__tar.gz → 0.5.1__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 (24) hide show
  1. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/PKG-INFO +69 -25
  2. metergraph_core-0.4.0/src/metergraph_core.egg-info/PKG-INFO → metergraph_core-0.5.1/README.md +49 -35
  3. metergraph_core-0.5.1/pyproject.toml +62 -0
  4. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/__init__.py +2 -2
  5. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/catalog.py +1 -0
  6. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/catalog_delta.py +212 -17
  7. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/data/prices.yaml +6198 -3
  8. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/data/sources.yaml +20 -0
  9. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/extractors.py +375 -1
  10. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/refresh.py +340 -5
  11. metergraph_core-0.4.0/README.md → metergraph_core-0.5.1/src/metergraph_core.egg-info/PKG-INFO +79 -23
  12. metergraph_core-0.4.0/pyproject.toml +0 -23
  13. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/MANIFEST.in +0 -0
  14. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/setup.cfg +0 -0
  15. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/billing.py +0 -0
  16. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/data/models.yaml +0 -0
  17. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/loader.py +0 -0
  18. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/models.py +0 -0
  19. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/retrieval.py +0 -0
  20. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core/sources.py +0 -0
  21. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core.egg-info/SOURCES.txt +0 -0
  22. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core.egg-info/dependency_links.txt +0 -0
  23. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core.egg-info/requires.txt +0 -0
  24. {metergraph_core-0.4.0 → metergraph_core-0.5.1}/src/metergraph_core.egg-info/top_level.txt +0 -0
@@ -1,8 +1,26 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metergraph-core
3
- Version: 0.4.0
4
- Summary: Reusable MeterGraph catalog and deterministic billing engine
3
+ Version: 0.5.1
4
+ Summary: Open, effective-dated LLM pricing catalog and deterministic cost calculator for popular models across major providers and gateways, including OpenAI, Anthropic, Google Gemini, AWS Bedrock, OpenRouter, Vercel AI Gateway, and more.
5
+ Author: Metergraph
5
6
  License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/metergraph/metergraph
8
+ Project-URL: Documentation, https://github.com/metergraph/metergraph/tree/main/core#readme
9
+ Project-URL: Source, https://github.com/metergraph/metergraph/tree/main/core
10
+ Project-URL: Issues, https://github.com/metergraph/metergraph/issues
11
+ Project-URL: Release notes, https://github.com/metergraph/metergraph/releases
12
+ Keywords: llm,pricing,cost,token-pricing,model-catalog,llm-pricing,model-pricing,token-cost,cost-calculation,openai,anthropic,gemini,bedrock,openrouter,vercel-ai-gateway,finops
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
6
24
  Requires-Python: >=3.10
7
25
  Description-Content-Type: text/markdown
8
26
  Requires-Dist: pyyaml>=6.0
@@ -12,22 +30,9 @@ Requires-Dist: pytest>=8; extra == "dev"
12
30
 
13
31
  # metergraph-core
14
32
 
15
- Reusable model registry, price catalog, and deterministic billing engine for
16
- MeterGraph.
17
-
18
- `metergraph-core` owns two separate public datasets. `models.yaml` records
19
- canonical model identity, customer-facing names, executable provider routes,
20
- and the ordered candidate fields MeterGraph products offer. `prices.yaml`
21
- records effective-dated rates and billing rules. Core parses and validates both
22
- datasets, resolves provider aliases and routes, calculates deterministic costs,
23
- and selects a qualified gateway-reported charge or catalog estimate as the
24
- effective call cost. A third dataset, `sources.yaml`, registers the official
25
- pricing sources that keep `prices.yaml` current; see
26
- [Source registry](#source-registry).
27
-
28
- It does not own HTTP routes, database access, migrations, authentication,
29
- tenancy, ingest, dashboard code, or any hosted-only concern, and it never reads
30
- server environment variables.
33
+ Calculate the cost of an LLM call from its model, provider, tokens, region, and
34
+ date. `metergraph-core` ships an open, effective-dated model pricing catalog and
35
+ a deterministic Python cost engine.
31
36
 
32
37
  ## Install
33
38
 
@@ -53,6 +58,32 @@ result = catalog.snapshot.cost(
53
58
  print(result.canonical_model, result.price_id, result.cost_usd, result.status)
54
59
  ```
55
60
 
61
+ The result names the canonical model and the catalog price row it was billed
62
+ at, so every cost traces back to an effective-dated rate.
63
+
64
+ ## Package scope
65
+
66
+ `metergraph-core` is the reusable model registry, price catalog, and
67
+ deterministic billing engine for
68
+ [Metergraph](https://github.com/metergraph/metergraph), which attributes LLM
69
+ cost to the function, agent, and workflow that made each call.
70
+
71
+ It owns two separate public datasets. `models.yaml` records
72
+ canonical model identity, customer-facing names, executable provider routes,
73
+ and the ordered candidate fields MeterGraph products offer. `prices.yaml`
74
+ records effective-dated rates and billing rules. Core parses and validates both
75
+ datasets, resolves provider aliases and routes, calculates deterministic costs,
76
+ and selects a qualified gateway-reported charge or catalog estimate as the
77
+ effective call cost. A third dataset, `sources.yaml`, registers the official
78
+ pricing sources that keep `prices.yaml` current; see
79
+ [Source registry](#source-registry).
80
+
81
+ It does not own HTTP routes, database access, migrations, authentication,
82
+ tenancy, ingest, dashboard code, or any hosted-only concern, and it never reads
83
+ server environment variables.
84
+
85
+ ## Loading catalogs
86
+
56
87
  `load_catalog()` loads the catalog bundled in the installed package. Pass an
57
88
  explicit `path` for tests or a self-hosted catalog replacement. The returned
58
89
  `LoadedCatalog` exposes the declared catalog `version`, the SHA-256
@@ -229,7 +260,7 @@ A pricing delta proposes changes to a catalog's price rows. It is a change
229
260
  artifact to review and apply, never a catalog to serve.
230
261
 
231
262
  ```yaml
232
- schema_version: 1
263
+ schema_version: 2
233
264
  kind: pricing_delta
234
265
  provenance:
235
266
  observations: [openai-api-pricing@2026-10-20]
@@ -326,12 +357,12 @@ only the labels, headers and key paths that parser relies on, so a price change
326
357
  or a newly listed model keeps the fingerprint and a format change alters it.
327
358
  Extractors never fetch. The package adds no browser or LLM dependency.
328
359
 
329
- ## Refresh and discovery scripts
360
+ ## Pricing maintenance scripts
330
361
 
331
- Two repository scripts run the registry against live sources. Neither holds
332
- credentials, applies a delta, writes the catalog, publishes, or touches GitHub.
362
+ The repository scripts run the registry against live sources without credentials
363
+ or GitHub access.
333
364
 
334
- Neither ever emits, stores or redistributes raw fetched page content. Their
365
+ The fetch-capable scripts never emit, store or redistribute raw page content. Their
335
366
  reports and evidence files hold only structural fingerprints, normalized
336
367
  extracted values (row labels as slugs, parsed amounts, numeric candidates),
337
368
  candidates, operations and short non-verbatim diagnostics. No output may name
@@ -354,7 +385,7 @@ an escalation, and 1 on error.
354
385
  behind a refresh report's escalations (`--escalations`), and new-source content
355
386
  from a file or stdin (`--new-source`, never a URL). It prints evidence for each:
356
387
  candidate and prior values, the reason for review, normalized page facts, and a
357
- proposed delta for changed catalog rows. An optional adapter
388
+ proposed delta for supported catalog changes. An optional adapter
358
389
  (`--llm-adapter module:callable`) is called as
359
390
  `propose(source, content, current_rows)` and returns delta operations. Its
360
391
  output is kept as review evidence only after it passes schema validation and
@@ -362,7 +393,20 @@ encodes as strict JSON. Adapter failures and rejected items are reported with
362
393
  stable codes, never with the adapter's own text. Everything discovery emits
363
394
  requires review.
364
395
 
365
- Both read `<source-id>.*` files from `--content-dir` instead of fetching. The
396
+ For structured gateway feeds, discovery also proposes `add_model` and
397
+ `add_alias` operations when an exact model identity is safe to extend. Free,
398
+ conditional, tiered, regional and unsupported-charge rows remain exclusions.
399
+ After review, `scripts/apply_price_delta.py --reviewed` writes additive operations
400
+ to a new catalog path while preserving existing comments. It rejects in-place
401
+ writes and history-changing operations, then verifies the rendered catalog
402
+ against the pure delta result.
403
+
404
+ Apply overlapping gateway sources sequentially. Run discovery for the next
405
+ source against the prior candidate so a shared new model becomes an alias and
406
+ price on one canonical entry instead of a conflicting second `add_model`.
407
+
408
+ The fetch-capable scripts read `<source-id>.*` files from `--content-dir` instead
409
+ of fetching. The
366
410
  tests use one synthetic fixture per low-risk source, plus OpenAI's, in
367
411
  `tests/fixtures/sources/`, reproducing only the structure its parser reads;
368
412
  the generic discovery parsers are tested on small inline synthetic pages.
@@ -1,33 +1,8 @@
1
- Metadata-Version: 2.4
2
- Name: metergraph-core
3
- Version: 0.4.0
4
- Summary: Reusable MeterGraph catalog and deterministic billing engine
5
- License-Expression: Apache-2.0
6
- Requires-Python: >=3.10
7
- Description-Content-Type: text/markdown
8
- Requires-Dist: pyyaml>=6.0
9
- Provides-Extra: dev
10
- Requires-Dist: build>=1.2; extra == "dev"
11
- Requires-Dist: pytest>=8; extra == "dev"
12
-
13
1
  # metergraph-core
14
2
 
15
- Reusable model registry, price catalog, and deterministic billing engine for
16
- MeterGraph.
17
-
18
- `metergraph-core` owns two separate public datasets. `models.yaml` records
19
- canonical model identity, customer-facing names, executable provider routes,
20
- and the ordered candidate fields MeterGraph products offer. `prices.yaml`
21
- records effective-dated rates and billing rules. Core parses and validates both
22
- datasets, resolves provider aliases and routes, calculates deterministic costs,
23
- and selects a qualified gateway-reported charge or catalog estimate as the
24
- effective call cost. A third dataset, `sources.yaml`, registers the official
25
- pricing sources that keep `prices.yaml` current; see
26
- [Source registry](#source-registry).
27
-
28
- It does not own HTTP routes, database access, migrations, authentication,
29
- tenancy, ingest, dashboard code, or any hosted-only concern, and it never reads
30
- server environment variables.
3
+ Calculate the cost of an LLM call from its model, provider, tokens, region, and
4
+ date. `metergraph-core` ships an open, effective-dated model pricing catalog and
5
+ a deterministic Python cost engine.
31
6
 
32
7
  ## Install
33
8
 
@@ -53,6 +28,32 @@ result = catalog.snapshot.cost(
53
28
  print(result.canonical_model, result.price_id, result.cost_usd, result.status)
54
29
  ```
55
30
 
31
+ The result names the canonical model and the catalog price row it was billed
32
+ at, so every cost traces back to an effective-dated rate.
33
+
34
+ ## Package scope
35
+
36
+ `metergraph-core` is the reusable model registry, price catalog, and
37
+ deterministic billing engine for
38
+ [Metergraph](https://github.com/metergraph/metergraph), which attributes LLM
39
+ cost to the function, agent, and workflow that made each call.
40
+
41
+ It owns two separate public datasets. `models.yaml` records
42
+ canonical model identity, customer-facing names, executable provider routes,
43
+ and the ordered candidate fields MeterGraph products offer. `prices.yaml`
44
+ records effective-dated rates and billing rules. Core parses and validates both
45
+ datasets, resolves provider aliases and routes, calculates deterministic costs,
46
+ and selects a qualified gateway-reported charge or catalog estimate as the
47
+ effective call cost. A third dataset, `sources.yaml`, registers the official
48
+ pricing sources that keep `prices.yaml` current; see
49
+ [Source registry](#source-registry).
50
+
51
+ It does not own HTTP routes, database access, migrations, authentication,
52
+ tenancy, ingest, dashboard code, or any hosted-only concern, and it never reads
53
+ server environment variables.
54
+
55
+ ## Loading catalogs
56
+
56
57
  `load_catalog()` loads the catalog bundled in the installed package. Pass an
57
58
  explicit `path` for tests or a self-hosted catalog replacement. The returned
58
59
  `LoadedCatalog` exposes the declared catalog `version`, the SHA-256
@@ -229,7 +230,7 @@ A pricing delta proposes changes to a catalog's price rows. It is a change
229
230
  artifact to review and apply, never a catalog to serve.
230
231
 
231
232
  ```yaml
232
- schema_version: 1
233
+ schema_version: 2
233
234
  kind: pricing_delta
234
235
  provenance:
235
236
  observations: [openai-api-pricing@2026-10-20]
@@ -326,12 +327,12 @@ only the labels, headers and key paths that parser relies on, so a price change
326
327
  or a newly listed model keeps the fingerprint and a format change alters it.
327
328
  Extractors never fetch. The package adds no browser or LLM dependency.
328
329
 
329
- ## Refresh and discovery scripts
330
+ ## Pricing maintenance scripts
330
331
 
331
- Two repository scripts run the registry against live sources. Neither holds
332
- credentials, applies a delta, writes the catalog, publishes, or touches GitHub.
332
+ The repository scripts run the registry against live sources without credentials
333
+ or GitHub access.
333
334
 
334
- Neither ever emits, stores or redistributes raw fetched page content. Their
335
+ The fetch-capable scripts never emit, store or redistribute raw page content. Their
335
336
  reports and evidence files hold only structural fingerprints, normalized
336
337
  extracted values (row labels as slugs, parsed amounts, numeric candidates),
337
338
  candidates, operations and short non-verbatim diagnostics. No output may name
@@ -354,7 +355,7 @@ an escalation, and 1 on error.
354
355
  behind a refresh report's escalations (`--escalations`), and new-source content
355
356
  from a file or stdin (`--new-source`, never a URL). It prints evidence for each:
356
357
  candidate and prior values, the reason for review, normalized page facts, and a
357
- proposed delta for changed catalog rows. An optional adapter
358
+ proposed delta for supported catalog changes. An optional adapter
358
359
  (`--llm-adapter module:callable`) is called as
359
360
  `propose(source, content, current_rows)` and returns delta operations. Its
360
361
  output is kept as review evidence only after it passes schema validation and
@@ -362,7 +363,20 @@ encodes as strict JSON. Adapter failures and rejected items are reported with
362
363
  stable codes, never with the adapter's own text. Everything discovery emits
363
364
  requires review.
364
365
 
365
- Both read `<source-id>.*` files from `--content-dir` instead of fetching. The
366
+ For structured gateway feeds, discovery also proposes `add_model` and
367
+ `add_alias` operations when an exact model identity is safe to extend. Free,
368
+ conditional, tiered, regional and unsupported-charge rows remain exclusions.
369
+ After review, `scripts/apply_price_delta.py --reviewed` writes additive operations
370
+ to a new catalog path while preserving existing comments. It rejects in-place
371
+ writes and history-changing operations, then verifies the rendered catalog
372
+ against the pure delta result.
373
+
374
+ Apply overlapping gateway sources sequentially. Run discovery for the next
375
+ source against the prior candidate so a shared new model becomes an alias and
376
+ price on one canonical entry instead of a conflicting second `add_model`.
377
+
378
+ The fetch-capable scripts read `<source-id>.*` files from `--content-dir` instead
379
+ of fetching. The
366
380
  tests use one synthetic fixture per low-risk source, plus OpenAI's, in
367
381
  `tests/fixtures/sources/`, reproducing only the structure its parser reads;
368
382
  the generic discovery parsers are tested on small inline synthetic pages.
@@ -0,0 +1,62 @@
1
+ [project]
2
+ name = "metergraph-core"
3
+ version = "0.5.1"
4
+ description = "Open, effective-dated LLM pricing catalog and deterministic cost calculator for popular models across major providers and gateways, including OpenAI, Anthropic, Google Gemini, AWS Bedrock, OpenRouter, Vercel AI Gateway, and more."
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ authors = [{ name = "Metergraph" }]
8
+ requires-python = ">=3.10"
9
+ keywords = [
10
+ "llm",
11
+ "pricing",
12
+ "cost",
13
+ "token-pricing",
14
+ "model-catalog",
15
+ "llm-pricing",
16
+ "model-pricing",
17
+ "token-cost",
18
+ "cost-calculation",
19
+ "openai",
20
+ "anthropic",
21
+ "gemini",
22
+ "bedrock",
23
+ "openrouter",
24
+ "vercel-ai-gateway",
25
+ "finops",
26
+ ]
27
+ classifiers = [
28
+ "Development Status :: 4 - Beta",
29
+ "Intended Audience :: Developers",
30
+ "Operating System :: OS Independent",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3 :: Only",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Programming Language :: Python :: 3.12",
36
+ "Programming Language :: Python :: 3.13",
37
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
38
+ "Topic :: Software Development :: Libraries :: Python Modules",
39
+ ]
40
+ dependencies = [
41
+ "pyyaml>=6.0",
42
+ ]
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/metergraph/metergraph"
46
+ Documentation = "https://github.com/metergraph/metergraph/tree/main/core#readme"
47
+ Source = "https://github.com/metergraph/metergraph/tree/main/core"
48
+ Issues = "https://github.com/metergraph/metergraph/issues"
49
+ "Release notes" = "https://github.com/metergraph/metergraph/releases"
50
+
51
+ [project.optional-dependencies]
52
+ dev = ["build>=1.2", "pytest>=8"]
53
+
54
+ [build-system]
55
+ requires = ["setuptools>=68"]
56
+ build-backend = "setuptools.build_meta"
57
+
58
+ [tool.setuptools.packages.find]
59
+ where = ["src"]
60
+
61
+ [tool.setuptools.package-data]
62
+ metergraph_core = ["data/models.yaml", "data/prices.yaml", "data/sources.yaml"]
@@ -50,7 +50,7 @@ from .retrieval import (
50
50
  RetrievalPrice,
51
51
  )
52
52
  from .catalog_delta import (
53
- PRICING_DELTA_SCHEMA_VERSION,
53
+ CATALOG_DELTA_SCHEMA_VERSION,
54
54
  CatalogDelta,
55
55
  CatalogDeltaConflict,
56
56
  CatalogDeltaError,
@@ -85,6 +85,7 @@ from .sources import (
85
85
 
86
86
  __all__ = [
87
87
  "CatalogDelta",
88
+ "CATALOG_DELTA_SCHEMA_VERSION",
88
89
  "CatalogDeltaConflict",
89
90
  "CatalogDeltaError",
90
91
  "DeltaConflict",
@@ -93,7 +94,6 @@ __all__ = [
93
94
  "Extraction",
94
95
  "LowRiskPolicy",
95
96
  "Observation",
96
- "PRICING_DELTA_SCHEMA_VERSION",
97
97
  "PriceRowKey",
98
98
  "PriceSource",
99
99
  "RefreshResult",
@@ -30,6 +30,7 @@ _DIRECT_CHANNEL_BY_PROVIDER = {
30
30
  "openai": "openai-api",
31
31
  "google": "google-api",
32
32
  "vercel": "vercel-ai-gateway",
33
+ "openrouter": "openrouter-api",
33
34
  "vertex-ai": "google-vertex-ai",
34
35
  "fireworks": "fireworks-api",
35
36
  "bedrock": "aws-bedrock",