prime-traces 0.0.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.
@@ -0,0 +1,27 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ build/
7
+ develop-eggs/
8
+ dist/
9
+ downloads/
10
+ eggs/
11
+ .eggs/
12
+ lib/
13
+ lib64/
14
+ parts/
15
+ sdist/
16
+ var/
17
+ wheels/
18
+ *.egg-info/
19
+ .installed.cfg
20
+ *.egg
21
+ .env
22
+ venv/
23
+ .venv/
24
+ ENV/
25
+ test_env/
26
+ .DS_Store
27
+ .claude/worktrees/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Prime Intellect
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,205 @@
1
+ Metadata-Version: 2.4
2
+ Name: prime-traces
3
+ Version: 0.0.1
4
+ Summary: Prime Intellect Traces SDK - Upload, query and export traces
5
+ Project-URL: Homepage, https://github.com/PrimeIntellect-ai/prime
6
+ Project-URL: Documentation, https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-traces
7
+ Project-URL: Repository, https://github.com/PrimeIntellect-ai/prime.git
8
+ Author-email: Prime Intellect <contact@primeintellect.ai>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: evals,observability,rollouts,traces
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: httpx>=0.25.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.13.1; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Prime Traces SDK
31
+
32
+ Upload and query training, evaluation and inference traces through the Prime
33
+ Traces service.
34
+
35
+ ## Features
36
+
37
+ - **Content-addressed uploads** - Batches are identified by the SHA-256 of
38
+ their exact bytes, so interrupted uploads are safe to rerun and never store
39
+ twice
40
+ - **Deterministic batching** - JSONL files are split at byte thresholds without
41
+ rewriting a single line
42
+ - **Typed reads** - Cursor-paginated summaries over extracted columns and raw
43
+ document retrieval
44
+ - **Type-safe** - Full type hints and Pydantic models
45
+ - **No CLI dependencies** - Pure SDK, usable in producers and services
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ uv add prime-traces
51
+ ```
52
+
53
+ or with pip:
54
+
55
+ ```bash
56
+ pip install prime-traces
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ ### Upload from memory
62
+
63
+ `upload_records` accepts JSON-compatible mappings as well as objects exposing
64
+ `to_record()`. Verifiers `Trace` / `Episode` and prime-rl `Rollout` objects
65
+ provide that method, so producers can upload completed records without writing
66
+ an intermediate JSONL file:
67
+
68
+ ```python
69
+ from prime_traces import LineFormat, TracesClient
70
+
71
+ client = TracesClient() # PRIME_API_KEY / ~/.prime/config.json
72
+
73
+ # Iterable[vf.Trace] or Iterable[prime_rl.orchestrator.types.Rollout]
74
+ receipts = client.upload_records(
75
+ traces,
76
+ context={"source": "prime-rl", "run_id": "run_9f3k2m"},
77
+ )
78
+
79
+ # Iterable[vf.Episode] for multi-agent runs
80
+ receipts = client.upload_records(
81
+ episodes,
82
+ line_format=LineFormat.EPISODE,
83
+ context={"source": "verifiers"},
84
+ )
85
+ ```
86
+
87
+ Records are serialized lazily and fed into bounded batches, so this neither
88
+ buffers the complete iterable nor round-trips through the filesystem. Callers
89
+ that already have encoded JSONL bytes can use `upload_lines` directly.
90
+
91
+ ### Upload a completed JSONL file
92
+
93
+ ```python
94
+ from prime_traces import TracesClient, LineFormat
95
+
96
+ client = TracesClient() # PRIME_API_KEY / ~/.prime/config.json
97
+
98
+ # One bare Verifiers trace per line:
99
+ receipts = client.upload_file("traces.jsonl", context={"source": "hosted_eval"})
100
+
101
+ # One complete episode per line (multi-agent runs):
102
+ receipts = client.upload_file(
103
+ "episodes.jsonl",
104
+ line_format=LineFormat.EPISODE,
105
+ context={"source": "hosted_eval", "suite_commit": "a1f39c2"},
106
+ )
107
+ ```
108
+
109
+ Uploads are content-addressed: each request is identified by the SHA-256 of its
110
+ exact uncompressed JSONL bytes and sent with an `Idempotency-Key`. Rerunning an
111
+ interrupted upload re-reads the file, reproduces the same bytes and keys, and
112
+ the service replays committed receipts without storing anything twice. A 400
113
+ rejection stops the upload with a bounded error code (`ErrorCode`); 429/503 and
114
+ gateway 502/504 are retried with the same bytes, honoring `Retry-After`.
115
+
116
+ ## Query
117
+
118
+ ```python
119
+ page = client.list(run_id="run_9f3k2m", reward_min=0.9, has_error=False)
120
+ for summary in page.items:
121
+ print(summary.trace_id, summary.score)
122
+
123
+ for summary in client.iter(task_id="tb2-0187"): # paginates for you
124
+ ...
125
+
126
+ summary = client.get("8d3f1a2b...")
127
+ raw = client.get_raw("8d3f1a2b...") # exact stored trace document
128
+ client.download_raw("8d3f1a2b...", "t.json") # streamed, for large traces
129
+
130
+ client.delete("8d3f1a2b...") # NotFoundError if the owner has no such trace
131
+ client.delete_run("run_9f3k2m") # one mutation, synchronous, no job handle
132
+ ```
133
+
134
+ Deletion is not a no-op on absent rows: the service checks existence first and
135
+ answers 404, so repeating a delete that already succeeded raises
136
+ `NotFoundError`. (The design docs specify it as idempotent; this tracks the
137
+ service as built.) Failures known to occur before delivery, 429 responses, and
138
+ service-coded 503 refusals are retried. Ambiguous response-path failures and
139
+ gateway 502/503/504 responses are surfaced as `AmbiguousDeleteError` without
140
+ replaying the deletion, because a retry could delete a trace written after the
141
+ first request.
142
+
143
+ Trace point reads/deletes and episode point/member reads currently reject IDs
144
+ containing `/`. ASGI decodes an encoded slash before matching the service's
145
+ `/{resource_id}` routes, so those IDs cannot be addressed until the service
146
+ accepts path-valued route parameters.
147
+
148
+ Episodes are read-only resources:
149
+
150
+ ```python
151
+ page = client.list_episodes(
152
+ run_id="run_9f3k2m",
153
+ environment_id="terminal-bench-2",
154
+ )
155
+ for episode in page.items:
156
+ print(episode.episode_id, episode.outcome)
157
+
158
+ if page.items:
159
+ episode_id = page.items[0].episode_id
160
+ detail = client.get_episode(episode_id) # + member aggregate under .traces
161
+ print(detail.error.type, detail.traces.trace_count)
162
+
163
+ # Member trace summaries use the trace filters (except sort) and pagination.
164
+ client.list_episode_traces(episode_id, has_error=True)
165
+ ```
166
+
167
+ Response shapes mirror the service's pinned models: pages are
168
+ `{items, next_cursor}`, a trace summary nests `model` / `score` / `execution`,
169
+ an episode nests `error` and (on point lookup) the member-trace aggregate
170
+ under `traces`, and unrecorded fields come back as `null`.
171
+
172
+ ## Configuration
173
+
174
+ | Source | Meaning |
175
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
176
+ | `PRIME_API_KEY` | Platform API token (needs `traces:read` / `traces:write` scopes) |
177
+ | `PRIME_TEAM_ID` | Optional team context, sent as `X-Prime-Team-ID` |
178
+ | `PRIME_TRACES_URL` | Base URL of the Prime Traces service; defaults to the platform API base URL. For the service's local compose stack: `http://localhost:8083` |
179
+ | `~/.prime/config.json` | Shared prime CLI config (`api_key`, `team_id`, `traces_url`) |
180
+
181
+ ## Not implemented yet (open v0 contract decisions)
182
+
183
+ - Exports, in any form. The service publishes `GET /traces/export` and the two
184
+ job routes, but all three handlers raise `NotImplementedError` — answered as
185
+ 500, not the 501 they document — and the streaming route declares no query
186
+ parameters, so there is no filter vocabulary to bind to. Wrapping it now
187
+ would ship a method that cannot succeed.
188
+ - `/search` and free-text queries — deferred with the `trace_components`
189
+ projection.
190
+ - Typed dot-path predicates (`traces.query`) — needs the server-side field
191
+ registry.
192
+ - An async client — the other prime SDKs ship sync/async pairs, and the main
193
+ producers (verifiers, prime-rl) are async; add once the sync surface
194
+ settles rather than freezing a duplicated API now.
195
+
196
+ ## Documentation
197
+
198
+ For detailed documentation, visit the
199
+ [Prime Traces SDK documentation](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-traces).
200
+
201
+ ## Related Packages
202
+
203
+ - [prime](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime) - Prime CLI (`prime traces ...` commands)
204
+ - [prime-sandboxes](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-sandboxes) - Sandboxes SDK
205
+ - [prime-evals](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-evals) - Evals SDK
@@ -0,0 +1,176 @@
1
+ # Prime Traces SDK
2
+
3
+ Upload and query training, evaluation and inference traces through the Prime
4
+ Traces service.
5
+
6
+ ## Features
7
+
8
+ - **Content-addressed uploads** - Batches are identified by the SHA-256 of
9
+ their exact bytes, so interrupted uploads are safe to rerun and never store
10
+ twice
11
+ - **Deterministic batching** - JSONL files are split at byte thresholds without
12
+ rewriting a single line
13
+ - **Typed reads** - Cursor-paginated summaries over extracted columns and raw
14
+ document retrieval
15
+ - **Type-safe** - Full type hints and Pydantic models
16
+ - **No CLI dependencies** - Pure SDK, usable in producers and services
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ uv add prime-traces
22
+ ```
23
+
24
+ or with pip:
25
+
26
+ ```bash
27
+ pip install prime-traces
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ### Upload from memory
33
+
34
+ `upload_records` accepts JSON-compatible mappings as well as objects exposing
35
+ `to_record()`. Verifiers `Trace` / `Episode` and prime-rl `Rollout` objects
36
+ provide that method, so producers can upload completed records without writing
37
+ an intermediate JSONL file:
38
+
39
+ ```python
40
+ from prime_traces import LineFormat, TracesClient
41
+
42
+ client = TracesClient() # PRIME_API_KEY / ~/.prime/config.json
43
+
44
+ # Iterable[vf.Trace] or Iterable[prime_rl.orchestrator.types.Rollout]
45
+ receipts = client.upload_records(
46
+ traces,
47
+ context={"source": "prime-rl", "run_id": "run_9f3k2m"},
48
+ )
49
+
50
+ # Iterable[vf.Episode] for multi-agent runs
51
+ receipts = client.upload_records(
52
+ episodes,
53
+ line_format=LineFormat.EPISODE,
54
+ context={"source": "verifiers"},
55
+ )
56
+ ```
57
+
58
+ Records are serialized lazily and fed into bounded batches, so this neither
59
+ buffers the complete iterable nor round-trips through the filesystem. Callers
60
+ that already have encoded JSONL bytes can use `upload_lines` directly.
61
+
62
+ ### Upload a completed JSONL file
63
+
64
+ ```python
65
+ from prime_traces import TracesClient, LineFormat
66
+
67
+ client = TracesClient() # PRIME_API_KEY / ~/.prime/config.json
68
+
69
+ # One bare Verifiers trace per line:
70
+ receipts = client.upload_file("traces.jsonl", context={"source": "hosted_eval"})
71
+
72
+ # One complete episode per line (multi-agent runs):
73
+ receipts = client.upload_file(
74
+ "episodes.jsonl",
75
+ line_format=LineFormat.EPISODE,
76
+ context={"source": "hosted_eval", "suite_commit": "a1f39c2"},
77
+ )
78
+ ```
79
+
80
+ Uploads are content-addressed: each request is identified by the SHA-256 of its
81
+ exact uncompressed JSONL bytes and sent with an `Idempotency-Key`. Rerunning an
82
+ interrupted upload re-reads the file, reproduces the same bytes and keys, and
83
+ the service replays committed receipts without storing anything twice. A 400
84
+ rejection stops the upload with a bounded error code (`ErrorCode`); 429/503 and
85
+ gateway 502/504 are retried with the same bytes, honoring `Retry-After`.
86
+
87
+ ## Query
88
+
89
+ ```python
90
+ page = client.list(run_id="run_9f3k2m", reward_min=0.9, has_error=False)
91
+ for summary in page.items:
92
+ print(summary.trace_id, summary.score)
93
+
94
+ for summary in client.iter(task_id="tb2-0187"): # paginates for you
95
+ ...
96
+
97
+ summary = client.get("8d3f1a2b...")
98
+ raw = client.get_raw("8d3f1a2b...") # exact stored trace document
99
+ client.download_raw("8d3f1a2b...", "t.json") # streamed, for large traces
100
+
101
+ client.delete("8d3f1a2b...") # NotFoundError if the owner has no such trace
102
+ client.delete_run("run_9f3k2m") # one mutation, synchronous, no job handle
103
+ ```
104
+
105
+ Deletion is not a no-op on absent rows: the service checks existence first and
106
+ answers 404, so repeating a delete that already succeeded raises
107
+ `NotFoundError`. (The design docs specify it as idempotent; this tracks the
108
+ service as built.) Failures known to occur before delivery, 429 responses, and
109
+ service-coded 503 refusals are retried. Ambiguous response-path failures and
110
+ gateway 502/503/504 responses are surfaced as `AmbiguousDeleteError` without
111
+ replaying the deletion, because a retry could delete a trace written after the
112
+ first request.
113
+
114
+ Trace point reads/deletes and episode point/member reads currently reject IDs
115
+ containing `/`. ASGI decodes an encoded slash before matching the service's
116
+ `/{resource_id}` routes, so those IDs cannot be addressed until the service
117
+ accepts path-valued route parameters.
118
+
119
+ Episodes are read-only resources:
120
+
121
+ ```python
122
+ page = client.list_episodes(
123
+ run_id="run_9f3k2m",
124
+ environment_id="terminal-bench-2",
125
+ )
126
+ for episode in page.items:
127
+ print(episode.episode_id, episode.outcome)
128
+
129
+ if page.items:
130
+ episode_id = page.items[0].episode_id
131
+ detail = client.get_episode(episode_id) # + member aggregate under .traces
132
+ print(detail.error.type, detail.traces.trace_count)
133
+
134
+ # Member trace summaries use the trace filters (except sort) and pagination.
135
+ client.list_episode_traces(episode_id, has_error=True)
136
+ ```
137
+
138
+ Response shapes mirror the service's pinned models: pages are
139
+ `{items, next_cursor}`, a trace summary nests `model` / `score` / `execution`,
140
+ an episode nests `error` and (on point lookup) the member-trace aggregate
141
+ under `traces`, and unrecorded fields come back as `null`.
142
+
143
+ ## Configuration
144
+
145
+ | Source | Meaning |
146
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | `PRIME_API_KEY` | Platform API token (needs `traces:read` / `traces:write` scopes) |
148
+ | `PRIME_TEAM_ID` | Optional team context, sent as `X-Prime-Team-ID` |
149
+ | `PRIME_TRACES_URL` | Base URL of the Prime Traces service; defaults to the platform API base URL. For the service's local compose stack: `http://localhost:8083` |
150
+ | `~/.prime/config.json` | Shared prime CLI config (`api_key`, `team_id`, `traces_url`) |
151
+
152
+ ## Not implemented yet (open v0 contract decisions)
153
+
154
+ - Exports, in any form. The service publishes `GET /traces/export` and the two
155
+ job routes, but all three handlers raise `NotImplementedError` — answered as
156
+ 500, not the 501 they document — and the streaming route declares no query
157
+ parameters, so there is no filter vocabulary to bind to. Wrapping it now
158
+ would ship a method that cannot succeed.
159
+ - `/search` and free-text queries — deferred with the `trace_components`
160
+ projection.
161
+ - Typed dot-path predicates (`traces.query`) — needs the server-side field
162
+ registry.
163
+ - An async client — the other prime SDKs ship sync/async pairs, and the main
164
+ producers (verifiers, prime-rl) are async; add once the sync surface
165
+ settles rather than freezing a duplicated API now.
166
+
167
+ ## Documentation
168
+
169
+ For detailed documentation, visit the
170
+ [Prime Traces SDK documentation](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-traces).
171
+
172
+ ## Related Packages
173
+
174
+ - [prime](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime) - Prime CLI (`prime traces ...` commands)
175
+ - [prime-sandboxes](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-sandboxes) - Sandboxes SDK
176
+ - [prime-evals](https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-evals) - Evals SDK
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Basic usage example for the prime-traces SDK.
4
+
5
+ This demonstrates the standalone SDK without any CLI dependencies.
6
+
7
+ Credentials come from PRIME_API_KEY / ~/.prime/config.json. Point
8
+ PRIME_TRACES_URL at the Prime Traces service — e.g. the service's local
9
+ compose stack: PRIME_TRACES_URL=http://localhost:8083
10
+ """
11
+
12
+ import tempfile
13
+ import time
14
+ from pathlib import Path
15
+
16
+ from prime_traces import APIError, ForbiddenError, TracesClient, ValidationRejectedError
17
+
18
+
19
+ def sample_trace(trace_id: str, reward: float, started_at: float) -> dict:
20
+ """One in-memory Verifiers-compatible trace record.
21
+
22
+ Trimmed to the fields the service's extractor reads, which is a small
23
+ subset of a real v1 record — the serialized record is stored verbatim,
24
+ and every summary column is a projection of it. Two of these are not
25
+ optional: a non-empty string ``id``, and a numeric ``timing.start`` inside
26
+ the accepted window (generous lookback, tight lookahead — producers upload
27
+ completed files, so an old run is ordinary and a future one never is).
28
+ A line missing either is rejected with ``invalid_trace`` /
29
+ ``created_at_out_of_window`` and the whole request stores nothing.
30
+ """
31
+ return {
32
+ "version": 4,
33
+ "id": trace_id,
34
+ "run": {"id": "run_example"},
35
+ "task": {"type": "ExampleTask", "data": {"name": "example-0001"}},
36
+ "agent": {
37
+ "name": "solver",
38
+ "config": {
39
+ "model": "deepseek-v4-flash",
40
+ "client": {"base_url": "https://api.pinference.ai/api/v1"},
41
+ },
42
+ },
43
+ "calls": [{"model": "deepseek-v4-flash", "usage": {"total_tokens": 1834}}],
44
+ "rewards": {"correctness": {"score": reward, "weight": 1.0}},
45
+ "metrics": {},
46
+ "stop_condition": "done",
47
+ "ok": True,
48
+ "errors": [],
49
+ # `timing.start` is the producer's wall clock and becomes `created_at`;
50
+ # `timing.scoring.end` is the last phase, so duration_ms comes from the
51
+ # two together.
52
+ "timing": {"start": started_at, "scoring": {"end": started_at + 12.5}},
53
+ "info": {},
54
+ }
55
+
56
+
57
+ def main():
58
+ # Verifiers Trace objects and prime-rl Rollouts can be passed directly;
59
+ # both expose the same to_record() protocol accepted by upload_records.
60
+ started_at = time.time()
61
+ traces = [
62
+ sample_trace("3f2a9c1e", reward=0.85, started_at=started_at),
63
+ sample_trace("b81d4e77", reward=0.40, started_at=started_at + 1.0),
64
+ ]
65
+ output_dir = Path(tempfile.mkdtemp())
66
+
67
+ with TracesClient() as client:
68
+ try:
69
+ print("Uploading...")
70
+ # Content-addressed: rerunning this replays committed receipts
71
+ # without storing anything twice.
72
+ receipts = client.upload_records(
73
+ traces,
74
+ context={"source": "example", "suite_commit": "a1f39c2"},
75
+ )
76
+ for receipt in receipts:
77
+ print(f"✓ upload {receipt.upload_id[:12]}… {receipt.status}")
78
+
79
+ print("\nListing this run's traces...")
80
+ page = client.list(run_id="run_example", limit=10)
81
+ for summary in page.items:
82
+ # `score` is a nested object, and a null `reward` inside it
83
+ # means unscored — distinct from a scored 0.0.
84
+ score = summary.score
85
+ reward = score.reward if score else None
86
+ print(f" {summary.trace_id} reward={reward}")
87
+
88
+ if page.items:
89
+ trace_id = page.items[0].trace_id
90
+ print(f"\nFetching raw document for {trace_id}...")
91
+ dest = output_dir / "trace.json"
92
+ written = client.download_raw(trace_id, dest)
93
+ print(f"✓ wrote {written} bytes to {dest}")
94
+
95
+ except ValidationRejectedError as error:
96
+ # A 400 rejects the whole request and stores nothing; branch on
97
+ # error.code (see prime_traces.ErrorCode), fix the file, rerun.
98
+ print(f"✗ rejected: {error.code}: {error}")
99
+ except ForbiddenError as error:
100
+ # `service_not_enabled` means the account is not in the private
101
+ # beta; `forbidden` means the token lacks traces:read/traces:write.
102
+ print(f"✗ not permitted: {error.code}: {error}")
103
+ except APIError as error:
104
+ print(f"✗ API error: {error}")
105
+
106
+
107
+ if __name__ == "__main__":
108
+ main()
@@ -0,0 +1,60 @@
1
+ [project]
2
+ name = "prime-traces"
3
+ # Version is single-sourced from src/prime_traces/__init__.py via Hatch
4
+ dynamic = ["version"]
5
+ description = "Prime Intellect Traces SDK - Upload, query and export traces"
6
+ readme = "README.md"
7
+ requires-python = ">=3.10"
8
+ license = {text = "MIT"}
9
+ authors = [
10
+ { name = "Prime Intellect", email = "contact@primeintellect.ai" }
11
+ ]
12
+ dependencies = [
13
+ "httpx>=0.25.0",
14
+ "pydantic>=2.0.0",
15
+ ]
16
+ keywords = ["traces", "observability", "evals", "rollouts"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Scientific/Engineering :: Artificial Intelligence"
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/PrimeIntellect-ai/prime"
32
+ Documentation = "https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-traces"
33
+ Repository = "https://github.com/PrimeIntellect-ai/prime.git"
34
+
35
+ [project.optional-dependencies]
36
+ dev = [
37
+ "pytest>=7.0.0",
38
+ "ruff>=0.13.1",
39
+ ]
40
+
41
+ [build-system]
42
+ requires = ["hatchling"]
43
+ build-backend = "hatchling.build"
44
+
45
+ [tool.hatch.version]
46
+ path = "src/prime_traces/__init__.py"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/prime_traces"]
50
+
51
+ [tool.pytest.ini_options]
52
+ addopts = "-v"
53
+ testpaths = ["tests"]
54
+
55
+ [tool.ruff]
56
+ line-length = 100
57
+ target-version = "py310"
58
+
59
+ [tool.ruff.lint]
60
+ extend-select = ["E", "F", "I"]