metergraph-core 0.2.54__tar.gz → 0.2.55__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.
- {metergraph_core-0.2.54/src/metergraph_core.egg-info → metergraph_core-0.2.55}/PKG-INFO +1 -1
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/pyproject.toml +1 -1
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/__init__.py +8 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/retrieval.py +93 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55/src/metergraph_core.egg-info}/PKG-INFO +1 -1
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/MANIFEST.in +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/README.md +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/setup.cfg +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/billing.py +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/catalog.py +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/data/models.yaml +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/data/prices.yaml +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/loader.py +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core/models.py +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core.egg-info/SOURCES.txt +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core.egg-info/dependency_links.txt +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core.egg-info/requires.txt +0 -0
- {metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core.egg-info/top_level.txt +0 -0
|
@@ -37,6 +37,10 @@ from .models import (
|
|
|
37
37
|
validate_model_registry,
|
|
38
38
|
)
|
|
39
39
|
from .retrieval import (
|
|
40
|
+
count_fetch_units,
|
|
41
|
+
count_search_units,
|
|
42
|
+
fetch_operation_for_channel,
|
|
43
|
+
search_operation_for_channel,
|
|
40
44
|
RetrievalCatalog,
|
|
41
45
|
RetrievalCostResult,
|
|
42
46
|
RetrievalPrice,
|
|
@@ -62,6 +66,8 @@ __all__ = [
|
|
|
62
66
|
"RetrievalCatalog",
|
|
63
67
|
"RetrievalCostResult",
|
|
64
68
|
"RetrievalPrice",
|
|
69
|
+
"count_fetch_units",
|
|
70
|
+
"count_search_units",
|
|
65
71
|
"counts_cache_read_in_input",
|
|
66
72
|
"direct_channel_for_provider",
|
|
67
73
|
"normalize_provider",
|
|
@@ -73,5 +79,7 @@ __all__ = [
|
|
|
73
79
|
"parse_disputes",
|
|
74
80
|
"parse_retrieval",
|
|
75
81
|
"resolve_billing",
|
|
82
|
+
"fetch_operation_for_channel",
|
|
83
|
+
"search_operation_for_channel",
|
|
76
84
|
"validate_model_registry",
|
|
77
85
|
]
|
|
@@ -15,6 +15,8 @@ count and an unknown operation or channel come back ``unpriced`` with a reason
|
|
|
15
15
|
from dataclasses import dataclass
|
|
16
16
|
from datetime import datetime, timezone
|
|
17
17
|
from decimal import Decimal, ROUND_HALF_UP
|
|
18
|
+
from collections.abc import Mapping
|
|
19
|
+
from types import MappingProxyType
|
|
18
20
|
from typing import Any
|
|
19
21
|
|
|
20
22
|
from .catalog import _COST_QUANTUM, _coerce_datetime
|
|
@@ -52,6 +54,97 @@ class RetrievalCostResult:
|
|
|
52
54
|
reasons: tuple[str, ...] = ()
|
|
53
55
|
|
|
54
56
|
|
|
57
|
+
# The retrieval operation a counted search or fetch is billed as on each
|
|
58
|
+
# channel. A channel absent here charges no per-use fee for that operation.
|
|
59
|
+
SEARCH_OPERATION_BY_CHANNEL: Mapping[str, str] = MappingProxyType({
|
|
60
|
+
"openai-api": "web_search",
|
|
61
|
+
"anthropic-api": "web_search",
|
|
62
|
+
"google-api": "google_search_grounding",
|
|
63
|
+
"google-vertex-ai": "google_search_grounding",
|
|
64
|
+
# Perplexity bills a request fee by search context size, which no
|
|
65
|
+
# capture path records; the low tier is the floor every request pays.
|
|
66
|
+
"perplexity-api": "search_request_low",
|
|
67
|
+
})
|
|
68
|
+
FETCH_OPERATION_BY_CHANNEL: Mapping[str, str] = MappingProxyType({
|
|
69
|
+
"anthropic-api": "web_fetch",
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
# The tool-call item types a provider emits for a search or a fetch it ran
|
|
73
|
+
# itself, as the Responses API and the relay record them.
|
|
74
|
+
_SEARCH_TOOL_TYPES = frozenset({"web_search_call"})
|
|
75
|
+
_FETCH_TOOL_TYPES = frozenset({"web_fetch_call"})
|
|
76
|
+
_PERPLEXITY = frozenset({"perplexity", "perplexity-ai"})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def search_operation_for_channel(channel: Any) -> str | None:
|
|
80
|
+
"""The retrieval operation a counted search is billed as on ``channel``,
|
|
81
|
+
or ``None`` where the channel charges no per-search fee."""
|
|
82
|
+
return SEARCH_OPERATION_BY_CHANNEL.get(str(channel or "").strip().lower())
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def fetch_operation_for_channel(channel: Any) -> str | None:
|
|
86
|
+
"""The retrieval operation a counted fetch is billed as on ``channel``,
|
|
87
|
+
or ``None`` where the channel charges no per-fetch fee."""
|
|
88
|
+
return FETCH_OPERATION_BY_CHANNEL.get(str(channel or "").strip().lower())
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _count(value: Any) -> int | None:
|
|
92
|
+
if value is None or isinstance(value, bool):
|
|
93
|
+
return None
|
|
94
|
+
try:
|
|
95
|
+
count = int(value)
|
|
96
|
+
except (TypeError, ValueError, OverflowError):
|
|
97
|
+
return None
|
|
98
|
+
return count if count >= 0 else None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _tool_items(row: Mapping[str, Any], types: frozenset[str]) -> int | None:
|
|
102
|
+
"""Items of the given types among ``tool_calls``: a measured zero when the
|
|
103
|
+
list is there and holds none, ``None`` when there is no list to read."""
|
|
104
|
+
calls = row.get("tool_calls")
|
|
105
|
+
if not isinstance(calls, list):
|
|
106
|
+
return None
|
|
107
|
+
return sum(
|
|
108
|
+
1
|
|
109
|
+
for call in calls
|
|
110
|
+
if isinstance(call, Mapping) and str(call.get("type") or "").strip().lower() in types
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def count_search_units(row: Mapping[str, Any]) -> int | None:
|
|
115
|
+
"""The searches one call row made, read from whichever field its capture
|
|
116
|
+
path carries, in the order they are believed: ``web_search_calls`` and
|
|
117
|
+
``grounding_queries`` (the relay's per-provider counts), Anthropic's
|
|
118
|
+
``server_tool_use.web_search_requests``, then the ``web_search_call``
|
|
119
|
+
items among ``tool_calls``. A Perplexity call is one search, since
|
|
120
|
+
Perplexity bills every request as one. A field that is present and says
|
|
121
|
+
nothing was searched is a measured zero; ``None`` means no field says."""
|
|
122
|
+
for key in ("web_search_calls", "grounding_queries"):
|
|
123
|
+
count = _count(row.get(key))
|
|
124
|
+
if count is not None:
|
|
125
|
+
return count
|
|
126
|
+
server = row.get("server_tool_use")
|
|
127
|
+
if isinstance(server, Mapping):
|
|
128
|
+
count = _count(server.get("web_search_requests"))
|
|
129
|
+
if count is not None:
|
|
130
|
+
return count
|
|
131
|
+
if str(row.get("provider") or "").strip().lower() in _PERPLEXITY:
|
|
132
|
+
return 1
|
|
133
|
+
return _tool_items(row, _SEARCH_TOOL_TYPES)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def count_fetch_units(row: Mapping[str, Any]) -> int | None:
|
|
137
|
+
"""The page fetches one call row made: Anthropic's
|
|
138
|
+
``server_tool_use.web_fetch_requests``, then the ``web_fetch_call``
|
|
139
|
+
items among ``tool_calls``, with the same measured-zero rule."""
|
|
140
|
+
server = row.get("server_tool_use")
|
|
141
|
+
if isinstance(server, Mapping):
|
|
142
|
+
count = _count(server.get("web_fetch_requests"))
|
|
143
|
+
if count is not None:
|
|
144
|
+
return count
|
|
145
|
+
return _tool_items(row, _FETCH_TOOL_TYPES)
|
|
146
|
+
|
|
147
|
+
|
|
55
148
|
def _units(value: Any) -> tuple[int | None, str | None]:
|
|
56
149
|
"""Coerce a retrieval unit count under a strict-integer contract.
|
|
57
150
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{metergraph_core-0.2.54 → metergraph_core-0.2.55}/src/metergraph_core.egg-info/top_level.txt
RENAMED
|
File without changes
|