benchflow 0.7.2.dev1982__py3-none-any.whl → 0.7.2.dev1986__py3-none-any.whl
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.
- benchflow/cli/traj.py +109 -1
- {benchflow-0.7.2.dev1982.dist-info → benchflow-0.7.2.dev1986.dist-info}/METADATA +1 -1
- {benchflow-0.7.2.dev1982.dist-info → benchflow-0.7.2.dev1986.dist-info}/RECORD +6 -6
- {benchflow-0.7.2.dev1982.dist-info → benchflow-0.7.2.dev1986.dist-info}/WHEEL +0 -0
- {benchflow-0.7.2.dev1982.dist-info → benchflow-0.7.2.dev1986.dist-info}/entry_points.txt +0 -0
- {benchflow-0.7.2.dev1982.dist-info → benchflow-0.7.2.dev1986.dist-info}/licenses/LICENSE +0 -0
benchflow/cli/traj.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
import os
|
|
6
7
|
import shutil
|
|
7
8
|
import subprocess
|
|
@@ -29,6 +30,7 @@ from benchflow.publish.traj_capture import (
|
|
|
29
30
|
stage_trajectory_artifacts,
|
|
30
31
|
validate_email,
|
|
31
32
|
validate_github_id,
|
|
33
|
+
validate_source_id,
|
|
32
34
|
)
|
|
33
35
|
from benchflow.publish.traj_report import (
|
|
34
36
|
DEFAULT_PREVIEW_STEPS,
|
|
@@ -127,6 +129,7 @@ class _UploadOptions:
|
|
|
127
129
|
github_id: str | None
|
|
128
130
|
email: str | None
|
|
129
131
|
source_id: str | None
|
|
132
|
+
repo: bool
|
|
130
133
|
direct: bool
|
|
131
134
|
container_url: str | None
|
|
132
135
|
dry_run: bool
|
|
@@ -223,6 +226,14 @@ def register_traj(app: typer.Typer) -> None:
|
|
|
223
226
|
str | None,
|
|
224
227
|
typer.Option("--source-id", help="Stable contributor source identifier"),
|
|
225
228
|
] = None,
|
|
229
|
+
repo: Annotated[
|
|
230
|
+
bool,
|
|
231
|
+
typer.Option(
|
|
232
|
+
"--repo/--no-repo",
|
|
233
|
+
help="Tag the upload with the session's repository "
|
|
234
|
+
"(owner/name from its git remote) as the source id",
|
|
235
|
+
),
|
|
236
|
+
] = True,
|
|
226
237
|
direct: Annotated[
|
|
227
238
|
bool,
|
|
228
239
|
typer.Option("--direct", help="Upload with local Azure credentials"),
|
|
@@ -254,6 +265,7 @@ def register_traj(app: typer.Typer) -> None:
|
|
|
254
265
|
github_id=github_id,
|
|
255
266
|
email=email,
|
|
256
267
|
source_id=source_id,
|
|
268
|
+
repo=repo,
|
|
257
269
|
direct=direct,
|
|
258
270
|
container_url=container_url,
|
|
259
271
|
dry_run=dry_run,
|
|
@@ -268,7 +280,17 @@ def register_traj(app: typer.Typer) -> None:
|
|
|
268
280
|
def _run_upload(options: _UploadOptions) -> None:
|
|
269
281
|
prompted = options.path is None
|
|
270
282
|
path = options.path or _prompt_for_path()
|
|
271
|
-
|
|
283
|
+
repo_slug: str | None = None
|
|
284
|
+
if options.source_id is not None:
|
|
285
|
+
source_id = options.source_id
|
|
286
|
+
else:
|
|
287
|
+
if options.repo:
|
|
288
|
+
repo_slug = _detect_repo_slug(path)
|
|
289
|
+
source_id = f"repo/{repo_slug}" if repo_slug else default_source_id(path)
|
|
290
|
+
if repo_slug:
|
|
291
|
+
# Contributor-visible metadata: surface the tag so private-repo
|
|
292
|
+
# sessions can opt out before anything leaves the machine.
|
|
293
|
+
console.print(f"Repo: {repo_slug} (use --no-repo to omit)")
|
|
272
294
|
destination = _resolve_destination(options)
|
|
273
295
|
|
|
274
296
|
with (
|
|
@@ -381,6 +403,92 @@ def _infer_email() -> str:
|
|
|
381
403
|
return ""
|
|
382
404
|
|
|
383
405
|
|
|
406
|
+
_SESSION_CWD_SCAN_LINES = 50
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def _detect_repo_slug(path: Path) -> str | None:
|
|
410
|
+
"""Best-effort ``owner/name`` for the repository the session was about.
|
|
411
|
+
|
|
412
|
+
Reads the working directory the session recorded (Claude events carry a
|
|
413
|
+
``cwd`` field; Codex ``session_meta`` payloads do too), asks that
|
|
414
|
+
directory's git for the ``origin`` remote, and falls back to the
|
|
415
|
+
invocation directory. Every failure is silent — repo tagging must never
|
|
416
|
+
break an upload — and local-path remotes never produce a tag, so no
|
|
417
|
+
local absolute path can leak into the manifest.
|
|
418
|
+
"""
|
|
419
|
+
for candidate in (_session_cwd(path), Path.cwd()):
|
|
420
|
+
if candidate is None or not candidate.is_dir():
|
|
421
|
+
continue
|
|
422
|
+
remote = _command_stdout(
|
|
423
|
+
"git", "-C", str(candidate), "remote", "get-url", "origin"
|
|
424
|
+
)
|
|
425
|
+
slug = _repo_slug_from_remote(remote) if remote else None
|
|
426
|
+
if slug:
|
|
427
|
+
return slug
|
|
428
|
+
return None
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _session_cwd(path: Path) -> Path | None:
|
|
432
|
+
"""Working directory recorded by the first session event that has one."""
|
|
433
|
+
session = path.expanduser()
|
|
434
|
+
if not session.is_file():
|
|
435
|
+
return None
|
|
436
|
+
try:
|
|
437
|
+
with session.open(encoding="utf-8", errors="replace") as stream:
|
|
438
|
+
for line_number, line in enumerate(stream):
|
|
439
|
+
if line_number >= _SESSION_CWD_SCAN_LINES:
|
|
440
|
+
break
|
|
441
|
+
body = line.strip()
|
|
442
|
+
if not body:
|
|
443
|
+
continue
|
|
444
|
+
try:
|
|
445
|
+
event = json.loads(body)
|
|
446
|
+
except json.JSONDecodeError:
|
|
447
|
+
continue
|
|
448
|
+
if not isinstance(event, dict):
|
|
449
|
+
continue
|
|
450
|
+
cwd = event.get("cwd")
|
|
451
|
+
if isinstance(cwd, str) and cwd:
|
|
452
|
+
return Path(cwd)
|
|
453
|
+
payload = event.get("payload")
|
|
454
|
+
if (
|
|
455
|
+
event.get("type") == "session_meta"
|
|
456
|
+
and isinstance(payload, dict)
|
|
457
|
+
and isinstance(payload.get("cwd"), str)
|
|
458
|
+
and payload["cwd"]
|
|
459
|
+
):
|
|
460
|
+
return Path(payload["cwd"])
|
|
461
|
+
except OSError:
|
|
462
|
+
return None
|
|
463
|
+
return None
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def _repo_slug_from_remote(remote: str) -> str | None:
|
|
467
|
+
"""Normalize an https/ssh git remote URL to ``owner/name``.
|
|
468
|
+
|
|
469
|
+
Only URL-shaped remotes qualify; a filesystem-path remote returns
|
|
470
|
+
``None`` so local paths never enter the uploaded source id.
|
|
471
|
+
"""
|
|
472
|
+
value = remote.strip()
|
|
473
|
+
if "://" in value:
|
|
474
|
+
_, _, rest = value.partition("://")
|
|
475
|
+
_, _, repo_path = rest.partition("/")
|
|
476
|
+
elif ":" in value and "@" in value.partition(":")[0]:
|
|
477
|
+
repo_path = value.partition(":")[2]
|
|
478
|
+
else:
|
|
479
|
+
return None
|
|
480
|
+
repo_path = repo_path.strip("/").removesuffix(".git")
|
|
481
|
+
segments = [segment for segment in repo_path.split("/") if segment]
|
|
482
|
+
if len(segments) < 2:
|
|
483
|
+
return None
|
|
484
|
+
slug = f"{segments[-2]}/{segments[-1]}"
|
|
485
|
+
try:
|
|
486
|
+
validate_source_id(f"repo/{slug}")
|
|
487
|
+
except ValueError:
|
|
488
|
+
return None
|
|
489
|
+
return slug
|
|
490
|
+
|
|
491
|
+
|
|
384
492
|
def _git_config(key: str) -> str | None:
|
|
385
493
|
return _command_stdout("git", "config", "--get", key)
|
|
386
494
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: benchflow
|
|
3
|
-
Version: 0.7.2.
|
|
3
|
+
Version: 0.7.2.dev1986
|
|
4
4
|
Summary: Multi-turn agent benchmarking with ACP — run any agent, any model, any provider.
|
|
5
5
|
Project-URL: Homepage, https://github.com/benchflow-ai/benchflow
|
|
6
6
|
Project-URL: Repository, https://github.com/benchflow-ai/benchflow
|
|
@@ -116,7 +116,7 @@ benchflow/cli/skills.py,sha256=2Apv1iqvmstWEhY6O-PRdxKc8RYwR6f7MvbYfl2dWm0,7497
|
|
|
116
116
|
benchflow/cli/tasks.py,sha256=b1XP1EZ79ZtK_1shF65qZyv27EcKKFZYV35M4DzxYKI,18534
|
|
117
117
|
benchflow/cli/trace_import.py,sha256=NHDieFdiKQ-2Sr1-GF8Z5EDcbGsz2qq_kFE0rXacC2o,14705
|
|
118
118
|
benchflow/cli/train.py,sha256=MIP_JxptitH348bWWURpcWt-TmDAw1s8d-RUU7jBaIg,23635
|
|
119
|
-
benchflow/cli/traj.py,sha256=
|
|
119
|
+
benchflow/cli/traj.py,sha256=2QlXCLNywIKsm8uQVsQ1TAEnaafV6b0dfLx37O2wEsU,23691
|
|
120
120
|
benchflow/continue_run/__init__.py,sha256=dWidng7kJphVUtbP1a1Ma0Lyjxj5yLgQZIApaKCJUew,1479
|
|
121
121
|
benchflow/continue_run/batch.py,sha256=8BNSInyp_Ol6Fcrg4ezBJdi3cBS12nC8mf963_x4fIg,4146
|
|
122
122
|
benchflow/continue_run/orchestrator.py,sha256=wYoseBNE_rZ0EjNwWDyqfave54xNRe43sCd_O4VJjyk,27676
|
|
@@ -292,8 +292,8 @@ benchflow/trajectories/tree.py,sha256=c0jyoP9OurDQq-zRtPc66edzWUvLGwQQz0jgtyqSw2
|
|
|
292
292
|
benchflow/trajectories/trl_sft_tokenization.py,sha256=-Ef0bP9cuzfzOz5nIv2mEF3taQIEw68h6SM1YO-Mwn4,8643
|
|
293
293
|
benchflow/trajectories/types.py,sha256=aSJclec3dOCUlfFNDL8GfzvkAcBo5r-dvlHE0MnGdMo,27554
|
|
294
294
|
benchflow/trajectories/viewer.py,sha256=59wr8pcWWsCYzuI_sFzTSFJFHeXzH6Yklrh8UsF1ksg,26561
|
|
295
|
-
benchflow-0.7.2.
|
|
296
|
-
benchflow-0.7.2.
|
|
297
|
-
benchflow-0.7.2.
|
|
298
|
-
benchflow-0.7.2.
|
|
299
|
-
benchflow-0.7.2.
|
|
295
|
+
benchflow-0.7.2.dev1986.dist-info/METADATA,sha256=D7gO4mBmAwaKA5_bFHpuy2Hu2_vfMEBQLdPfVoCyFEk,15261
|
|
296
|
+
benchflow-0.7.2.dev1986.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
297
|
+
benchflow-0.7.2.dev1986.dist-info/entry_points.txt,sha256=qPMBVtH4qz3P4nMALEAdTbvpxvsVch9RhqshZKQn1dE,84
|
|
298
|
+
benchflow-0.7.2.dev1986.dist-info/licenses/LICENSE,sha256=ohnbHkuBylrTtOvaZJk9Hz7dRwmaEEGAb5ZcBV4Xuhw,10779
|
|
299
|
+
benchflow-0.7.2.dev1986.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|