uenv-bridge 0.2.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 (64) hide show
  1. uenv_bridge-0.2.1/PKG-INFO +16 -0
  2. uenv_bridge-0.2.1/README.md +44 -0
  3. uenv_bridge-0.2.1/pyproject.toml +34 -0
  4. uenv_bridge-0.2.1/setup.cfg +4 -0
  5. uenv_bridge-0.2.1/src/uenv/bridge/__init__.py +4 -0
  6. uenv_bridge-0.2.1/src/uenv/bridge/authorized_hub.py +43 -0
  7. uenv_bridge-0.2.1/src/uenv/bridge/cli.py +294 -0
  8. uenv_bridge-0.2.1/src/uenv/bridge/client.py +746 -0
  9. uenv_bridge-0.2.1/src/uenv/bridge/client_identity.py +109 -0
  10. uenv_bridge-0.2.1/src/uenv/bridge/client_settings.py +79 -0
  11. uenv_bridge-0.2.1/src/uenv/bridge/commands.py +473 -0
  12. uenv_bridge-0.2.1/src/uenv/bridge/data_output.py +89 -0
  13. uenv_bridge-0.2.1/src/uenv/bridge/evaluation.py +223 -0
  14. uenv_bridge-0.2.1/src/uenv/bridge/gateway_hub.py +61 -0
  15. uenv_bridge-0.2.1/src/uenv/bridge/gateway_training.py +50 -0
  16. uenv_bridge-0.2.1/src/uenv/bridge/integrations/__init__.py +1 -0
  17. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/__init__.py +1 -0
  18. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/adapter.py +111 -0
  19. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/agent_loop.py +203 -0
  20. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/compat.json +97 -0
  21. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/configuration.py +65 -0
  22. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/dataset.py +44 -0
  23. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/jobs.py +553 -0
  24. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/local.py +189 -0
  25. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/recipes/agent-loop.yaml +3 -0
  26. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/recipes/verl_async.yaml +97 -0
  27. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/recipes/verl_sync.yaml +104 -0
  28. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/sampling.py +236 -0
  29. uenv_bridge-0.2.1/src/uenv/bridge/integrations/verl/setup.py +59 -0
  30. uenv_bridge-0.2.1/src/uenv/bridge/management_client.py +80 -0
  31. uenv_bridge-0.2.1/src/uenv/bridge/management_gateway.py +244 -0
  32. uenv_bridge-0.2.1/src/uenv/bridge/management_migration.py +45 -0
  33. uenv_bridge-0.2.1/src/uenv/bridge/model_gateway.py +168 -0
  34. uenv_bridge-0.2.1/src/uenv/bridge/model_sessions.py +137 -0
  35. uenv_bridge-0.2.1/src/uenv/bridge/platform_identity.py +286 -0
  36. uenv_bridge-0.2.1/src/uenv/bridge/platform_quota.py +59 -0
  37. uenv_bridge-0.2.1/src/uenv/bridge/platform_resources.py +154 -0
  38. uenv_bridge-0.2.1/src/uenv/bridge/result_export.py +162 -0
  39. uenv_bridge-0.2.1/src/uenv/bridge/result_reader.py +105 -0
  40. uenv_bridge-0.2.1/src/uenv/bridge/run_configuration.py +50 -0
  41. uenv_bridge-0.2.1/src/uenv/bridge/run_management.py +68 -0
  42. uenv_bridge-0.2.1/src/uenv/bridge/training.py +208 -0
  43. uenv_bridge-0.2.1/src/uenv/bridge/training_data.py +39 -0
  44. uenv_bridge-0.2.1/src/uenv/bridge/training_management.py +111 -0
  45. uenv_bridge-0.2.1/src/uenv/bridge/web.py +1711 -0
  46. uenv_bridge-0.2.1/src/uenv/bridge/web_access.py +72 -0
  47. uenv_bridge-0.2.1/src/uenv/bridge/web_assets/app.js +79 -0
  48. uenv_bridge-0.2.1/src/uenv/bridge/web_assets/index.html +14 -0
  49. uenv_bridge-0.2.1/src/uenv/bridge/web_assets/style.css +1 -0
  50. uenv_bridge-0.2.1/src/uenv/bridge/web_github_login.py +142 -0
  51. uenv_bridge-0.2.1/src/uenv/bridge/web_hub_access.py +54 -0
  52. uenv_bridge-0.2.1/src/uenv/bridge/web_identity.py +115 -0
  53. uenv_bridge-0.2.1/src/uenv/bridge/web_local_training.py +258 -0
  54. uenv_bridge-0.2.1/src/uenv/bridge/web_model_sessions.py +212 -0
  55. uenv_bridge-0.2.1/src/uenv/bridge/web_publication.py +277 -0
  56. uenv_bridge-0.2.1/src/uenv/bridge/web_state.py +571 -0
  57. uenv_bridge-0.2.1/src/uenv/bridge/web_training_routing.py +121 -0
  58. uenv_bridge-0.2.1/src/uenv/bridge/wire.py +55 -0
  59. uenv_bridge-0.2.1/src/uenv_bridge.egg-info/PKG-INFO +16 -0
  60. uenv_bridge-0.2.1/src/uenv_bridge.egg-info/SOURCES.txt +62 -0
  61. uenv_bridge-0.2.1/src/uenv_bridge.egg-info/dependency_links.txt +1 -0
  62. uenv_bridge-0.2.1/src/uenv_bridge.egg-info/entry_points.txt +5 -0
  63. uenv_bridge-0.2.1/src/uenv_bridge.egg-info/requires.txt +8 -0
  64. uenv_bridge-0.2.1/src/uenv_bridge.egg-info/top_level.txt +1 -0
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: uenv-bridge
3
+ Version: 0.2.1
4
+ Summary: Unified UEnv submission client
5
+ Project-URL: Documentation, https://uenv.io
6
+ Project-URL: Repository, https://github.com/audreyyan1015/uenv_refactor
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: uenv-sdk[grpc]==0.1.0
10
+ Requires-Dist: grpcio<2,>=1.80
11
+ Requires-Dist: PyYAML<7,>=6
12
+ Requires-Dist: aiohttp<4,>=3.12
13
+ Provides-Extra: web
14
+ Provides-Extra: training
15
+
16
+ UEnv client for evaluation, trajectory collection, environment publishing and training integration. Install with `python -m pip install -U uenv-bridge`, then run `uenv --help`. For local training, install in your existing PyTorch, VeRL and vLLM environment. GPU training frameworks and model weights are prepared separately. Documentation: https://uenv.io
@@ -0,0 +1,44 @@
1
+ # UEnv Bridge
2
+
3
+ CLI、Python 客户端和浏览器共用 UEnvClient;不存在任务专用启动脚本。
4
+
5
+ - client.py:准备和提交统一批次,查询状态、结果和授权文件,取消任务。
6
+ - cli.py:读取 run.yaml 和标准化 JSONL,调用同一客户端。
7
+ - web.py / web_assets:浏览器适配与静态页面,调用同一客户端。
8
+ - web_state.py:保存网页提交身份、精确重试请求、上传和管理操作关联;任务状态仍由 Server 管理。
9
+ - integrations/verl/jobs.py:在已有训练环境调用 Ray Jobs、读取 VeRL 输出并核对停止;不实现训练器。
10
+ - training.py / integrations/verl/adapter.py / integrations/verl/agent_loop.py:把统一结果及轨迹交给训练器。
11
+ - model_gateway.py:连接训练器提供的模型服务,保留真实 token 与策略版本信息。
12
+
13
+ 源码安装:`python -m pip install -e python/uenv_bridge`。
14
+
15
+ 客户端统一使用基础包,评测、轨迹采集、环境发布和训练接入不需要额外安装选项。正式在线安装命令为 `python -m pip install -U uenv-bridge`;须先将依赖的 `uenv-sdk` 和本包发布到 PyPI,目前使用[发行包安装](../../docs/user/02-安装部署与环境准备/2.1-安装与运行环境准备.md#只安装任务客户端)。本机训练在已有 PyTorch、VeRL、vLLM 的 Python 环境中安装,UEnv 不安装这些训练组件。
16
+
17
+ `training`、`web` extras 仅为空的兼容名称,供旧发行安装器使用;所有依赖由基础包统一声明。后续停止支持引用这些名称的旧安装器时再移除。
18
+ 浏览器:`uenv-web --endpoint http://127.0.0.1:SERVER_PORT --hub http://127.0.0.1:HUB_PORT`。
19
+ 默认只监听 127.0.0.1:8090。需要远程访问时使用 TLS 反向代理。
20
+
21
+ run.yaml 和 SDK 传入的 RunSpec 是同一份配置。标准化样本每行包含 task 和可选 private_data。
22
+ 原始样本先由数据集包的 DatasetAdapter 准备;Bridge 不实现数据集评分或特殊调度。
23
+ 训练器负责模型服务与权重更新,可编辑的 VeRL 配置在仓库及发行包根目录 training-config/,原生入口说明在 examples/verl/;VeRL 专用接入实现在 integrations/verl/,公共数据准备由 training_data.py 和 uenv training prepare 提供,使用现有 Bridge 提交、轨迹校验与转换路径。
24
+
25
+ 评测批量输出仍使用同一客户端:
26
+
27
+ uenv run --run run.yaml --samples samples.jsonl --endpoint http://127.0.0.1:SERVER_PORT --wait --batch-size 100 --output results.jsonl
28
+
29
+ --output 必须搭配 --wait,文件已存在时拒绝覆盖。
30
+ --wait 持续等待每批任务的终态,涵盖排队时间;Ctrl+C 可停止等待,已提交的任务仍可通过取消命令终止。
31
+ 未指定 --output 时,stdout 每行仍是一条 EpisodeResult;运行汇总写 stderr。
32
+ SDK 使用 client.evaluate_prepared(prepared, batch_size=100, output="results.jsonl"),
33
+ 返回汇总字典及 exit_code;不要在数据集 Scorer 中再汇总批次分数。
34
+ 同一份已准备请求重试时保持 batch_size 不变;分批请求身份由原 batch_id 和切分位置确定。
35
+
36
+
37
+ 完整 React 运行界面的连接方式见 `frontend/README.md`。`--state-dir` 指定 Linux 节点上的私有提交目录,默认 `~/.local/state/uenv/web`;它必须在 Web 重启后保留。现有未带 Idempotency-Key 的 `run + samples` HTTP 调用保持原返回方式。新界面使用固定键,后台准备后保存精确 BatchRequest,重试不重新生成任务身份。
38
+
39
+ 运行配置查询通过新 `UEnvClient.run_spec()` 调用 Server `GetRunSpec`,读取原运行记录;应同步更新 Server 与 SDK。模型密钥继续使用已有执行侧 credential_ref,不能放进网页配置。网页导出复用 `export_results(..., max_bytes=...)`,命令行默认行为不变。
40
+
41
+
42
+ 完整控制台的资源发布调用 SDK/Hub;资源启用与凭据交付调用现有安装器受限入口;训练作业使用现有 Ray/VeRL 环境。`--console-config` 提供管理员固定的令牌文件、完整发行目录、集群配置与训练目标。配置、权限、文件上传和恢复说明统一见仓库 `frontend/README.md`。
43
+
44
+ 控制台工作目录只保存必要关联与固定重试产物,不另存 Hub 资源或 Server 调度状态。管理令牌在浏览器内存中使用,密钥通过独立受控接口进入已有 Worker 凭据文件;未启用管理配置时保留原简易任务接口语义。HTTP 的成功回执、真实业务终态和节点就绪分别查询。
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "uenv-bridge"
7
+ version = "0.2.1"
8
+ description = "Unified UEnv submission client"
9
+ requires-python = ">=3.11"
10
+ dependencies = ["uenv-sdk[grpc]==0.1.0", "grpcio>=1.80,<2", "PyYAML>=6,<7", "aiohttp>=3.12,<4"]
11
+
12
+ readme = { text = "UEnv client for evaluation, trajectory collection, environment publishing and training integration. Install with `python -m pip install -U uenv-bridge`, then run `uenv --help`. For local training, install in your existing PyTorch, VeRL and vLLM environment. GPU training frameworks and model weights are prepared separately. Documentation: https://uenv.io", content-type = "text/markdown" }
13
+
14
+ [project.urls]
15
+ Documentation = "https://uenv.io"
16
+ Repository = "https://github.com/audreyyan1015/uenv_refactor"
17
+
18
+ [project.optional-dependencies]
19
+ # Empty aliases keep existing released installers working. New installs use the base package.
20
+ web = []
21
+ training = []
22
+
23
+ [project.scripts]
24
+ uenv = "uenv.bridge.commands:main"
25
+ uenv-bridge = "uenv.bridge.cli:main"
26
+ uenv-web = "uenv.bridge.web:main"
27
+ uenv-evaluate = "uenv.bridge.cli:main"
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["src"]
31
+
32
+ [tool.setuptools.package-data]
33
+ "uenv.bridge" = ["web_assets/*"]
34
+ "uenv.bridge.integrations.verl" = ["compat.json", "recipes/*.yaml"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,4 @@
1
+ """The CLI and framework integrations share UEnvClient's submission boundary."""
2
+ from .client import UEnvClient
3
+
4
+ __all__ = ["UEnvClient"]
@@ -0,0 +1,43 @@
1
+ """Authorize existing Hub reads before the trusted preparation pipeline uses them."""
2
+ from uenv.sdk.hub import HubClient
3
+
4
+
5
+ class AuthorizedHub(HubClient):
6
+ def __init__(self, hub, policy, principal, *, permission='execute'):
7
+ super().__init__(hub.origin.geturl())
8
+ self.hub, self.policy, self.principal, self.permission = hub, policy, principal, permission
9
+ self.origin, self.cache = hub.origin, None
10
+
11
+ def require(self, kind, ref):
12
+ return self.policy.require(self.principal, kind, ref['id'],
13
+ ref['revision' if kind == 'data' else 'version'], permission=self.permission)
14
+
15
+ def package(self, ref):
16
+ self.require('package',ref)
17
+ return self.hub.package(ref)
18
+
19
+ def data(self, ref):
20
+ self.require('data',ref)
21
+ result = self.hub.data(ref)
22
+ self.require('package',result['dataset_package'])
23
+ return result
24
+
25
+ def dataset_release(self, ref):
26
+ self.data(ref)
27
+ return self.hub.dataset_release(ref)
28
+
29
+ def samples(self, dataset, **kwargs):
30
+ self.data(dataset)
31
+ return self.hub.samples(dataset, **kwargs)
32
+
33
+ def iter_samples(self, dataset, **kwargs):
34
+ self.data(dataset)
35
+ return self.hub.iter_samples(dataset, **kwargs)
36
+
37
+ def _cached_file(self, query):
38
+ self.require('package' if 'package' in query else 'data', query.get('package',query.get('dataset')))
39
+ return self.hub._cached_file(query)
40
+
41
+ def cached_data_file(self, manifest, ref):
42
+ self.data(manifest['dataset'])
43
+ return self.hub.cached_data_file(manifest,ref)
@@ -0,0 +1,294 @@
1
+ """Load files, then call the same UEnvClient methods as Python integrations."""
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from uenv.sdk import SchemaRegistry
9
+ from uenv.sdk.package_loader import load_yaml
10
+ from .client import UEnvClient
11
+ from .client_settings import load_client_settings
12
+
13
+
14
+ def main(argv=None):
15
+ parser = argparse.ArgumentParser(description="Submit and manage unified UEnv runs")
16
+ parser.add_argument("--config", type=Path, help="Client connection YAML")
17
+ parser.add_argument("--endpoint")
18
+ parser.add_argument("--direct", action="store_true", help="Explicit legacy caller-owned submission; --wait owns its window")
19
+ action = parser.add_mutually_exclusive_group(required=True)
20
+ action.add_argument("--run", type=Path)
21
+ action.add_argument("--retry-submission", metavar="SUBMISSION_ID", help="Retry the saved request without replacing its configuration")
22
+ action.add_argument(
23
+ "--status", metavar="RUN_ID", help="Read current run state counts"
24
+ )
25
+ action.add_argument(
26
+ "--cancel-run",
27
+ metavar="RUN_ID",
28
+ help="Cancel the run and reject later new batches",
29
+ )
30
+ action.add_argument(
31
+ "--upload-file",
32
+ type=Path,
33
+ help="Upload task material using the same UEnvClient.upload_file API",
34
+ )
35
+ parser.add_argument(
36
+ "--media-type",
37
+ help="Uploaded file media type; default application/octet-stream",
38
+ )
39
+ source = parser.add_mutually_exclusive_group()
40
+ source.add_argument("--samples", type=Path)
41
+ source.add_argument(
42
+ "--hub-selection",
43
+ type=Path,
44
+ help="Deprecated: HubSampleQuery file; put dataset in --run instead",
45
+ )
46
+ parser.add_argument(
47
+ "--hub-endpoint", help="Hub origin"
48
+ )
49
+ parser.add_argument(
50
+ "--raw-package",
51
+ type=Path,
52
+ help="Trusted selected dataset package; read and normalize the package source format before submission",
53
+ )
54
+ parser.add_argument(
55
+ "--dataset",
56
+ type=Path,
57
+ help="Deprecated: data identity file for --raw-package; put dataset in --run instead",
58
+ )
59
+ parser.add_argument("--wait", action="store_true")
60
+ parser.add_argument("--output", type=Path, help="Write unchanged EpisodeResult JSONL; requires --wait")
61
+ parser.add_argument("--batch-size", type=int, help="Maximum submitted episodes awaiting results")
62
+ parser.add_argument("--name", default="", help="Display name for a managed run")
63
+ parser.add_argument("--id", help="Stable idempotency key for a managed Hub run; reuse after a lost HTTP reply")
64
+ args = parser.parse_args(argv)
65
+ if args.name and (not args.run or args.direct):
66
+ parser.error("--name requires a managed --run")
67
+ if len(args.name) > 200:
68
+ parser.error("--name must be at most 200 characters")
69
+ if args.id and (not args.run or args.direct):
70
+ parser.error("--id requires a managed --run")
71
+ if args.output is not None and not ((args.run or args.retry_submission) and args.wait):
72
+ parser.error("--output requires --run and --wait")
73
+ if args.batch_size is not None and (not args.run or (args.direct and not args.wait)):
74
+ parser.error("--batch-size requires --run; --direct also requires --wait")
75
+ if args.batch_size is not None and args.batch_size < 1:
76
+ parser.error("--batch-size must be positive")
77
+ try:
78
+ connection = load_client_settings(args.config, server=args.endpoint, hub=args.hub_endpoint,
79
+ require_hub=bool(args.run), allow_platform=bool((args.status or args.cancel_run or args.run) and not args.direct))
80
+ except ValueError as error:
81
+ parser.error(str(error))
82
+ args.endpoint = connection.server
83
+ if args.run and not args.direct and not connection.management:
84
+ parser.error("Managed runs require management in client.yaml; --direct explicitly selects caller-owned submission")
85
+ def observe_operation(manager, operation, *, stop_event=None):
86
+ print(json.dumps(operation, ensure_ascii=False), file=sys.stderr if args.wait else sys.stdout, flush=True)
87
+ if args.wait:
88
+ from .evaluation import observe_run
89
+ run_id = manager.wait_submission(operation,stop_event=stop_event)
90
+ summary = observe_run(manager, run_id, output=args.output,stop_event=stop_event)
91
+ print(json.dumps(summary, ensure_ascii=False), file=sys.stderr)
92
+ return summary["exit_code"]
93
+ return 0
94
+
95
+ if args.retry_submission:
96
+ if args.direct or not connection.management or any((args.samples, args.hub_selection, args.raw_package, args.dataset, args.media_type, args.hub_endpoint)):
97
+ parser.error("--retry-submission requires management and takes no replacement task or execution parameters")
98
+ from .management_gateway import ManagementGatewayClient
99
+ manager = ManagementGatewayClient(connection.management, token_file=connection.management_token_file)
100
+ return observe_operation(manager, manager.submission(args.retry_submission, retry=True))
101
+ if args.status is not None or args.cancel_run is not None:
102
+ if any(
103
+ (
104
+ args.samples,
105
+ args.hub_selection,
106
+ args.hub_endpoint,
107
+ args.raw_package,
108
+ args.dataset,
109
+ args.wait,
110
+ args.media_type,
111
+ )
112
+ ):
113
+ parser.error(
114
+ "Run management cannot be combined with submission or upload arguments"
115
+ )
116
+ if connection.management and not args.direct:
117
+ from .management_gateway import ManagementGatewayClient
118
+ manager = ManagementGatewayClient(connection.management, token_file=connection.management_token_file)
119
+ result = manager.run_status(args.status) if args.status is not None else manager.management.stop("run", args.cancel_run)
120
+ print(json.dumps(result, ensure_ascii=False))
121
+ return
122
+ with UEnvClient(args.endpoint) as client:
123
+ result = (
124
+ client.run_status(args.status)
125
+ if args.status is not None
126
+ else (client.cancel_run(args.cancel_run) if args.direct
127
+ else client.management.stop("run", args.cancel_run))
128
+ )
129
+ print(json.dumps(result, ensure_ascii=False))
130
+ return
131
+ if args.upload_file:
132
+ if any(
133
+ (
134
+ args.samples,
135
+ args.hub_selection,
136
+ args.hub_endpoint,
137
+ args.raw_package,
138
+ args.dataset,
139
+ args.wait,
140
+ )
141
+ ):
142
+ parser.error(
143
+ "--upload-file cannot be combined with task submission arguments"
144
+ )
145
+ with UEnvClient(args.endpoint) as client:
146
+ print(
147
+ json.dumps(
148
+ client.upload_file(
149
+ args.upload_file,
150
+ media_type=args.media_type or "application/octet-stream",
151
+ ),
152
+ ensure_ascii=False,
153
+ )
154
+ )
155
+ return
156
+ if args.media_type:
157
+ parser.error("--media-type is only valid with --upload-file")
158
+ run = load_yaml(args.run)
159
+ inline_dataset = isinstance(run, dict) and "dataset" in run
160
+ if args.hub_selection and inline_dataset:
161
+ parser.error("--hub-selection conflicts with dataset in --run")
162
+ if args.dataset and inline_dataset:
163
+ parser.error("--dataset conflicts with dataset in --run")
164
+ if args.dataset and not args.raw_package:
165
+ parser.error("--dataset requires --raw-package")
166
+ if args.raw_package and not (args.dataset or inline_dataset):
167
+ parser.error("--raw-package requires dataset in --run (or legacy --dataset)")
168
+ if args.hub_selection and args.raw_package:
169
+ parser.error("Hub rows are already normalized; --raw-package is not applicable")
170
+ embedded_hub = inline_dataset and not args.raw_package
171
+ if embedded_hub and args.samples:
172
+ parser.error("dataset in --run cannot be combined with --samples unless --raw-package is used")
173
+ if not args.direct and embedded_hub:
174
+ from uuid import uuid4
175
+ from .management_gateway import ManagementGatewayClient
176
+ identifier = args.id or str(uuid4())
177
+ # Print the retry key before HTTP, including when its acknowledgement is lost.
178
+ print(json.dumps({"submission_key": identifier}), file=sys.stderr, flush=True)
179
+ manager = ManagementGatewayClient(connection.management, token_file=connection.management_token_file)
180
+ if connection.platform:
181
+ if not args.wait:
182
+ parser.error("Platform local models require --wait to keep the outbound model session alive")
183
+ if run.get("model",{}).get("credential_ref"):
184
+ parser.error("The local model session does not use platform credential references")
185
+ import asyncio
186
+ from .model_sessions import OutboundModelSession
187
+ async def connected():
188
+ import threading
189
+ stop = threading.Event()
190
+ operation = None
191
+ async with OutboundModelSession(manager,run["model"]["endpoint"]) as session:
192
+ try:
193
+ operation = await asyncio.to_thread(manager.submit_run,run,identifier=identifier,
194
+ name=args.name,batch_size=args.batch_size or 100,model_session_id=session.descriptor["session_id"])
195
+ return await session.wait(asyncio.to_thread(observe_operation,manager,operation,stop_event=stop))
196
+ except BaseException as error:
197
+ stop.set()
198
+ if operation is not None:
199
+ try:
200
+ await asyncio.to_thread(manager.management.stop,'run',operation['run_id'])
201
+ except Exception as cancellation:
202
+ error.add_note('Run cancellation not confirmed: '+type(cancellation).__name__)
203
+ raise
204
+ return asyncio.run(connected())
205
+ return observe_operation(manager, manager.submit_run(run, identifier=identifier, name=args.name, batch_size=args.batch_size or 100))
206
+ if args.id:
207
+ parser.error("--id requires a managed Hub dataset selection")
208
+ hub_endpoint = connection.hub
209
+ if not hub_endpoint:
210
+ parser.error("Task preparation requires a Hub address")
211
+ if not (args.samples or args.hub_selection or embedded_hub):
212
+ parser.error("--run requires an inline Hub dataset or --samples")
213
+ registry = SchemaRegistry.bundled()
214
+ from uenv.sdk.hub import HubClient
215
+ hub = HubClient(hub_endpoint)
216
+ samples = (
217
+ args.samples
218
+ if args.raw_package
219
+ else [
220
+ json.loads(line)
221
+ for line in args.samples.read_text(encoding="utf-8").splitlines()
222
+ if line.strip()
223
+ ]
224
+ if args.samples
225
+ else None
226
+ )
227
+ with UEnvClient(
228
+ args.endpoint,
229
+
230
+ registry=registry,
231
+ hub=hub if not (args.hub_selection or embedded_hub) else None,
232
+ ) as client:
233
+ if args.hub_selection or embedded_hub:
234
+ if args.hub_selection:
235
+ selection = load_yaml(args.hub_selection)
236
+ registry.validate("HubSampleQuery", selection)
237
+ print(
238
+ "warning: --hub-selection is deprecated; put dataset in --run",
239
+ file=sys.stderr,
240
+ )
241
+ prepared = client.prepare_hub(run, hub=hub, **selection)
242
+ else:
243
+ prepared = client.prepare_hub(run, hub=hub)
244
+ else:
245
+ if args.dataset:
246
+ print(
247
+ "warning: --dataset is deprecated; put dataset in --run",
248
+ file=sys.stderr,
249
+ )
250
+ prepared = (
251
+ client.prepare_raw(
252
+ run,
253
+ samples,
254
+ package_directory=args.raw_package,
255
+ **(
256
+ {"dataset": load_yaml(args.dataset)}
257
+ if args.dataset
258
+ else {}
259
+ ),
260
+ )
261
+ if args.raw_package
262
+ else client.prepare(run, samples)
263
+ )
264
+ def print_receipt(receipt):
265
+ print(
266
+ json.dumps(
267
+ {"run_id": prepared["run_spec"]["run_id"], "receipt": receipt},
268
+ ensure_ascii=False,
269
+ ),
270
+ file=sys.stderr if args.wait else sys.stdout,
271
+ flush=True,
272
+ )
273
+
274
+ if not args.direct:
275
+ from .management_gateway import ManagementGatewayClient
276
+ from .evaluation import observe_prepared
277
+ manager = ManagementGatewayClient(connection.management, token_file=connection.management_token_file, registry=client.registry)
278
+ operation = manager.submit_prepared(prepared, batch_size=args.batch_size or 100, name=args.name)
279
+ print(json.dumps(operation, ensure_ascii=False), file=sys.stderr if args.wait else sys.stdout, flush=True)
280
+ if args.wait:
281
+ summary = observe_prepared(manager, prepared, output=args.output)
282
+ print(json.dumps(summary, ensure_ascii=False), file=sys.stderr)
283
+ return summary["exit_code"]
284
+ return 0
285
+ if args.wait:
286
+ summary = client.evaluate_prepared(prepared, batch_size=args.batch_size or 100,
287
+ output=args.output, on_submitted=print_receipt)
288
+ print(json.dumps(summary, ensure_ascii=False), file=sys.stderr)
289
+ return summary["exit_code"]
290
+ print_receipt(client.submit_prepared(prepared))
291
+
292
+
293
+ if __name__ == "__main__":
294
+ raise SystemExit(main())