xrtm-data 0.3.2__tar.gz → 0.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 (30) hide show
  1. {xrtm_data-0.3.2/src/xrtm_data.egg-info → xrtm_data-0.4.0}/PKG-INFO +2 -2
  2. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/README.md +1 -1
  3. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/pyproject.toml +1 -1
  4. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/__init__.py +4 -0
  5. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/core/schemas/__init__.py +4 -0
  6. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/core/schemas/forecast.py +63 -0
  7. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/version.py +1 -1
  8. {xrtm_data-0.3.2 → xrtm_data-0.4.0/src/xrtm_data.egg-info}/PKG-INFO +2 -2
  9. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/tests/test_schemas.py +63 -1
  10. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/LICENSE +0 -0
  11. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/setup.cfg +0 -0
  12. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/core/__init__.py +0 -0
  13. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/core/interfaces.py +0 -0
  14. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/core/schemas/prior.py +0 -0
  15. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/core/schemas/trade.py +0 -0
  16. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/corpora/__init__.py +0 -0
  17. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/corpora/_builtin_corpora.py +0 -0
  18. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/corpora/real_binary.py +0 -0
  19. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/corpora/registry.py +0 -0
  20. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/providers/__init__.py +0 -0
  21. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/providers/online/__init__.py +0 -0
  22. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/providers/online/metaculus.py +0 -0
  23. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm/data/providers/online/polymarket.py +0 -0
  24. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm_data.egg-info/SOURCES.txt +0 -0
  25. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm_data.egg-info/dependency_links.txt +0 -0
  26. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm_data.egg-info/requires.txt +0 -0
  27. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/src/xrtm_data.egg-info/top_level.txt +0 -0
  28. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/tests/test_corpus_registry.py +0 -0
  29. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/tests/test_prior_schemas.py +0 -0
  30. {xrtm_data-0.3.2 → xrtm_data-0.4.0}/tests/test_real_binary_corpus.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xrtm-data
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: The Snapshot Vault for XRTM.
5
5
  Author-email: XRTM Team <moy@xrtm.org>
6
6
  License-Expression: Apache-2.0
@@ -17,7 +17,7 @@ Requires-Dist: ruff>=0.1.0; extra == "dev"
17
17
  Requires-Dist: mypy>=1.0.0; extra == "dev"
18
18
  Dynamic: license-file
19
19
 
20
- # xrtm-data v0.3.0
20
+ # xrtm-data v0.4.0
21
21
 
22
22
  [![PyPI](https://img.shields.io/pypi/v/xrtm-data?style=flat-square)](https://pypi.org/project/xrtm-data/)
23
23
 
@@ -1,4 +1,4 @@
1
- # xrtm-data v0.3.0
1
+ # xrtm-data v0.4.0
2
2
 
3
3
  [![PyPI](https://img.shields.io/pypi/v/xrtm-data?style=flat-square)](https://pypi.org/project/xrtm-data/)
4
4
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "xrtm-data"
7
- version = "0.3.2"
7
+ version = "0.4.0"
8
8
  description = "The Snapshot Vault for XRTM."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.13"
@@ -39,11 +39,13 @@ from xrtm.data.core.schemas import (
39
39
  CausalNode,
40
40
  ConfidenceInterval,
41
41
  ForecastOutput,
42
+ ForecastProvenance,
42
43
  ForecastQuestion,
43
44
  ForecastRequest,
44
45
  ForecastResult,
45
46
  MetadataBase,
46
47
  ReasoningTrace,
48
+ TokenUsage,
47
49
  )
48
50
 
49
51
  __all__ = [
@@ -63,4 +65,6 @@ __all__ = [
63
65
  "CausalGraph",
64
66
  "ReasoningTrace",
65
67
  "ConfidenceInterval",
68
+ "TokenUsage",
69
+ "ForecastProvenance",
66
70
  ]
@@ -25,11 +25,13 @@ from xrtm.data.core.schemas.forecast import (
25
25
  CausalNode,
26
26
  ConfidenceInterval,
27
27
  ForecastOutput,
28
+ ForecastProvenance,
28
29
  ForecastQuestion,
29
30
  ForecastRequest,
30
31
  ForecastResult,
31
32
  MetadataBase,
32
33
  ReasoningTrace,
34
+ TokenUsage,
33
35
  )
34
36
  from xrtm.data.core.schemas.prior import BetaPrior, PriorState
35
37
  from xrtm.data.core.schemas.trade import TradeEvent, TradeWindow
@@ -46,6 +48,8 @@ __all__ = [
46
48
  "CausalGraph",
47
49
  "ReasoningTrace",
48
50
  "ConfidenceInterval",
51
+ "TokenUsage",
52
+ "ForecastProvenance",
49
53
  # Prior schemas
50
54
  "BetaPrior",
51
55
  "PriorState",
@@ -178,6 +178,57 @@ class ConfidenceInterval(BaseModel):
178
178
  level: float = Field(0.9, ge=0, le=1, description="Confidence level")
179
179
 
180
180
 
181
+ class TokenUsage(BaseModel):
182
+ r"""
183
+ Token accounting for a single forecast or inference run.
184
+
185
+ Attributes:
186
+ prompt_tokens: Total input tokens billed for this run.
187
+ completion_tokens: Total output tokens billed for this run.
188
+ cached_prompt_tokens: Input tokens served from a provider prefix cache.
189
+ reasoning_tokens: Output tokens spent on chain-of-thought reasoning.
190
+ total_tokens: Total billed tokens (prompt + completion).
191
+ """
192
+
193
+ prompt_tokens: int = Field(default=0, ge=0, description="Total input tokens billed for this run")
194
+ completion_tokens: int = Field(default=0, ge=0, description="Total output tokens billed for this run")
195
+ cached_prompt_tokens: int = Field(default=0, ge=0, description="Input tokens served from a provider prefix cache")
196
+ reasoning_tokens: int = Field(default=0, ge=0, description="Output tokens spent on chain-of-thought reasoning")
197
+ total_tokens: int = Field(default=0, ge=0, description="Total billed tokens (prompt + completion)")
198
+
199
+ @model_validator(mode="after")
200
+ def _fill_total_tokens(self) -> "TokenUsage":
201
+ r"""Derive ``total_tokens`` when a producer did not provide it."""
202
+ if self.total_tokens == 0:
203
+ self.total_tokens = self.prompt_tokens + self.completion_tokens
204
+ return self
205
+
206
+
207
+ class ForecastProvenance(BaseModel):
208
+ r"""
209
+ Operational provenance for a forecast: which engine, model, and prompt produced it.
210
+
211
+ Attributes:
212
+ provider: Inference provider family (e.g. ``"deepseek"``, ``"typesafe"``).
213
+ model_id: Model identifier as requested (e.g. ``"deepseek-flash"``).
214
+ model_version: Model version or checkpoint reported by the provider.
215
+ prompt_id: Identifier or version of the prompt template used.
216
+ temperature: Sampling temperature used for the run.
217
+ thinking: Whether provider reasoning/thinking mode was enabled.
218
+ cache_hit: True when the result was served from a cache.
219
+ run_id: Identifier shared by all calls belonging to one forecast run.
220
+ """
221
+
222
+ provider: Optional[str] = Field(default=None, description="Inference provider family (e.g. 'deepseek')")
223
+ model_id: Optional[str] = Field(default=None, description="Model identifier as requested")
224
+ model_version: Optional[str] = Field(default=None, description="Model version or checkpoint reported by the provider")
225
+ prompt_id: Optional[str] = Field(default=None, description="Identifier or version of the prompt template used")
226
+ temperature: Optional[float] = Field(default=None, description="Sampling temperature used for the run")
227
+ thinking: Optional[bool] = Field(default=None, description="Whether provider reasoning/thinking mode was enabled")
228
+ cache_hit: bool = Field(default=False, description="True when the result was served from a cache")
229
+ run_id: Optional[str] = Field(default=None, description="Identifier shared by all calls belonging to one forecast run")
230
+
231
+
181
232
  class MappingCompatibleModel(BaseModel):
182
233
  r"""Base model with lightweight dict-style compatibility helpers."""
183
234
 
@@ -293,6 +344,16 @@ class ForecastOutput(BaseModel):
293
344
  description="Ordered workflow stages executed for this forecast result",
294
345
  )
295
346
  calibration_metrics: Dict[str, Any] = Field(default_factory=dict, description="Performance metrics")
347
+ parse_status: str = Field(
348
+ default="unknown",
349
+ description="Parse outcome for the model output: 'ok', 'empty_content', 'invalid_json', "
350
+ "'schema_error', 'provider_error', or 'unknown'.",
351
+ )
352
+ usage: TokenUsage = Field(default_factory=TokenUsage, description="Token accounting for this forecast")
353
+ provenance: Optional[ForecastProvenance] = Field(
354
+ default=None,
355
+ description="Model and prompt provenance for this forecast",
356
+ )
296
357
  metadata: MetadataBase = Field(default_factory=MetadataBase) # type: ignore[arg-type]
297
358
 
298
359
  @model_validator(mode="before")
@@ -458,6 +519,8 @@ __all__ = [
458
519
  "ReasoningTrace",
459
520
  "ForecastOutput",
460
521
  "ForecastResult",
522
+ "TokenUsage",
523
+ "ForecastProvenance",
461
524
  ]
462
525
 
463
526
  ForecastResult = ForecastOutput
@@ -21,7 +21,7 @@ This module provides the single source of truth for the package version.
21
21
 
22
22
  __all__ = ["__version__", "__author__", "__contact__", "__license__", "__copyright__"]
23
23
 
24
- __version__ = "0.3.2"
24
+ __version__ = "0.4.0"
25
25
  __author__ = "XRTM Team"
26
26
  __contact__ = "moy@xrtm.org"
27
27
  __license__ = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xrtm-data
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: The Snapshot Vault for XRTM.
5
5
  Author-email: XRTM Team <moy@xrtm.org>
6
6
  License-Expression: Apache-2.0
@@ -17,7 +17,7 @@ Requires-Dist: ruff>=0.1.0; extra == "dev"
17
17
  Requires-Dist: mypy>=1.0.0; extra == "dev"
18
18
  Dynamic: license-file
19
19
 
20
- # xrtm-data v0.3.0
20
+ # xrtm-data v0.4.0
21
21
 
22
22
  [![PyPI](https://img.shields.io/pypi/v/xrtm-data?style=flat-square)](https://pypi.org/project/xrtm-data/)
23
23
 
@@ -16,7 +16,16 @@ from datetime import datetime, timedelta, timezone
16
16
 
17
17
  import pytest
18
18
 
19
- from xrtm.data import CausalEdge, CausalNode, ForecastOutput, ForecastQuestion, ForecastResult, MetadataBase
19
+ from xrtm.data import (
20
+ CausalEdge,
21
+ CausalNode,
22
+ ForecastOutput,
23
+ ForecastProvenance,
24
+ ForecastQuestion,
25
+ ForecastResult,
26
+ MetadataBase,
27
+ TokenUsage,
28
+ )
20
29
  from xrtm.data.core.schemas import TradeEvent, TradeWindow
21
30
 
22
31
 
@@ -202,3 +211,56 @@ def test_forecast_question_context_serializes():
202
211
 
203
212
  reloaded = ForecastQuestion.model_validate(payload)
204
213
  assert reloaded.context == {"key": "value", "nested": {"a": 1}}
214
+
215
+
216
+ def test_token_usage_derives_total():
217
+ """total_tokens is derived when a producer omits it."""
218
+ usage = TokenUsage(prompt_tokens=1200, completion_tokens=300)
219
+ assert usage.total_tokens == 1500
220
+
221
+
222
+ def test_token_usage_preserves_explicit_total():
223
+ """An explicit total_tokens from the provider is not overwritten."""
224
+ usage = TokenUsage(prompt_tokens=10, completion_tokens=5, total_tokens=99)
225
+ assert usage.total_tokens == 99
226
+
227
+
228
+ def test_forecast_output_telemetry_defaults():
229
+ """Telemetry fields are optional and safe for legacy producers."""
230
+ output = ForecastOutput(question_id="q_telemetry", probability=0.5, reasoning="legacy")
231
+ assert output.parse_status == "unknown"
232
+ assert output.usage.total_tokens == 0
233
+ assert output.provenance is None
234
+
235
+
236
+ def test_forecast_output_telemetry_round_trip():
237
+ """Telemetry survives JSON serialization and re-validation."""
238
+ output = ForecastOutput(
239
+ forecast_request_id="q_telemetry_2",
240
+ probability=0.72,
241
+ reasoning="telemetry round trip",
242
+ parse_status="ok",
243
+ usage=TokenUsage(
244
+ prompt_tokens=900,
245
+ completion_tokens=250,
246
+ cached_prompt_tokens=800,
247
+ reasoning_tokens=120,
248
+ ),
249
+ provenance=ForecastProvenance(
250
+ provider="deepseek",
251
+ model_id="deepseek-flash",
252
+ prompt_id="analyst-v2",
253
+ temperature=0.2,
254
+ thinking=False,
255
+ cache_hit=False,
256
+ ),
257
+ )
258
+ payload = output.model_dump(mode="json")
259
+ assert payload["parse_status"] == "ok"
260
+ assert payload["usage"]["total_tokens"] == 1150
261
+ assert payload["provenance"]["model_id"] == "deepseek-flash"
262
+
263
+ reloaded = ForecastOutput.model_validate(payload)
264
+ assert reloaded.usage.cached_prompt_tokens == 800
265
+ assert reloaded.provenance is not None
266
+ assert reloaded.provenance.provider == "deepseek"
File without changes
File without changes