nemo-platform-plugin 0.1.0__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.
Files changed (1224) hide show
  1. nemo_platform/__init__.py +117 -0
  2. nemo_platform/_base_client.py +2146 -0
  3. nemo_platform/_client.py +1200 -0
  4. nemo_platform/_compat.py +241 -0
  5. nemo_platform/_constants.py +29 -0
  6. nemo_platform/_decoders/jsonl.py +138 -0
  7. nemo_platform/_exceptions.py +123 -0
  8. nemo_platform/_files.py +188 -0
  9. nemo_platform/_models.py +967 -0
  10. nemo_platform/_qs.py +164 -0
  11. nemo_platform/_resource.py +58 -0
  12. nemo_platform/_response.py +872 -0
  13. nemo_platform/_streaming.py +391 -0
  14. nemo_platform/_types.py +288 -0
  15. nemo_platform/_utils/__init__.py +79 -0
  16. nemo_platform/_utils/_compat.py +60 -0
  17. nemo_platform/_utils/_datetime_parse.py +151 -0
  18. nemo_platform/_utils/_json.py +50 -0
  19. nemo_platform/_utils/_logs.py +40 -0
  20. nemo_platform/_utils/_path.py +142 -0
  21. nemo_platform/_utils/_proxy.py +80 -0
  22. nemo_platform/_utils/_reflection.py +57 -0
  23. nemo_platform/_utils/_resources_proxy.py +39 -0
  24. nemo_platform/_utils/_streams.py +27 -0
  25. nemo_platform/_utils/_sync.py +73 -0
  26. nemo_platform/_utils/_transform.py +472 -0
  27. nemo_platform/_utils/_typing.py +171 -0
  28. nemo_platform/_utils/_utils.py +448 -0
  29. nemo_platform/_version.py +21 -0
  30. nemo_platform/auth/__init__.py +15 -0
  31. nemo_platform/auth/device_flow.py +303 -0
  32. nemo_platform/auth/helpers.py +211 -0
  33. nemo_platform/auth/token_provider.py +239 -0
  34. nemo_platform/beta/evaluator/__init__.py +120 -0
  35. nemo_platform/beta/evaluator/agent_inference.py +360 -0
  36. nemo_platform/beta/evaluator/constants.py +4 -0
  37. nemo_platform/beta/evaluator/dataset_schemas/common.py +177 -0
  38. nemo_platform/beta/evaluator/dataset_schemas/compatibility.py +353 -0
  39. nemo_platform/beta/evaluator/dataset_schemas/templates.py +389 -0
  40. nemo_platform/beta/evaluator/datasets/__init__.py +28 -0
  41. nemo_platform/beta/evaluator/datasets/loader.py +415 -0
  42. nemo_platform/beta/evaluator/enums.py +64 -0
  43. nemo_platform/beta/evaluator/execution/_protocols.py +20 -0
  44. nemo_platform/beta/evaluator/execution/backends/base.py +86 -0
  45. nemo_platform/beta/evaluator/execution/backends/local/backend.py +132 -0
  46. nemo_platform/beta/evaluator/execution/benchmark_execution.py +666 -0
  47. nemo_platform/beta/evaluator/execution/config.py +64 -0
  48. nemo_platform/beta/evaluator/execution/evaluator.py +289 -0
  49. nemo_platform/beta/evaluator/execution/job_poll.py +98 -0
  50. nemo_platform/beta/evaluator/execution/metric_execution.py +878 -0
  51. nemo_platform/beta/evaluator/execution/pipeline.py +64 -0
  52. nemo_platform/beta/evaluator/execution/runs.py +143 -0
  53. nemo_platform/beta/evaluator/execution/scoring.py +224 -0
  54. nemo_platform/beta/evaluator/execution/utils.py +116 -0
  55. nemo_platform/beta/evaluator/execution/values.py +53 -0
  56. nemo_platform/beta/evaluator/inference.py +456 -0
  57. nemo_platform/beta/evaluator/metrics/aggregation.py +451 -0
  58. nemo_platform/beta/evaluator/metrics/bleu.py +94 -0
  59. nemo_platform/beta/evaluator/metrics/exact_match.py +52 -0
  60. nemo_platform/beta/evaluator/metrics/f1.py +50 -0
  61. nemo_platform/beta/evaluator/metrics/hooks.py +41 -0
  62. nemo_platform/beta/evaluator/metrics/llm_judge.py +392 -0
  63. nemo_platform/beta/evaluator/metrics/number_check.py +95 -0
  64. nemo_platform/beta/evaluator/metrics/protocol.py +241 -0
  65. nemo_platform/beta/evaluator/metrics/ragas/__init__.py +41 -0
  66. nemo_platform/beta/evaluator/metrics/ragas/base.py +521 -0
  67. nemo_platform/beta/evaluator/metrics/ragas/git_patch.py +36 -0
  68. nemo_platform/beta/evaluator/metrics/ragas/imports.py +192 -0
  69. nemo_platform/beta/evaluator/metrics/ragas/metrics.py +183 -0
  70. nemo_platform/beta/evaluator/metrics/remote.py +250 -0
  71. nemo_platform/beta/evaluator/metrics/rouge.py +71 -0
  72. nemo_platform/beta/evaluator/metrics/string_check.py +69 -0
  73. nemo_platform/beta/evaluator/metrics/template_rendering.py +141 -0
  74. nemo_platform/beta/evaluator/metrics/tool_calling.py +173 -0
  75. nemo_platform/beta/evaluator/metrics/types.py +62 -0
  76. nemo_platform/beta/evaluator/metrics/utils.py +54 -0
  77. nemo_platform/beta/evaluator/resilience/api.py +142 -0
  78. nemo_platform/beta/evaluator/resilience/classifier.py +142 -0
  79. nemo_platform/beta/evaluator/resilience/config.py +69 -0
  80. nemo_platform/beta/evaluator/resilience/errors.py +117 -0
  81. nemo_platform/beta/evaluator/resilience/policy.py +50 -0
  82. nemo_platform/beta/evaluator/resilience/scheduler.py +459 -0
  83. nemo_platform/beta/evaluator/resilience/types.py +93 -0
  84. nemo_platform/beta/evaluator/structured_output.py +184 -0
  85. nemo_platform/beta/evaluator/templates.py +115 -0
  86. nemo_platform/beta/evaluator/values/__init__.py +162 -0
  87. nemo_platform/beta/evaluator/values/agents.py +84 -0
  88. nemo_platform/beta/evaluator/values/common.py +28 -0
  89. nemo_platform/beta/evaluator/values/dataset_schemas.py +112 -0
  90. nemo_platform/beta/evaluator/values/datasets.py +28 -0
  91. nemo_platform/beta/evaluator/values/metrics.py +587 -0
  92. nemo_platform/beta/evaluator/values/models.py +157 -0
  93. nemo_platform/beta/evaluator/values/multi_metric_results.py +359 -0
  94. nemo_platform/beta/evaluator/values/params.py +109 -0
  95. nemo_platform/beta/evaluator/values/results.py +699 -0
  96. nemo_platform/beta/evaluator/values/scores.py +300 -0
  97. nemo_platform/beta/safe_synthesizer/__init__.py +4 -0
  98. nemo_platform/beta/safe_synthesizer/config.py +29 -0
  99. nemo_platform/beta/safe_synthesizer/job.py +309 -0
  100. nemo_platform/beta/safe_synthesizer/job_builder.py +355 -0
  101. nemo_platform/cli/__init__.py +4 -0
  102. nemo_platform/cli/app.py +321 -0
  103. nemo_platform/cli/commands/__init__.py +15 -0
  104. nemo_platform/cli/commands/api/__init__.py +114 -0
  105. nemo_platform/cli/commands/api/adapters.py +384 -0
  106. nemo_platform/cli/commands/api/files/__init__.py +237 -0
  107. nemo_platform/cli/commands/api/files/filesets.py +386 -0
  108. nemo_platform/cli/commands/api/files/otlp/__init__.py +12 -0
  109. nemo_platform/cli/commands/api/files/otlp/logs.py +116 -0
  110. nemo_platform/cli/commands/api/guardrail/__init__.py +270 -0
  111. nemo_platform/cli/commands/api/guardrail/configs.py +311 -0
  112. nemo_platform/cli/commands/api/iam/__init__.py +12 -0
  113. nemo_platform/cli/commands/api/iam/role_bindings.py +264 -0
  114. nemo_platform/cli/commands/api/inference/__init__.py +76 -0
  115. nemo_platform/cli/commands/api/inference/deployment_configs/__init__.py +370 -0
  116. nemo_platform/cli/commands/api/inference/deployment_configs/versions.py +132 -0
  117. nemo_platform/cli/commands/api/inference/deployments/__init__.py +565 -0
  118. nemo_platform/cli/commands/api/inference/deployments/versions.py +141 -0
  119. nemo_platform/cli/commands/api/inference/gateway/__init__.py +14 -0
  120. nemo_platform/cli/commands/api/inference/gateway/model.py +324 -0
  121. nemo_platform/cli/commands/api/inference/gateway/openai/__init__.py +12 -0
  122. nemo_platform/cli/commands/api/inference/gateway/openai/v1/__init__.py +12 -0
  123. nemo_platform/cli/commands/api/inference/gateway/openai/v1/models.py +106 -0
  124. nemo_platform/cli/commands/api/inference/gateway/provider.py +327 -0
  125. nemo_platform/cli/commands/api/inference/models.py +106 -0
  126. nemo_platform/cli/commands/api/inference/providers.py +612 -0
  127. nemo_platform/cli/commands/api/inference/virtual_models.py +412 -0
  128. nemo_platform/cli/commands/api/intake/__init__.py +18 -0
  129. nemo_platform/cli/commands/api/intake/apps/__init__.py +326 -0
  130. nemo_platform/cli/commands/api/intake/apps/tasks.py +340 -0
  131. nemo_platform/cli/commands/api/intake/entries/__init__.py +445 -0
  132. nemo_platform/cli/commands/api/intake/entries/events.py +118 -0
  133. nemo_platform/cli/commands/api/intake/evaluator_results.py +267 -0
  134. nemo_platform/cli/commands/api/intake/exports/__init__.py +63 -0
  135. nemo_platform/cli/commands/api/intake/exports/jobs.py +245 -0
  136. nemo_platform/cli/commands/api/intake/ingest/__init__.py +14 -0
  137. nemo_platform/cli/commands/api/intake/ingest/atif.py +115 -0
  138. nemo_platform/cli/commands/api/intake/ingest/chat_completions.py +125 -0
  139. nemo_platform/cli/commands/api/intake/ingest/otlp/__init__.py +12 -0
  140. nemo_platform/cli/commands/api/intake/ingest/otlp/v1/__init__.py +12 -0
  141. nemo_platform/cli/commands/api/intake/ingest/otlp/v1/traces.py +72 -0
  142. nemo_platform/cli/commands/api/intake/spans/__init__.py +202 -0
  143. nemo_platform/cli/commands/api/intake/spans/evaluator_results.py +65 -0
  144. nemo_platform/cli/commands/api/intake/traces.py +183 -0
  145. nemo_platform/cli/commands/api/jobs/__init__.py +576 -0
  146. nemo_platform/cli/commands/api/jobs/results.py +211 -0
  147. nemo_platform/cli/commands/api/jobs/steps.py +243 -0
  148. nemo_platform/cli/commands/api/jobs/tasks.py +210 -0
  149. nemo_platform/cli/commands/api/members.py +304 -0
  150. nemo_platform/cli/commands/api/models/__init__.py +555 -0
  151. nemo_platform/cli/commands/api/models/adapters.py +261 -0
  152. nemo_platform/cli/commands/api/projects.py +332 -0
  153. nemo_platform/cli/commands/api/safe_synthesizer/__init__.py +12 -0
  154. nemo_platform/cli/commands/api/safe_synthesizer/jobs/__init__.py +417 -0
  155. nemo_platform/cli/commands/api/safe_synthesizer/jobs/results.py +211 -0
  156. nemo_platform/cli/commands/api/secrets/__init__.py +315 -0
  157. nemo_platform/cli/commands/api/secrets/admin.py +44 -0
  158. nemo_platform/cli/commands/api/workspaces.py +339 -0
  159. nemo_platform/cli/commands/auth.py +803 -0
  160. nemo_platform/cli/commands/config.py +308 -0
  161. nemo_platform/cli/commands/docs.py +277 -0
  162. nemo_platform/cli/commands/manifest_registry.py +180 -0
  163. nemo_platform/cli/commands/plugins.py +87 -0
  164. nemo_platform/cli/commands/quickstart/__init__.py +15 -0
  165. nemo_platform/cli/commands/quickstart/cli.py +1178 -0
  166. nemo_platform/cli/commands/services/_process.py +472 -0
  167. nemo_platform/cli/commands/services/cli.py +694 -0
  168. nemo_platform/cli/commands/setup.py +1947 -0
  169. nemo_platform/cli/commands/skills/agents/claude.py +29 -0
  170. nemo_platform/cli/commands/skills/agents/codex.py +32 -0
  171. nemo_platform/cli/commands/skills/agents/cursor.py +18 -0
  172. nemo_platform/cli/commands/skills/agents/opencode.py +20 -0
  173. nemo_platform/cli/commands/skills/base.py +53 -0
  174. nemo_platform/cli/commands/skills/cli.py +313 -0
  175. nemo_platform/cli/commands/skills/installer.py +51 -0
  176. nemo_platform/cli/commands/skills/registry.py +396 -0
  177. nemo_platform/cli/commands/use_cases/__init__.py +15 -0
  178. nemo_platform/cli/commands/use_cases/agent.py +245 -0
  179. nemo_platform/cli/commands/use_cases/chat.py +965 -0
  180. nemo_platform/cli/commands/use_cases/wait.py +151 -0
  181. nemo_platform/cli/core/__init__.py +8 -0
  182. nemo_platform/cli/core/agent_helpers.py +84 -0
  183. nemo_platform/cli/core/api.py +160 -0
  184. nemo_platform/cli/core/autocomplete.py +63 -0
  185. nemo_platform/cli/core/code_generator.py +306 -0
  186. nemo_platform/cli/core/context.py +179 -0
  187. nemo_platform/cli/core/errors.py +349 -0
  188. nemo_platform/cli/core/formatters.py +718 -0
  189. nemo_platform/cli/core/help_formatter.py +868 -0
  190. nemo_platform/cli/core/lazy_load.py +187 -0
  191. nemo_platform/cli/core/logging.py +24 -0
  192. nemo_platform/cli/core/pagination.py +255 -0
  193. nemo_platform/cli/core/stdin_utils.py +233 -0
  194. nemo_platform/cli/core/streaming.py +30 -0
  195. nemo_platform/cli/core/table_config.py +302 -0
  196. nemo_platform/cli/core/timestamp_formatter.py +127 -0
  197. nemo_platform/cli/core/types.py +112 -0
  198. nemo_platform/cli/core/waiters.py +339 -0
  199. nemo_platform/cli/manifest.py +108 -0
  200. nemo_platform/client/__init__.py +15 -0
  201. nemo_platform/client/factory.py +597 -0
  202. nemo_platform/config/README.md +168 -0
  203. nemo_platform/config/__init__.py +23 -0
  204. nemo_platform/config/config.py +538 -0
  205. nemo_platform/config/models.py +377 -0
  206. nemo_platform/config/types.py +7 -0
  207. nemo_platform/filesets/__init__.py +19 -0
  208. nemo_platform/filesets/filesystem/callbacks.py +229 -0
  209. nemo_platform/filesets/filesystem/filesystem.py +940 -0
  210. nemo_platform/filesets/resources.py +1120 -0
  211. nemo_platform/lib/.keep +4 -0
  212. nemo_platform/models/__init__.py +14 -0
  213. nemo_platform/models/resources.py +836 -0
  214. nemo_platform/pagination.py +149 -0
  215. nemo_platform/py.typed +0 -0
  216. nemo_platform/quickstart/__init__.py +99 -0
  217. nemo_platform/quickstart/cluster.py +198 -0
  218. nemo_platform/quickstart/config.py +402 -0
  219. nemo_platform/quickstart/container.py +758 -0
  220. nemo_platform/quickstart/gpu_config.py +111 -0
  221. nemo_platform/quickstart/platform_config.py +82 -0
  222. nemo_platform/quickstart/preflight.py +451 -0
  223. nemo_platform/quickstart/prompts.py +426 -0
  224. nemo_platform/quickstart/storage.py +90 -0
  225. nemo_platform/quickstart/validators.py +268 -0
  226. nemo_platform/resources/__init__.py +16 -0
  227. nemo_platform/resources/adapters/__init__.py +34 -0
  228. nemo_platform/resources/adapters/adapters.py +704 -0
  229. nemo_platform/resources/adapters/api.md +15 -0
  230. nemo_platform/resources/audit/__init__.py +16 -0
  231. nemo_platform/resources/entities/__init__.py +34 -0
  232. nemo_platform/resources/entities/api.md +16 -0
  233. nemo_platform/resources/entities/entities.py +1014 -0
  234. nemo_platform/resources/evaluation/__init__.py +118 -0
  235. nemo_platform/resources/evaluation/api.md +303 -0
  236. nemo_platform/resources/evaluation/benchmark_job_results.py +541 -0
  237. nemo_platform/resources/evaluation/benchmark_jobs/__init__.py +48 -0
  238. nemo_platform/resources/evaluation/benchmark_jobs/benchmark_jobs.py +900 -0
  239. nemo_platform/resources/evaluation/benchmark_jobs/results/__init__.py +76 -0
  240. nemo_platform/resources/evaluation/benchmark_jobs/results/aggregate_scores.py +197 -0
  241. nemo_platform/resources/evaluation/benchmark_jobs/results/artifacts.py +206 -0
  242. nemo_platform/resources/evaluation/benchmark_jobs/results/results.py +516 -0
  243. nemo_platform/resources/evaluation/benchmark_jobs/results/row_scores.py +213 -0
  244. nemo_platform/resources/evaluation/benchmarks.py +690 -0
  245. nemo_platform/resources/evaluation/evaluation.py +277 -0
  246. nemo_platform/resources/evaluation/metric_job_results.py +533 -0
  247. nemo_platform/resources/evaluation/metric_jobs/__init__.py +48 -0
  248. nemo_platform/resources/evaluation/metric_jobs/metric_jobs.py +888 -0
  249. nemo_platform/resources/evaluation/metric_jobs/results/__init__.py +76 -0
  250. nemo_platform/resources/evaluation/metric_jobs/results/aggregate_scores.py +197 -0
  251. nemo_platform/resources/evaluation/metric_jobs/results/artifacts.py +206 -0
  252. nemo_platform/resources/evaluation/metric_jobs/results/results.py +512 -0
  253. nemo_platform/resources/evaluation/metric_jobs/results/row_scores.py +213 -0
  254. nemo_platform/resources/evaluation/metrics.py +3495 -0
  255. nemo_platform/resources/files/__init__.py +62 -0
  256. nemo_platform/resources/files/api.md +65 -0
  257. nemo_platform/resources/files/files.py +683 -0
  258. nemo_platform/resources/files/filesets.py +783 -0
  259. nemo_platform/resources/files/otlp/__init__.py +48 -0
  260. nemo_platform/resources/files/otlp/logs.py +337 -0
  261. nemo_platform/resources/files/otlp/otlp.py +117 -0
  262. nemo_platform/resources/guardrail/__init__.py +48 -0
  263. nemo_platform/resources/guardrail/api.md +116 -0
  264. nemo_platform/resources/guardrail/configs.py +679 -0
  265. nemo_platform/resources/guardrail/guardrail.py +463 -0
  266. nemo_platform/resources/iam/__init__.py +48 -0
  267. nemo_platform/resources/iam/api.md +22 -0
  268. nemo_platform/resources/iam/iam.py +117 -0
  269. nemo_platform/resources/iam/role_bindings.py +537 -0
  270. nemo_platform/resources/inference/__init__.py +118 -0
  271. nemo_platform/resources/inference/api.md +224 -0
  272. nemo_platform/resources/inference/deployment_configs/__init__.py +48 -0
  273. nemo_platform/resources/inference/deployment_configs/deployment_configs.py +756 -0
  274. nemo_platform/resources/inference/deployment_configs/versions.py +418 -0
  275. nemo_platform/resources/inference/deployments/__init__.py +48 -0
  276. nemo_platform/resources/inference/deployments/deployments.py +1017 -0
  277. nemo_platform/resources/inference/deployments/versions.py +434 -0
  278. nemo_platform/resources/inference/gateway/__init__.py +76 -0
  279. nemo_platform/resources/inference/gateway/gateway.py +181 -0
  280. nemo_platform/resources/inference/gateway/model.py +708 -0
  281. nemo_platform/resources/inference/gateway/openai/__init__.py +48 -0
  282. nemo_platform/resources/inference/gateway/openai/openai.py +700 -0
  283. nemo_platform/resources/inference/gateway/openai/v1/__init__.py +48 -0
  284. nemo_platform/resources/inference/gateway/openai/v1/models.py +290 -0
  285. nemo_platform/resources/inference/gateway/openai/v1/v1.py +117 -0
  286. nemo_platform/resources/inference/gateway/provider.py +749 -0
  287. nemo_platform/resources/inference/inference.py +277 -0
  288. nemo_platform/resources/inference/models.py +290 -0
  289. nemo_platform/resources/inference/providers.py +1049 -0
  290. nemo_platform/resources/inference/virtual_models.py +846 -0
  291. nemo_platform/resources/intake/__init__.py +132 -0
  292. nemo_platform/resources/intake/api.md +268 -0
  293. nemo_platform/resources/intake/apps/__init__.py +48 -0
  294. nemo_platform/resources/intake/apps/apps.py +718 -0
  295. nemo_platform/resources/intake/apps/tasks.py +731 -0
  296. nemo_platform/resources/intake/entries/__init__.py +48 -0
  297. nemo_platform/resources/intake/entries/entries.py +855 -0
  298. nemo_platform/resources/intake/entries/events.py +320 -0
  299. nemo_platform/resources/intake/evaluator_results.py +512 -0
  300. nemo_platform/resources/intake/exports/__init__.py +48 -0
  301. nemo_platform/resources/intake/exports/exports.py +229 -0
  302. nemo_platform/resources/intake/exports/jobs.py +464 -0
  303. nemo_platform/resources/intake/ingest/__init__.py +76 -0
  304. nemo_platform/resources/intake/ingest/atif.py +242 -0
  305. nemo_platform/resources/intake/ingest/chat_completions.py +270 -0
  306. nemo_platform/resources/intake/ingest/ingest.py +181 -0
  307. nemo_platform/resources/intake/ingest/otlp/__init__.py +48 -0
  308. nemo_platform/resources/intake/ingest/otlp/otlp.py +117 -0
  309. nemo_platform/resources/intake/ingest/otlp/v1/__init__.py +48 -0
  310. nemo_platform/resources/intake/ingest/otlp/v1/traces.py +183 -0
  311. nemo_platform/resources/intake/ingest/otlp/v1/v1.py +117 -0
  312. nemo_platform/resources/intake/intake.py +309 -0
  313. nemo_platform/resources/intake/spans/__init__.py +48 -0
  314. nemo_platform/resources/intake/spans/evaluator_results.py +197 -0
  315. nemo_platform/resources/intake/spans/spans.py +367 -0
  316. nemo_platform/resources/intake/traces.py +351 -0
  317. nemo_platform/resources/jobs/__init__.py +76 -0
  318. nemo_platform/resources/jobs/api.md +118 -0
  319. nemo_platform/resources/jobs/jobs.py +1300 -0
  320. nemo_platform/resources/jobs/results.py +555 -0
  321. nemo_platform/resources/jobs/steps.py +491 -0
  322. nemo_platform/resources/jobs/tasks.py +470 -0
  323. nemo_platform/resources/members/__init__.py +34 -0
  324. nemo_platform/resources/members/api.md +19 -0
  325. nemo_platform/resources/members/members.py +634 -0
  326. nemo_platform/resources/models/__init__.py +48 -0
  327. nemo_platform/resources/models/adapters.py +514 -0
  328. nemo_platform/resources/models/api.md +44 -0
  329. nemo_platform/resources/models/models.py +981 -0
  330. nemo_platform/resources/projects/__init__.py +34 -0
  331. nemo_platform/resources/projects/api.md +21 -0
  332. nemo_platform/resources/projects/projects.py +736 -0
  333. nemo_platform/resources/safe_synthesizer/__init__.py +48 -0
  334. nemo_platform/resources/safe_synthesizer/api.md +62 -0
  335. nemo_platform/resources/safe_synthesizer/jobs/__init__.py +48 -0
  336. nemo_platform/resources/safe_synthesizer/jobs/jobs.py +895 -0
  337. nemo_platform/resources/safe_synthesizer/jobs/results.py +819 -0
  338. nemo_platform/resources/safe_synthesizer/safe_synthesizer.py +117 -0
  339. nemo_platform/resources/secrets/__init__.py +48 -0
  340. nemo_platform/resources/secrets/admin.py +150 -0
  341. nemo_platform/resources/secrets/api.md +34 -0
  342. nemo_platform/resources/secrets/secrets.py +756 -0
  343. nemo_platform/resources/workspaces/__init__.py +34 -0
  344. nemo_platform/resources/workspaces/api.md +20 -0
  345. nemo_platform/resources/workspaces/workspaces.py +734 -0
  346. nemo_platform/skills/__init__.py +28 -0
  347. nemo_platform/skills/inference/SKILL.md +564 -0
  348. nemo_platform/skills/nemo-build-agent/SKILL.md +221 -0
  349. nemo_platform/skills/nemo-build-agent/references/templates/data-designer-config.py +80 -0
  350. nemo_platform/skills/nemo-evaluator/SKILL.md +140 -0
  351. nemo_platform/skills/nemo-explore/SKILL.md +70 -0
  352. nemo_platform/skills/nemo-files/SKILL.md +81 -0
  353. nemo_platform/skills/nemo-fine-tune/SKILL.md +43 -0
  354. nemo_platform/skills/nemo-guardrails/SKILL.md +519 -0
  355. nemo_platform/skills/nemo-secrets/SKILL.md +60 -0
  356. nemo_platform/skills/nemo-skill-selection/SKILL.md +146 -0
  357. nemo_platform/skills/nemo-spec/SKILL.md +76 -0
  358. nemo_platform/skills/nemo-spec/references/templates/agent-spec.md +68 -0
  359. nemo_platform/skills/nemo-status/SKILL.md +115 -0
  360. nemo_platform/skills/nemo-teardown/SKILL.md +185 -0
  361. nemo_platform/skills/nemo-try-agent/SKILL.md +102 -0
  362. nemo_platform/types/__init__.py +54 -0
  363. nemo_platform/types/adapters/__init__.py +24 -0
  364. nemo_platform/types/adapters/adapter_create_params.py +63 -0
  365. nemo_platform/types/adapters/adapter_entity_filter_param.py +56 -0
  366. nemo_platform/types/adapters/adapter_list_params.py +46 -0
  367. nemo_platform/types/adapters/adapter_patch_params.py +35 -0
  368. nemo_platform/types/adapters/adapters_page.py +37 -0
  369. nemo_platform/types/audit/__init__.py +18 -0
  370. nemo_platform/types/audit/jobs/__init__.py +18 -0
  371. nemo_platform/types/entities/__init__.py +26 -0
  372. nemo_platform/types/entities/entities_page.py +37 -0
  373. nemo_platform/types/entities/entity.py +63 -0
  374. nemo_platform/types/entities/entity_create_params.py +46 -0
  375. nemo_platform/types/entities/entity_delete_entity_by_name_params.py +31 -0
  376. nemo_platform/types/entities/entity_get_entity_by_name_params.py +31 -0
  377. nemo_platform/types/entities/entity_list_params.py +47 -0
  378. nemo_platform/types/entities/entity_update_entity_by_name_params.py +52 -0
  379. nemo_platform/types/evaluation/__init__.py +242 -0
  380. nemo_platform/types/evaluation/agent.py +68 -0
  381. nemo_platform/types/evaluation/agent_goal_accuracy_metric.py +92 -0
  382. nemo_platform/types/evaluation/agent_goal_accuracy_metric_param.py +69 -0
  383. nemo_platform/types/evaluation/agent_goal_accuracy_metric_param_param.py +70 -0
  384. nemo_platform/types/evaluation/agent_goal_accuracy_metric_response.py +88 -0
  385. nemo_platform/types/evaluation/agent_param.py +69 -0
  386. nemo_platform/types/evaluation/aggregate_range_score.py +65 -0
  387. nemo_platform/types/evaluation/aggregate_rubric_score.py +64 -0
  388. nemo_platform/types/evaluation/aggregated_metric_result.py +34 -0
  389. nemo_platform/types/evaluation/answer_accuracy_metric.py +89 -0
  390. nemo_platform/types/evaluation/answer_accuracy_metric_param.py +66 -0
  391. nemo_platform/types/evaluation/answer_accuracy_metric_param_param.py +67 -0
  392. nemo_platform/types/evaluation/answer_accuracy_metric_response.py +85 -0
  393. nemo_platform/types/evaluation/benchmark.py +81 -0
  394. nemo_platform/types/evaluation/benchmark_create_params.py +64 -0
  395. nemo_platform/types/evaluation/benchmark_create_response.py +26 -0
  396. nemo_platform/types/evaluation/benchmark_evaluation_job.py +75 -0
  397. nemo_platform/types/evaluation/benchmark_evaluation_jobs_list_filter_param.py +49 -0
  398. nemo_platform/types/evaluation/benchmark_evaluation_jobs_page.py +37 -0
  399. nemo_platform/types/evaluation/benchmark_evaluation_jobs_sort_field.py +22 -0
  400. nemo_platform/types/evaluation/benchmark_job_create_params.py +58 -0
  401. nemo_platform/types/evaluation/benchmark_job_get_logs_params.py +30 -0
  402. nemo_platform/types/evaluation/benchmark_job_list_params.py +44 -0
  403. nemo_platform/types/evaluation/benchmark_job_result.py +93 -0
  404. nemo_platform/types/evaluation/benchmark_job_result_list_params.py +116 -0
  405. nemo_platform/types/evaluation/benchmark_job_result_retrieve_params.py +50 -0
  406. nemo_platform/types/evaluation/benchmark_job_results_list_response.py +37 -0
  407. nemo_platform/types/evaluation/benchmark_jobs/__init__.py +18 -0
  408. nemo_platform/types/evaluation/benchmark_jobs/results/__init__.py +22 -0
  409. nemo_platform/types/evaluation/benchmark_jobs/results/benchmark_evaluation_result.py +30 -0
  410. nemo_platform/types/evaluation/benchmark_jobs/results/benchmark_metric_result.py +44 -0
  411. nemo_platform/types/evaluation/benchmark_jobs/results/row_score_download_params.py +28 -0
  412. nemo_platform/types/evaluation/benchmark_list_params.py +84 -0
  413. nemo_platform/types/evaluation/benchmark_offline_job.py +43 -0
  414. nemo_platform/types/evaluation/benchmark_offline_job_param.py +44 -0
  415. nemo_platform/types/evaluation/benchmark_online_agent_job.py +71 -0
  416. nemo_platform/types/evaluation/benchmark_online_agent_job_param.py +74 -0
  417. nemo_platform/types/evaluation/benchmark_online_job.py +66 -0
  418. nemo_platform/types/evaluation/benchmark_online_job_param.py +68 -0
  419. nemo_platform/types/evaluation/benchmark_ref.py +22 -0
  420. nemo_platform/types/evaluation/benchmark_retrieve_params.py +29 -0
  421. nemo_platform/types/evaluation/benchmark_retrieve_response.py +27 -0
  422. nemo_platform/types/evaluation/benchmarks_list_response.py +42 -0
  423. nemo_platform/types/evaluation/bleu_metric.py +76 -0
  424. nemo_platform/types/evaluation/bleu_metric_param.py +50 -0
  425. nemo_platform/types/evaluation/bleu_metric_param_param.py +52 -0
  426. nemo_platform/types/evaluation/bleu_metric_response.py +69 -0
  427. nemo_platform/types/evaluation/built_in_dataset.py +46 -0
  428. nemo_platform/types/evaluation/context_entity_recall_metric.py +89 -0
  429. nemo_platform/types/evaluation/context_entity_recall_metric_param.py +66 -0
  430. nemo_platform/types/evaluation/context_entity_recall_metric_param_param.py +67 -0
  431. nemo_platform/types/evaluation/context_entity_recall_metric_response.py +85 -0
  432. nemo_platform/types/evaluation/context_precision_metric.py +89 -0
  433. nemo_platform/types/evaluation/context_precision_metric_param.py +66 -0
  434. nemo_platform/types/evaluation/context_precision_metric_param_param.py +67 -0
  435. nemo_platform/types/evaluation/context_precision_metric_response.py +85 -0
  436. nemo_platform/types/evaluation/context_recall_metric.py +89 -0
  437. nemo_platform/types/evaluation/context_recall_metric_param.py +66 -0
  438. nemo_platform/types/evaluation/context_recall_metric_param_param.py +67 -0
  439. nemo_platform/types/evaluation/context_recall_metric_response.py +85 -0
  440. nemo_platform/types/evaluation/context_relevance_metric.py +89 -0
  441. nemo_platform/types/evaluation/context_relevance_metric_param.py +66 -0
  442. nemo_platform/types/evaluation/context_relevance_metric_param_param.py +67 -0
  443. nemo_platform/types/evaluation/context_relevance_metric_response.py +85 -0
  444. nemo_platform/types/evaluation/dataset_rows.py +35 -0
  445. nemo_platform/types/evaluation/dataset_rows_param.py +36 -0
  446. nemo_platform/types/evaluation/evaluate_dataset_rows_param.py +33 -0
  447. nemo_platform/types/evaluation/exact_match_metric.py +79 -0
  448. nemo_platform/types/evaluation/exact_match_metric_param.py +53 -0
  449. nemo_platform/types/evaluation/exact_match_metric_param_param.py +53 -0
  450. nemo_platform/types/evaluation/exact_match_metric_response.py +72 -0
  451. nemo_platform/types/evaluation/extended_benchmark.py +130 -0
  452. nemo_platform/types/evaluation/f1_metric.py +76 -0
  453. nemo_platform/types/evaluation/f1_metric_param.py +50 -0
  454. nemo_platform/types/evaluation/f1_metric_param_param.py +50 -0
  455. nemo_platform/types/evaluation/f1_metric_response.py +69 -0
  456. nemo_platform/types/evaluation/faithfulness_metric.py +89 -0
  457. nemo_platform/types/evaluation/faithfulness_metric_param.py +66 -0
  458. nemo_platform/types/evaluation/faithfulness_metric_param_param.py +67 -0
  459. nemo_platform/types/evaluation/faithfulness_metric_response.py +85 -0
  460. nemo_platform/types/evaluation/field_mapping.py +56 -0
  461. nemo_platform/types/evaluation/field_mapping_param.py +57 -0
  462. nemo_platform/types/evaluation/fileset.py +48 -0
  463. nemo_platform/types/evaluation/fileset_param.py +49 -0
  464. nemo_platform/types/evaluation/fileset_ref.py +22 -0
  465. nemo_platform/types/evaluation/histogram.py +30 -0
  466. nemo_platform/types/evaluation/histogram_bin.py +33 -0
  467. nemo_platform/types/evaluation/inference_params.py +65 -0
  468. nemo_platform/types/evaluation/inference_params_param.py +53 -0
  469. nemo_platform/types/evaluation/json_score_parser.py +35 -0
  470. nemo_platform/types/evaluation/json_score_parser_param.py +34 -0
  471. nemo_platform/types/evaluation/llm_judge_metric.py +126 -0
  472. nemo_platform/types/evaluation/llm_judge_metric_param.py +103 -0
  473. nemo_platform/types/evaluation/llm_judge_metric_param_param.py +105 -0
  474. nemo_platform/types/evaluation/llm_judge_metric_response.py +120 -0
  475. nemo_platform/types/evaluation/metric_create_params.py +959 -0
  476. nemo_platform/types/evaluation/metric_create_response.py +75 -0
  477. nemo_platform/types/evaluation/metric_evaluate_params.py +111 -0
  478. nemo_platform/types/evaluation/metric_evaluation_job.py +65 -0
  479. nemo_platform/types/evaluation/metric_evaluation_jobs_list_filter_param.py +49 -0
  480. nemo_platform/types/evaluation/metric_evaluation_jobs_page.py +37 -0
  481. nemo_platform/types/evaluation/metric_evaluation_jobs_sort_field.py +22 -0
  482. nemo_platform/types/evaluation/metric_evaluation_response.py +98 -0
  483. nemo_platform/types/evaluation/metric_evaluation_row_score.py +45 -0
  484. nemo_platform/types/evaluation/metric_job_create_params.py +48 -0
  485. nemo_platform/types/evaluation/metric_job_get_logs_params.py +30 -0
  486. nemo_platform/types/evaluation/metric_job_list_params.py +44 -0
  487. nemo_platform/types/evaluation/metric_job_result.py +93 -0
  488. nemo_platform/types/evaluation/metric_job_result_list_params.py +114 -0
  489. nemo_platform/types/evaluation/metric_job_result_retrieve_params.py +50 -0
  490. nemo_platform/types/evaluation/metric_job_results_list_response.py +37 -0
  491. nemo_platform/types/evaluation/metric_jobs/__init__.py +18 -0
  492. nemo_platform/types/evaluation/metric_jobs/results/__init__.py +20 -0
  493. nemo_platform/types/evaluation/metric_jobs/results/row_score_download_params.py +28 -0
  494. nemo_platform/types/evaluation/metric_list_params.py +73 -0
  495. nemo_platform/types/evaluation/metric_offline_job.py +106 -0
  496. nemo_platform/types/evaluation/metric_offline_job_param.py +107 -0
  497. nemo_platform/types/evaluation/metric_online_agent_job.py +133 -0
  498. nemo_platform/types/evaluation/metric_online_agent_job_param.py +135 -0
  499. nemo_platform/types/evaluation/metric_online_job.py +127 -0
  500. nemo_platform/types/evaluation/metric_online_job_param.py +129 -0
  501. nemo_platform/types/evaluation/metric_output.py +30 -0
  502. nemo_platform/types/evaluation/metric_ref.py +22 -0
  503. nemo_platform/types/evaluation/metric_retrieve_response.py +98 -0
  504. nemo_platform/types/evaluation/metric_retriever_job.py +64 -0
  505. nemo_platform/types/evaluation/metric_retriever_job_param.py +65 -0
  506. nemo_platform/types/evaluation/metric_type.py +47 -0
  507. nemo_platform/types/evaluation/metrics_list_response.py +90 -0
  508. nemo_platform/types/evaluation/model.py +44 -0
  509. nemo_platform/types/evaluation/model_param.py +44 -0
  510. nemo_platform/types/evaluation/model_ref.py +22 -0
  511. nemo_platform/types/evaluation/nemo_agent_toolkit_remote_metric.py +87 -0
  512. nemo_platform/types/evaluation/nemo_agent_toolkit_remote_metric_param.py +64 -0
  513. nemo_platform/types/evaluation/nemo_agent_toolkit_remote_metric_param_param.py +65 -0
  514. nemo_platform/types/evaluation/nemo_agent_toolkit_remote_metric_response.py +80 -0
  515. nemo_platform/types/evaluation/noise_sensitivity_metric.py +89 -0
  516. nemo_platform/types/evaluation/noise_sensitivity_metric_param.py +66 -0
  517. nemo_platform/types/evaluation/noise_sensitivity_metric_param_param.py +67 -0
  518. nemo_platform/types/evaluation/noise_sensitivity_metric_response.py +85 -0
  519. nemo_platform/types/evaluation/number_check_metric.py +104 -0
  520. nemo_platform/types/evaluation/number_check_metric_param.py +81 -0
  521. nemo_platform/types/evaluation/number_check_metric_param_param.py +83 -0
  522. nemo_platform/types/evaluation/number_check_metric_response.py +97 -0
  523. nemo_platform/types/evaluation/parameter.py +42 -0
  524. nemo_platform/types/evaluation/parameter_param.py +40 -0
  525. nemo_platform/types/evaluation/percentiles.py +54 -0
  526. nemo_platform/types/evaluation/range_score.py +56 -0
  527. nemo_platform/types/evaluation/range_score_param.py +57 -0
  528. nemo_platform/types/evaluation/reasoning_params.py +41 -0
  529. nemo_platform/types/evaluation/reasoning_params_param.py +41 -0
  530. nemo_platform/types/evaluation/regex_score_parser.py +38 -0
  531. nemo_platform/types/evaluation/regex_score_parser_param.py +37 -0
  532. nemo_platform/types/evaluation/remote_metric.py +91 -0
  533. nemo_platform/types/evaluation/remote_metric_param.py +68 -0
  534. nemo_platform/types/evaluation/remote_metric_param_param.py +69 -0
  535. nemo_platform/types/evaluation/remote_metric_response.py +84 -0
  536. nemo_platform/types/evaluation/remote_score.py +49 -0
  537. nemo_platform/types/evaluation/remote_score_param.py +50 -0
  538. nemo_platform/types/evaluation/response_groundedness_metric.py +89 -0
  539. nemo_platform/types/evaluation/response_groundedness_metric_param.py +66 -0
  540. nemo_platform/types/evaluation/response_groundedness_metric_param_param.py +67 -0
  541. nemo_platform/types/evaluation/response_groundedness_metric_response.py +85 -0
  542. nemo_platform/types/evaluation/response_relevancy_metric.py +95 -0
  543. nemo_platform/types/evaluation/response_relevancy_metric_param.py +74 -0
  544. nemo_platform/types/evaluation/response_relevancy_metric_param_param.py +75 -0
  545. nemo_platform/types/evaluation/response_relevancy_metric_response.py +93 -0
  546. nemo_platform/types/evaluation/retriever_pipeline.py +34 -0
  547. nemo_platform/types/evaluation/retriever_pipeline_param.py +35 -0
  548. nemo_platform/types/evaluation/rouge_metric.py +76 -0
  549. nemo_platform/types/evaluation/rouge_metric_param.py +53 -0
  550. nemo_platform/types/evaluation/rouge_metric_param_param.py +53 -0
  551. nemo_platform/types/evaluation/rouge_metric_response.py +69 -0
  552. nemo_platform/types/evaluation/row_score.py +59 -0
  553. nemo_platform/types/evaluation/rubric.py +40 -0
  554. nemo_platform/types/evaluation/rubric_param.py +40 -0
  555. nemo_platform/types/evaluation/rubric_score.py +54 -0
  556. nemo_platform/types/evaluation/rubric_score_param.py +55 -0
  557. nemo_platform/types/evaluation/rubric_score_stat.py +38 -0
  558. nemo_platform/types/evaluation/run_config.py +39 -0
  559. nemo_platform/types/evaluation/run_config_online.py +51 -0
  560. nemo_platform/types/evaluation/run_config_online_model.py +73 -0
  561. nemo_platform/types/evaluation/run_config_online_model_param.py +75 -0
  562. nemo_platform/types/evaluation/run_config_online_param.py +51 -0
  563. nemo_platform/types/evaluation/run_config_param.py +39 -0
  564. nemo_platform/types/evaluation/string_check_metric.py +82 -0
  565. nemo_platform/types/evaluation/string_check_metric_param.py +59 -0
  566. nemo_platform/types/evaluation/string_check_metric_param_param.py +61 -0
  567. nemo_platform/types/evaluation/string_check_metric_response.py +75 -0
  568. nemo_platform/types/evaluation/system_benchmark.py +71 -0
  569. nemo_platform/types/evaluation/system_benchmark_offline_job.py +58 -0
  570. nemo_platform/types/evaluation/system_benchmark_offline_job_param.py +60 -0
  571. nemo_platform/types/evaluation/system_benchmark_online_job.py +54 -0
  572. nemo_platform/types/evaluation/system_benchmark_online_job_param.py +55 -0
  573. nemo_platform/types/evaluation/system_metric.py +70 -0
  574. nemo_platform/types/evaluation/system_metric_param.py +50 -0
  575. nemo_platform/types/evaluation/system_metric_param_param.py +51 -0
  576. nemo_platform/types/evaluation/system_metric_response.py +66 -0
  577. nemo_platform/types/evaluation/tool_call_accuracy_metric.py +70 -0
  578. nemo_platform/types/evaluation/tool_call_accuracy_metric_param.py +44 -0
  579. nemo_platform/types/evaluation/tool_call_accuracy_metric_param_param.py +44 -0
  580. nemo_platform/types/evaluation/tool_call_accuracy_metric_response.py +63 -0
  581. nemo_platform/types/evaluation/tool_calling_metric.py +70 -0
  582. nemo_platform/types/evaluation/tool_calling_metric_param.py +47 -0
  583. nemo_platform/types/evaluation/tool_calling_metric_param_param.py +47 -0
  584. nemo_platform/types/evaluation/tool_calling_metric_response.py +63 -0
  585. nemo_platform/types/evaluation/topic_adherence_metric.py +92 -0
  586. nemo_platform/types/evaluation/topic_adherence_metric_param.py +69 -0
  587. nemo_platform/types/evaluation/topic_adherence_metric_param_param.py +70 -0
  588. nemo_platform/types/evaluation/topic_adherence_metric_response.py +88 -0
  589. nemo_platform/types/files/__init__.py +45 -0
  590. nemo_platform/types/files/cache_status.py +22 -0
  591. nemo_platform/types/files/dataset_metadata_content.py +46 -0
  592. nemo_platform/types/files/dataset_metadata_content_param.py +45 -0
  593. nemo_platform/types/files/file_list_files_params.py +35 -0
  594. nemo_platform/types/files/file_upload_file_params.py +28 -0
  595. nemo_platform/types/files/fileset.py +62 -0
  596. nemo_platform/types/files/fileset_create_params.py +74 -0
  597. nemo_platform/types/files/fileset_file.py +36 -0
  598. nemo_platform/types/files/fileset_filter_param.py +54 -0
  599. nemo_platform/types/files/fileset_list_params.py +47 -0
  600. nemo_platform/types/files/fileset_metadata_param.py +46 -0
  601. nemo_platform/types/files/fileset_metadata_param_param.py +47 -0
  602. nemo_platform/types/files/fileset_outputs_page.py +37 -0
  603. nemo_platform/types/files/fileset_purpose.py +22 -0
  604. nemo_platform/types/files/fileset_update_params.py +49 -0
  605. nemo_platform/types/files/huggingface_storage_config.py +60 -0
  606. nemo_platform/types/files/huggingface_storage_config_param.py +60 -0
  607. nemo_platform/types/files/list_fileset_files_response.py +27 -0
  608. nemo_platform/types/files/local_storage_config.py +39 -0
  609. nemo_platform/types/files/local_storage_config_param.py +38 -0
  610. nemo_platform/types/files/ngc_storage_config.py +66 -0
  611. nemo_platform/types/files/ngc_storage_config_param.py +66 -0
  612. nemo_platform/types/files/otlp/__init__.py +22 -0
  613. nemo_platform/types/files/otlp/log_query_params.py +36 -0
  614. nemo_platform/types/files/otlp/otel_export_logs_partial_success.py +34 -0
  615. nemo_platform/types/files/otlp/otel_export_logs_service_response.py +35 -0
  616. nemo_platform/types/files/s3_storage_config.py +85 -0
  617. nemo_platform/types/files/s3_storage_config_param.py +85 -0
  618. nemo_platform/types/files/secret_ref.py +22 -0
  619. nemo_platform/types/files/storage_config_type.py +22 -0
  620. nemo_platform/types/guardrail/__init__.py +165 -0
  621. nemo_platform/types/guardrail/action_rails.py +36 -0
  622. nemo_platform/types/guardrail/action_rails_param.py +38 -0
  623. nemo_platform/types/guardrail/activated_rail.py +61 -0
  624. nemo_platform/types/guardrail/ai_defense_rail_config.py +36 -0
  625. nemo_platform/types/guardrail/ai_defense_rail_config_param.py +36 -0
  626. nemo_platform/types/guardrail/auto_align_options.py +29 -0
  627. nemo_platform/types/guardrail/auto_align_options_param.py +30 -0
  628. nemo_platform/types/guardrail/auto_align_rail_config.py +35 -0
  629. nemo_platform/types/guardrail/auto_align_rail_config_param.py +37 -0
  630. nemo_platform/types/guardrail/cache_stats_config.py +32 -0
  631. nemo_platform/types/guardrail/cache_stats_config_param.py +32 -0
  632. nemo_platform/types/guardrail/chat_completion_assistant_message_param.py +45 -0
  633. nemo_platform/types/guardrail/chat_completion_content_part_image_param.py +34 -0
  634. nemo_platform/types/guardrail/chat_completion_content_part_text_param.py +32 -0
  635. nemo_platform/types/guardrail/chat_completion_function_message_param.py +35 -0
  636. nemo_platform/types/guardrail/chat_completion_message_tool_call_param.py +37 -0
  637. nemo_platform/types/guardrail/chat_completion_system_message_param.py +35 -0
  638. nemo_platform/types/guardrail/chat_completion_tool_message_param.py +35 -0
  639. nemo_platform/types/guardrail/chat_completion_user_message_param.py +41 -0
  640. nemo_platform/types/guardrail/clavata_rail_config.py +47 -0
  641. nemo_platform/types/guardrail/clavata_rail_config_param.py +48 -0
  642. nemo_platform/types/guardrail/clavata_rail_options.py +36 -0
  643. nemo_platform/types/guardrail/clavata_rail_options_param.py +38 -0
  644. nemo_platform/types/guardrail/config_create_params.py +36 -0
  645. nemo_platform/types/guardrail/config_list_params.py +47 -0
  646. nemo_platform/types/guardrail/config_update_params.py +33 -0
  647. nemo_platform/types/guardrail/content_safety_config.py +34 -0
  648. nemo_platform/types/guardrail/content_safety_config_param.py +35 -0
  649. nemo_platform/types/guardrail/crowd_strike_aidr_rail_config.py +29 -0
  650. nemo_platform/types/guardrail/crowd_strike_aidr_rail_config_param.py +29 -0
  651. nemo_platform/types/guardrail/dialog_rails.py +34 -0
  652. nemo_platform/types/guardrail/dialog_rails_param.py +35 -0
  653. nemo_platform/types/guardrail/executed_action.py +48 -0
  654. nemo_platform/types/guardrail/fact_checking_rail_config.py +31 -0
  655. nemo_platform/types/guardrail/fact_checking_rail_config_param.py +32 -0
  656. nemo_platform/types/guardrail/fiddler_guardrails.py +35 -0
  657. nemo_platform/types/guardrail/fiddler_guardrails_param.py +35 -0
  658. nemo_platform/types/guardrail/function_call_param.py +35 -0
  659. nemo_platform/types/guardrail/function_param.py +35 -0
  660. nemo_platform/types/guardrail/g_li_ner_detection.py +51 -0
  661. nemo_platform/types/guardrail/g_li_ner_detection_options.py +29 -0
  662. nemo_platform/types/guardrail/g_li_ner_detection_options_param.py +31 -0
  663. nemo_platform/types/guardrail/g_li_ner_detection_param.py +52 -0
  664. nemo_platform/types/guardrail/generation_log.py +44 -0
  665. nemo_platform/types/guardrail/generation_log_options_param.py +50 -0
  666. nemo_platform/types/guardrail/generation_options_param.py +55 -0
  667. nemo_platform/types/guardrail/generation_rails_options_param.py +53 -0
  668. nemo_platform/types/guardrail/generation_stats.py +56 -0
  669. nemo_platform/types/guardrail/guardrail_check_params.py +164 -0
  670. nemo_platform/types/guardrail/guardrail_check_response.py +36 -0
  671. nemo_platform/types/guardrail/guardrail_config.py +59 -0
  672. nemo_platform/types/guardrail/guardrail_config_filter_param.py +49 -0
  673. nemo_platform/types/guardrail/guardrail_configs_page.py +37 -0
  674. nemo_platform/types/guardrail/guardrails_ai_rail_config.py +33 -0
  675. nemo_platform/types/guardrail/guardrails_ai_rail_config_param.py +35 -0
  676. nemo_platform/types/guardrail/guardrails_ai_validator_config.py +44 -0
  677. nemo_platform/types/guardrail/guardrails_ai_validator_config_param.py +45 -0
  678. nemo_platform/types/guardrail/guardrails_data.py +40 -0
  679. nemo_platform/types/guardrail/guardrails_data_param.py +67 -0
  680. nemo_platform/types/guardrail/image_u_rl_param.py +32 -0
  681. nemo_platform/types/guardrail/injection_detection.py +49 -0
  682. nemo_platform/types/guardrail/injection_detection_param.py +52 -0
  683. nemo_platform/types/guardrail/input_rails.py +32 -0
  684. nemo_platform/types/guardrail/input_rails_param.py +34 -0
  685. nemo_platform/types/guardrail/instruction.py +30 -0
  686. nemo_platform/types/guardrail/instruction_param.py +32 -0
  687. nemo_platform/types/guardrail/jailbreak_detection_config.py +52 -0
  688. nemo_platform/types/guardrail/jailbreak_detection_config_param.py +58 -0
  689. nemo_platform/types/guardrail/llm_call_info.py +63 -0
  690. nemo_platform/types/guardrail/log_adapter_config.py +41 -0
  691. nemo_platform/types/guardrail/log_adapter_config_param.py +27 -0
  692. nemo_platform/types/guardrail/message_template.py +30 -0
  693. nemo_platform/types/guardrail/message_template_param.py +32 -0
  694. nemo_platform/types/guardrail/model.py +55 -0
  695. nemo_platform/types/guardrail/model_cache_config.py +36 -0
  696. nemo_platform/types/guardrail/model_cache_config_param.py +37 -0
  697. nemo_platform/types/guardrail/model_param.py +55 -0
  698. nemo_platform/types/guardrail/model_parameters.py +51 -0
  699. nemo_platform/types/guardrail/model_parameters_param.py +38 -0
  700. nemo_platform/types/guardrail/multilingual_config.py +40 -0
  701. nemo_platform/types/guardrail/multilingual_config_param.py +41 -0
  702. nemo_platform/types/guardrail/output_rails.py +44 -0
  703. nemo_platform/types/guardrail/output_rails_param.py +46 -0
  704. nemo_platform/types/guardrail/output_rails_streaming_config.py +44 -0
  705. nemo_platform/types/guardrail/output_rails_streaming_config_param.py +44 -0
  706. nemo_platform/types/guardrail/pangea_rail_config.py +33 -0
  707. nemo_platform/types/guardrail/pangea_rail_config_param.py +34 -0
  708. nemo_platform/types/guardrail/pangea_rail_options.py +31 -0
  709. nemo_platform/types/guardrail/pangea_rail_options_param.py +33 -0
  710. nemo_platform/types/guardrail/patronus_evaluate_api_params.py +38 -0
  711. nemo_platform/types/guardrail/patronus_evaluate_api_params_param.py +40 -0
  712. nemo_platform/types/guardrail/patronus_evaluate_config.py +30 -0
  713. nemo_platform/types/guardrail/patronus_evaluate_config_param.py +31 -0
  714. nemo_platform/types/guardrail/patronus_evaluation_success_strategy.py +22 -0
  715. nemo_platform/types/guardrail/patronus_rail_config.py +33 -0
  716. nemo_platform/types/guardrail/patronus_rail_config_param.py +34 -0
  717. nemo_platform/types/guardrail/private_ai_detection.py +39 -0
  718. nemo_platform/types/guardrail/private_ai_detection_options.py +29 -0
  719. nemo_platform/types/guardrail/private_ai_detection_options_param.py +31 -0
  720. nemo_platform/types/guardrail/private_ai_detection_param.py +40 -0
  721. nemo_platform/types/guardrail/rail_status.py +26 -0
  722. nemo_platform/types/guardrail/rails.py +73 -0
  723. nemo_platform/types/guardrail/rails_config.py +79 -0
  724. nemo_platform/types/guardrail/rails_config_data.py +94 -0
  725. nemo_platform/types/guardrail/rails_config_data_param.py +95 -0
  726. nemo_platform/types/guardrail/rails_config_param.py +81 -0
  727. nemo_platform/types/guardrail/rails_param.py +74 -0
  728. nemo_platform/types/guardrail/reasoning_config.py +32 -0
  729. nemo_platform/types/guardrail/reasoning_config_param.py +32 -0
  730. nemo_platform/types/guardrail/regex_detection.py +36 -0
  731. nemo_platform/types/guardrail/regex_detection_options.py +32 -0
  732. nemo_platform/types/guardrail/regex_detection_options_param.py +34 -0
  733. nemo_platform/types/guardrail/regex_detection_param.py +37 -0
  734. nemo_platform/types/guardrail/retrieval_rails.py +29 -0
  735. nemo_platform/types/guardrail/retrieval_rails_param.py +31 -0
  736. nemo_platform/types/guardrail/sensitive_data_detection.py +43 -0
  737. nemo_platform/types/guardrail/sensitive_data_detection_options.py +37 -0
  738. nemo_platform/types/guardrail/sensitive_data_detection_options_param.py +39 -0
  739. nemo_platform/types/guardrail/sensitive_data_detection_param.py +45 -0
  740. nemo_platform/types/guardrail/single_call_config.py +31 -0
  741. nemo_platform/types/guardrail/single_call_config_param.py +31 -0
  742. nemo_platform/types/guardrail/status_enum.py +22 -0
  743. nemo_platform/types/guardrail/task_prompt.py +63 -0
  744. nemo_platform/types/guardrail/task_prompt_param.py +65 -0
  745. nemo_platform/types/guardrail/tool_input_rails.py +36 -0
  746. nemo_platform/types/guardrail/tool_input_rails_param.py +38 -0
  747. nemo_platform/types/guardrail/tool_output_rails.py +36 -0
  748. nemo_platform/types/guardrail/tool_output_rails_param.py +38 -0
  749. nemo_platform/types/guardrail/tracing_config.py +48 -0
  750. nemo_platform/types/guardrail/tracing_config_param.py +50 -0
  751. nemo_platform/types/guardrail/trend_micro_rail_config.py +51 -0
  752. nemo_platform/types/guardrail/trend_micro_rail_config_param.py +51 -0
  753. nemo_platform/types/guardrail/user_messages_config.py +42 -0
  754. nemo_platform/types/guardrail/user_messages_config_param.py +42 -0
  755. nemo_platform/types/iam/__init__.py +26 -0
  756. nemo_platform/types/iam/date_range_filter_param.py +36 -0
  757. nemo_platform/types/iam/role_binding.py +42 -0
  758. nemo_platform/types/iam/role_binding_create_params.py +39 -0
  759. nemo_platform/types/iam/role_binding_delete_params.py +30 -0
  760. nemo_platform/types/iam/role_binding_filter_param.py +49 -0
  761. nemo_platform/types/iam/role_binding_list_params.py +44 -0
  762. nemo_platform/types/iam/role_bindings_page.py +37 -0
  763. nemo_platform/types/inference/__init__.py +60 -0
  764. nemo_platform/types/inference/deployment_config_create_params.py +47 -0
  765. nemo_platform/types/inference/deployment_config_list_params.py +46 -0
  766. nemo_platform/types/inference/deployment_config_update_params.py +37 -0
  767. nemo_platform/types/inference/deployment_configs/__init__.py +20 -0
  768. nemo_platform/types/inference/deployment_configs/version_list_response.py +25 -0
  769. nemo_platform/types/inference/deployment_create_params.py +45 -0
  770. nemo_platform/types/inference/deployment_list_models_response.py +23 -0
  771. nemo_platform/types/inference/deployment_list_params.py +52 -0
  772. nemo_platform/types/inference/deployment_update_params.py +35 -0
  773. nemo_platform/types/inference/deployment_update_status_params.py +42 -0
  774. nemo_platform/types/inference/deployments/__init__.py +20 -0
  775. nemo_platform/types/inference/deployments/version_list_response.py +25 -0
  776. nemo_platform/types/inference/gateway/__init__.py +38 -0
  777. nemo_platform/types/inference/gateway/model_patch_params.py +31 -0
  778. nemo_platform/types/inference/gateway/model_patch_response.py +23 -0
  779. nemo_platform/types/inference/gateway/model_post_params.py +31 -0
  780. nemo_platform/types/inference/gateway/model_post_response.py +23 -0
  781. nemo_platform/types/inference/gateway/model_put_params.py +31 -0
  782. nemo_platform/types/inference/gateway/model_put_response.py +23 -0
  783. nemo_platform/types/inference/gateway/openai/__init__.py +18 -0
  784. nemo_platform/types/inference/gateway/openai/v1/__init__.py +21 -0
  785. nemo_platform/types/inference/gateway/openai/v1/openai_list_models_resp.py +31 -0
  786. nemo_platform/types/inference/gateway/openai/v1/openai_model_resp.py +34 -0
  787. nemo_platform/types/inference/gateway/openai_patch_params.py +29 -0
  788. nemo_platform/types/inference/gateway/openai_patch_response.py +23 -0
  789. nemo_platform/types/inference/gateway/openai_post_params.py +29 -0
  790. nemo_platform/types/inference/gateway/openai_post_response.py +23 -0
  791. nemo_platform/types/inference/gateway/openai_put_params.py +29 -0
  792. nemo_platform/types/inference/gateway/openai_put_response.py +23 -0
  793. nemo_platform/types/inference/gateway/provider_patch_params.py +31 -0
  794. nemo_platform/types/inference/gateway/provider_patch_response.py +23 -0
  795. nemo_platform/types/inference/gateway/provider_post_params.py +31 -0
  796. nemo_platform/types/inference/gateway/provider_post_response.py +23 -0
  797. nemo_platform/types/inference/gateway/provider_put_params.py +31 -0
  798. nemo_platform/types/inference/gateway/provider_put_response.py +23 -0
  799. nemo_platform/types/inference/gateway/provider_ready_response.py +23 -0
  800. nemo_platform/types/inference/k8s_nim_operator_config.py +57 -0
  801. nemo_platform/types/inference/k8s_nim_operator_config_param.py +58 -0
  802. nemo_platform/types/inference/middleware_call.py +55 -0
  803. nemo_platform/types/inference/middleware_call_param.py +56 -0
  804. nemo_platform/types/inference/model_deployment.py +97 -0
  805. nemo_platform/types/inference/model_deployment_config.py +76 -0
  806. nemo_platform/types/inference/model_deployment_config_filter_param.py +49 -0
  807. nemo_platform/types/inference/model_deployment_configs_page.py +37 -0
  808. nemo_platform/types/inference/model_deployment_filter_param.py +56 -0
  809. nemo_platform/types/inference/model_deployment_status.py +24 -0
  810. nemo_platform/types/inference/model_deployment_status_history_item.py +37 -0
  811. nemo_platform/types/inference/model_deployments_page.py +37 -0
  812. nemo_platform/types/inference/model_provider.py +134 -0
  813. nemo_platform/types/inference/model_provider_filter_param.py +56 -0
  814. nemo_platform/types/inference/model_provider_sort.py +24 -0
  815. nemo_platform/types/inference/model_provider_status.py +24 -0
  816. nemo_platform/types/inference/model_providers_page.py +37 -0
  817. nemo_platform/types/inference/model_type.py +22 -0
  818. nemo_platform/types/inference/nim_deployment.py +96 -0
  819. nemo_platform/types/inference/nim_deployment_param.py +93 -0
  820. nemo_platform/types/inference/provider_create_params.py +94 -0
  821. nemo_platform/types/inference/provider_list_params.py +47 -0
  822. nemo_platform/types/inference/provider_update_params.py +87 -0
  823. nemo_platform/types/inference/provider_update_status_params.py +48 -0
  824. nemo_platform/types/inference/served_model_mapping.py +35 -0
  825. nemo_platform/types/inference/served_model_mapping_param.py +32 -0
  826. nemo_platform/types/inference/virtual_model.py +91 -0
  827. nemo_platform/types/inference/virtual_model_create_params.py +83 -0
  828. nemo_platform/types/inference/virtual_model_inference_config.py +32 -0
  829. nemo_platform/types/inference/virtual_model_inference_config_param.py +34 -0
  830. nemo_platform/types/inference/virtual_model_list_params.py +35 -0
  831. nemo_platform/types/inference/virtual_model_patch_params.py +80 -0
  832. nemo_platform/types/inference/virtual_models_page.py +37 -0
  833. nemo_platform/types/intake/__init__.py +86 -0
  834. nemo_platform/types/intake/app.py +51 -0
  835. nemo_platform/types/intake/app_create_params.py +38 -0
  836. nemo_platform/types/intake/app_filter_param.py +46 -0
  837. nemo_platform/types/intake/app_list_params.py +44 -0
  838. nemo_platform/types/intake/app_patch_params.py +35 -0
  839. nemo_platform/types/intake/app_sort_field.py +22 -0
  840. nemo_platform/types/intake/apps/__init__.py +26 -0
  841. nemo_platform/types/intake/apps/task.py +54 -0
  842. nemo_platform/types/intake/apps/task_create_params.py +40 -0
  843. nemo_platform/types/intake/apps/task_filter_param.py +49 -0
  844. nemo_platform/types/intake/apps/task_list_params.py +44 -0
  845. nemo_platform/types/intake/apps/task_patch_params.py +37 -0
  846. nemo_platform/types/intake/apps/task_sort_field.py +22 -0
  847. nemo_platform/types/intake/apps/tasks_page.py +37 -0
  848. nemo_platform/types/intake/apps_page.py +37 -0
  849. nemo_platform/types/intake/entries/__init__.py +20 -0
  850. nemo_platform/types/intake/entries/event_create_params.py +40 -0
  851. nemo_platform/types/intake/entry.py +98 -0
  852. nemo_platform/types/intake/entry_context.py +79 -0
  853. nemo_platform/types/intake/entry_context_filter_param.py +41 -0
  854. nemo_platform/types/intake/entry_context_param.py +82 -0
  855. nemo_platform/types/intake/entry_create_params.py +85 -0
  856. nemo_platform/types/intake/entry_data.py +48 -0
  857. nemo_platform/types/intake/entry_data_param.py +51 -0
  858. nemo_platform/types/intake/entry_filter_param.py +85 -0
  859. nemo_platform/types/intake/entry_list_params.py +47 -0
  860. nemo_platform/types/intake/entry_patch_params.py +79 -0
  861. nemo_platform/types/intake/entry_sort_field.py +22 -0
  862. nemo_platform/types/intake/entry_user_rating_filter_param.py +31 -0
  863. nemo_platform/types/intake/entrys_page.py +37 -0
  864. nemo_platform/types/intake/evaluation_context_param.py +41 -0
  865. nemo_platform/types/intake/evaluator_result.py +52 -0
  866. nemo_platform/types/intake/evaluator_result_create_params.py +52 -0
  867. nemo_platform/types/intake/evaluator_result_data_type.py +22 -0
  868. nemo_platform/types/intake/evaluator_result_event.py +67 -0
  869. nemo_platform/types/intake/evaluator_result_event_param.py +69 -0
  870. nemo_platform/types/intake/evaluator_result_filter_param.py +49 -0
  871. nemo_platform/types/intake/evaluator_result_list_params.py +43 -0
  872. nemo_platform/types/intake/evaluator_result_sort_field.py +22 -0
  873. nemo_platform/types/intake/evaluator_results_page.py +37 -0
  874. nemo_platform/types/intake/export_config_param.py +44 -0
  875. nemo_platform/types/intake/export_config_param_param.py +45 -0
  876. nemo_platform/types/intake/export_preview_params.py +34 -0
  877. nemo_platform/types/intake/export_preview_response.py +39 -0
  878. nemo_platform/types/intake/exports/__init__.py +28 -0
  879. nemo_platform/types/intake/exports/export_config.py +44 -0
  880. nemo_platform/types/intake/exports/export_job.py +76 -0
  881. nemo_platform/types/intake/exports/export_job_filter_param.py +50 -0
  882. nemo_platform/types/intake/exports/export_job_sort_field.py +22 -0
  883. nemo_platform/types/intake/exports/export_jobs_page.py +37 -0
  884. nemo_platform/types/intake/exports/export_status_details.py +35 -0
  885. nemo_platform/types/intake/exports/job_create_params.py +40 -0
  886. nemo_platform/types/intake/exports/job_list_params.py +46 -0
  887. nemo_platform/types/intake/exports/job_status.py +22 -0
  888. nemo_platform/types/intake/flexible_entry_request.py +63 -0
  889. nemo_platform/types/intake/flexible_entry_request_param.py +51 -0
  890. nemo_platform/types/intake/flexible_entry_response.py +62 -0
  891. nemo_platform/types/intake/flexible_entry_response_param.py +49 -0
  892. nemo_platform/types/intake/flexible_message.py +56 -0
  893. nemo_platform/types/intake/flexible_message_param.py +43 -0
  894. nemo_platform/types/intake/float_filter_param.py +32 -0
  895. nemo_platform/types/intake/ingest/__init__.py +37 -0
  896. nemo_platform/types/intake/ingest/atif_agent_param.py +35 -0
  897. nemo_platform/types/intake/ingest/atif_content_part_image_param.py +30 -0
  898. nemo_platform/types/intake/ingest/atif_content_part_param.py +28 -0
  899. nemo_platform/types/intake/ingest/atif_content_part_text_param.py +28 -0
  900. nemo_platform/types/intake/ingest/atif_create_params.py +52 -0
  901. nemo_platform/types/intake/ingest/atif_final_metrics_param.py +37 -0
  902. nemo_platform/types/intake/ingest/atif_image_source_param.py +28 -0
  903. nemo_platform/types/intake/ingest/atif_metrics_param.py +41 -0
  904. nemo_platform/types/intake/ingest/atif_observation_param.py +29 -0
  905. nemo_platform/types/intake/ingest/atif_observation_result_param.py +36 -0
  906. nemo_platform/types/intake/ingest/atif_step_agent_param.py +58 -0
  907. nemo_platform/types/intake/ingest/atif_step_param.py +29 -0
  908. nemo_platform/types/intake/ingest/atif_step_system_param.py +43 -0
  909. nemo_platform/types/intake/ingest/atif_step_user_param.py +43 -0
  910. nemo_platform/types/intake/ingest/atif_subagent_trajectory_ref_param.py +33 -0
  911. nemo_platform/types/intake/ingest/atif_tool_call_param.py +31 -0
  912. nemo_platform/types/intake/ingest/chat_completion_create_params.py +66 -0
  913. nemo_platform/types/intake/ingest/chat_completions_ingest_response.py +26 -0
  914. nemo_platform/types/intake/ingest/otlp/__init__.py +18 -0
  915. nemo_platform/types/intake/ingest/otlp/v1/__init__.py +20 -0
  916. nemo_platform/types/intake/ingest/otlp/v1/ingest_response.py +26 -0
  917. nemo_platform/types/intake/message_role.py +22 -0
  918. nemo_platform/types/intake/reviewer_annotation_event.py +95 -0
  919. nemo_platform/types/intake/reviewer_annotation_event_param.py +97 -0
  920. nemo_platform/types/intake/span.py +100 -0
  921. nemo_platform/types/intake/span_evaluation_context.py +40 -0
  922. nemo_platform/types/intake/span_filter_param.py +95 -0
  923. nemo_platform/types/intake/span_kind.py +24 -0
  924. nemo_platform/types/intake/span_list_params.py +46 -0
  925. nemo_platform/types/intake/span_sort_field.py +22 -0
  926. nemo_platform/types/intake/span_status.py +22 -0
  927. nemo_platform/types/intake/spans/__init__.py +20 -0
  928. nemo_platform/types/intake/spans/evaluator_result_list_response.py +25 -0
  929. nemo_platform/types/intake/spans_page.py +37 -0
  930. nemo_platform/types/intake/thumb_direction.py +22 -0
  931. nemo_platform/types/intake/trace.py +65 -0
  932. nemo_platform/types/intake/trace_filter_param.py +60 -0
  933. nemo_platform/types/intake/trace_list_params.py +49 -0
  934. nemo_platform/types/intake/trace_retrieve_params.py +32 -0
  935. nemo_platform/types/intake/trace_sort_field.py +22 -0
  936. nemo_platform/types/intake/traces_page.py +37 -0
  937. nemo_platform/types/intake/usage.py +65 -0
  938. nemo_platform/types/intake/usage_param.py +68 -0
  939. nemo_platform/types/intake/user_action_event.py +65 -0
  940. nemo_platform/types/intake/user_action_event_param.py +68 -0
  941. nemo_platform/types/intake/user_feedback_event.py +84 -0
  942. nemo_platform/types/intake/user_feedback_event_param.py +86 -0
  943. nemo_platform/types/intake/user_rating.py +68 -0
  944. nemo_platform/types/intake/user_rating_param.py +70 -0
  945. nemo_platform/types/jobs/__init__.py +95 -0
  946. nemo_platform/types/jobs/compute_resource_spec.py +32 -0
  947. nemo_platform/types/jobs/compute_resource_spec_param.py +32 -0
  948. nemo_platform/types/jobs/compute_resources.py +46 -0
  949. nemo_platform/types/jobs/compute_resources_param.py +47 -0
  950. nemo_platform/types/jobs/container_spec.py +35 -0
  951. nemo_platform/types/jobs/container_spec_param.py +37 -0
  952. nemo_platform/types/jobs/cpu_execution_provider.py +46 -0
  953. nemo_platform/types/jobs/cpu_execution_provider_param.py +46 -0
  954. nemo_platform/types/jobs/distributed_gpu_execution_provider.py +46 -0
  955. nemo_platform/types/jobs/distributed_gpu_execution_provider_param.py +46 -0
  956. nemo_platform/types/jobs/docker_job_execution_profile.py +43 -0
  957. nemo_platform/types/jobs/docker_job_execution_profile_config.py +52 -0
  958. nemo_platform/types/jobs/docker_job_network_config.py +27 -0
  959. nemo_platform/types/jobs/docker_job_storage_config.py +36 -0
  960. nemo_platform/types/jobs/docker_volume_mount.py +47 -0
  961. nemo_platform/types/jobs/e2e_job_execution_profile.py +43 -0
  962. nemo_platform/types/jobs/gpu_execution_provider.py +46 -0
  963. nemo_platform/types/jobs/gpu_execution_provider_param.py +46 -0
  964. nemo_platform/types/jobs/image_pull_secret.py +27 -0
  965. nemo_platform/types/jobs/job_create_params.py +46 -0
  966. nemo_platform/types/jobs/job_execution_profile_config.py +42 -0
  967. nemo_platform/types/jobs/job_get_logs_params.py +41 -0
  968. nemo_platform/types/jobs/job_list_execution_profiles_response.py +37 -0
  969. nemo_platform/types/jobs/job_list_params.py +47 -0
  970. nemo_platform/types/jobs/job_update_status_details_params.py +29 -0
  971. nemo_platform/types/jobs/kubernetes_empty_dir_volume.py +32 -0
  972. nemo_platform/types/jobs/kubernetes_job_execution_profile.py +43 -0
  973. nemo_platform/types/jobs/kubernetes_job_execution_profile_config.py +101 -0
  974. nemo_platform/types/jobs/kubernetes_job_storage_config.py +40 -0
  975. nemo_platform/types/jobs/kubernetes_object_metadata.py +28 -0
  976. nemo_platform/types/jobs/kubernetes_persistent_volume_claim.py +32 -0
  977. nemo_platform/types/jobs/kubernetes_volume.py +37 -0
  978. nemo_platform/types/jobs/kubernetes_volume_mount.py +38 -0
  979. nemo_platform/types/jobs/platform_job_environment_variable.py +36 -0
  980. nemo_platform/types/jobs/platform_job_environment_variable_param.py +37 -0
  981. nemo_platform/types/jobs/platform_job_list_task_response.py +29 -0
  982. nemo_platform/types/jobs/platform_job_response.py +75 -0
  983. nemo_platform/types/jobs/platform_job_responses_page.py +37 -0
  984. nemo_platform/types/jobs/platform_job_secret_environment_variable_ref.py +27 -0
  985. nemo_platform/types/jobs/platform_job_secret_environment_variable_ref_param.py +29 -0
  986. nemo_platform/types/jobs/platform_job_sort_field.py +22 -0
  987. nemo_platform/types/jobs/platform_job_spec.py +30 -0
  988. nemo_platform/types/jobs/platform_job_spec_param.py +32 -0
  989. nemo_platform/types/jobs/platform_job_step.py +75 -0
  990. nemo_platform/types/jobs/platform_job_step_spec.py +63 -0
  991. nemo_platform/types/jobs/platform_job_step_spec_param.py +65 -0
  992. nemo_platform/types/jobs/platform_job_step_with_context.py +67 -0
  993. nemo_platform/types/jobs/platform_job_step_with_contexts_page.py +37 -0
  994. nemo_platform/types/jobs/platform_job_steps_list_filter_param.py +38 -0
  995. nemo_platform/types/jobs/platform_job_task.py +75 -0
  996. nemo_platform/types/jobs/platform_jobs_list_filter_param.py +51 -0
  997. nemo_platform/types/jobs/result_create_params.py +34 -0
  998. nemo_platform/types/jobs/result_list_params.py +34 -0
  999. nemo_platform/types/jobs/step_lifecycle.py +37 -0
  1000. nemo_platform/types/jobs/step_lifecycle_param.py +37 -0
  1001. nemo_platform/types/jobs/step_list_params.py +44 -0
  1002. nemo_platform/types/jobs/step_update_status_params.py +44 -0
  1003. nemo_platform/types/jobs/subprocess_execution_provider.py +33 -0
  1004. nemo_platform/types/jobs/subprocess_execution_provider_param.py +34 -0
  1005. nemo_platform/types/jobs/subprocess_job_execution_profile.py +36 -0
  1006. nemo_platform/types/jobs/subprocess_job_execution_profile_config.py +49 -0
  1007. nemo_platform/types/jobs/task_create_or_update_params.py +46 -0
  1008. nemo_platform/types/jobs/volcano_job_execution_profile.py +39 -0
  1009. nemo_platform/types/jobs/volcano_job_execution_profile_config.py +114 -0
  1010. nemo_platform/types/members/__init__.py +24 -0
  1011. nemo_platform/types/members/member_create_params.py +40 -0
  1012. nemo_platform/types/members/member_delete_params.py +32 -0
  1013. nemo_platform/types/members/member_update_params.py +37 -0
  1014. nemo_platform/types/members/workspace_member.py +39 -0
  1015. nemo_platform/types/members/workspace_member_list_response.py +29 -0
  1016. nemo_platform/types/models/__init__.py +34 -0
  1017. nemo_platform/types/models/adapter.py +73 -0
  1018. nemo_platform/types/models/adapter_create_params.py +54 -0
  1019. nemo_platform/types/models/adapter_update_params.py +37 -0
  1020. nemo_platform/types/models/base_model_filter_param.py +29 -0
  1021. nemo_platform/types/models/finetuning_type_filter_param.py +31 -0
  1022. nemo_platform/types/models/lora.py +30 -0
  1023. nemo_platform/types/models/lora_param.py +30 -0
  1024. nemo_platform/types/models/model_create_params.py +93 -0
  1025. nemo_platform/types/models/model_entity.py +112 -0
  1026. nemo_platform/types/models/model_entity_filter_param.py +72 -0
  1027. nemo_platform/types/models/model_entity_sort_field.py +22 -0
  1028. nemo_platform/types/models/model_entitys_page.py +37 -0
  1029. nemo_platform/types/models/model_list_params.py +50 -0
  1030. nemo_platform/types/models/model_retrieve_params.py +29 -0
  1031. nemo_platform/types/models/model_update_params.py +86 -0
  1032. nemo_platform/types/projects/__init__.py +25 -0
  1033. nemo_platform/types/projects/project.py +45 -0
  1034. nemo_platform/types/projects/project_create_params.py +37 -0
  1035. nemo_platform/types/projects/project_list_params.py +49 -0
  1036. nemo_platform/types/projects/project_sort_field.py +22 -0
  1037. nemo_platform/types/projects/project_update_params.py +29 -0
  1038. nemo_platform/types/projects/projects_page.py +37 -0
  1039. nemo_platform/types/safe_synthesizer/__init__.py +68 -0
  1040. nemo_platform/types/safe_synthesizer/classify_config.py +41 -0
  1041. nemo_platform/types/safe_synthesizer/classify_config_param.py +43 -0
  1042. nemo_platform/types/safe_synthesizer/column.py +46 -0
  1043. nemo_platform/types/safe_synthesizer/column_actions.py +36 -0
  1044. nemo_platform/types/safe_synthesizer/column_actions_param.py +38 -0
  1045. nemo_platform/types/safe_synthesizer/column_param.py +49 -0
  1046. nemo_platform/types/safe_synthesizer/data_parameters.py +69 -0
  1047. nemo_platform/types/safe_synthesizer/data_parameters_param.py +69 -0
  1048. nemo_platform/types/safe_synthesizer/differential_privacy_hyperparams.py +48 -0
  1049. nemo_platform/types/safe_synthesizer/differential_privacy_hyperparams_param.py +48 -0
  1050. nemo_platform/types/safe_synthesizer/evaluation_parameters.py +64 -0
  1051. nemo_platform/types/safe_synthesizer/evaluation_parameters_param.py +66 -0
  1052. nemo_platform/types/safe_synthesizer/generate_parameters.py +104 -0
  1053. nemo_platform/types/safe_synthesizer/generate_parameters_param.py +102 -0
  1054. nemo_platform/types/safe_synthesizer/gliner_config.py +41 -0
  1055. nemo_platform/types/safe_synthesizer/gliner_config_param.py +41 -0
  1056. nemo_platform/types/safe_synthesizer/globals.py +45 -0
  1057. nemo_platform/types/safe_synthesizer/globals_param.py +47 -0
  1058. nemo_platform/types/safe_synthesizer/job_create_params.py +46 -0
  1059. nemo_platform/types/safe_synthesizer/job_get_logs_params.py +30 -0
  1060. nemo_platform/types/safe_synthesizer/job_list_params.py +44 -0
  1061. nemo_platform/types/safe_synthesizer/jobs/__init__.py +21 -0
  1062. nemo_platform/types/safe_synthesizer/jobs/safe_synthesizer_summary.py +95 -0
  1063. nemo_platform/types/safe_synthesizer/jobs/safe_synthesizer_timing.py +41 -0
  1064. nemo_platform/types/safe_synthesizer/ner_config.py +42 -0
  1065. nemo_platform/types/safe_synthesizer/ner_config_param.py +44 -0
  1066. nemo_platform/types/safe_synthesizer/pii_replacer_config.py +40 -0
  1067. nemo_platform/types/safe_synthesizer/pii_replacer_config_param.py +42 -0
  1068. nemo_platform/types/safe_synthesizer/row.py +50 -0
  1069. nemo_platform/types/safe_synthesizer/row_actions.py +33 -0
  1070. nemo_platform/types/safe_synthesizer/row_actions_param.py +35 -0
  1071. nemo_platform/types/safe_synthesizer/row_param.py +53 -0
  1072. nemo_platform/types/safe_synthesizer/safe_synthesizer_job.py +63 -0
  1073. nemo_platform/types/safe_synthesizer/safe_synthesizer_job_config.py +55 -0
  1074. nemo_platform/types/safe_synthesizer/safe_synthesizer_job_config_param.py +56 -0
  1075. nemo_platform/types/safe_synthesizer/safe_synthesizer_jobs_list_filter_param.py +49 -0
  1076. nemo_platform/types/safe_synthesizer/safe_synthesizer_jobs_page.py +37 -0
  1077. nemo_platform/types/safe_synthesizer/safe_synthesizer_jobs_sort_field.py +22 -0
  1078. nemo_platform/types/safe_synthesizer/safe_synthesizer_parameters.py +91 -0
  1079. nemo_platform/types/safe_synthesizer/safe_synthesizer_parameters_param.py +92 -0
  1080. nemo_platform/types/safe_synthesizer/step_definition.py +39 -0
  1081. nemo_platform/types/safe_synthesizer/step_definition_param.py +41 -0
  1082. nemo_platform/types/safe_synthesizer/time_series_parameters.py +73 -0
  1083. nemo_platform/types/safe_synthesizer/time_series_parameters_param.py +74 -0
  1084. nemo_platform/types/safe_synthesizer/training_hyperparams.py +165 -0
  1085. nemo_platform/types/safe_synthesizer/training_hyperparams_param.py +167 -0
  1086. nemo_platform/types/safe_synthesizer/validation_parameters.py +54 -0
  1087. nemo_platform/types/safe_synthesizer/validation_parameters_param.py +54 -0
  1088. nemo_platform/types/secrets/__init__.py +28 -0
  1089. nemo_platform/types/secrets/platform_secret_access_response.py +33 -0
  1090. nemo_platform/types/secrets/platform_secret_admin_rotation_response.py +28 -0
  1091. nemo_platform/types/secrets/platform_secret_response.py +40 -0
  1092. nemo_platform/types/secrets/platform_secret_responses_page.py +37 -0
  1093. nemo_platform/types/secrets/secret_create_params.py +39 -0
  1094. nemo_platform/types/secrets/secret_list_params.py +32 -0
  1095. nemo_platform/types/secrets/secret_update_params.py +32 -0
  1096. nemo_platform/types/shared/__init__.py +50 -0
  1097. nemo_platform/types/shared/api_endpoint_data.py +43 -0
  1098. nemo_platform/types/shared/auth_context.py +48 -0
  1099. nemo_platform/types/shared/auth_discovery_response.py +32 -0
  1100. nemo_platform/types/shared/backend_format.py +22 -0
  1101. nemo_platform/types/shared/datetime_filter.py +33 -0
  1102. nemo_platform/types/shared/delete_response.py +33 -0
  1103. nemo_platform/types/shared/error_response.py +46 -0
  1104. nemo_platform/types/shared/field_error.py +28 -0
  1105. nemo_platform/types/shared/file_storage_type.py +22 -0
  1106. nemo_platform/types/shared/fileset_metadata.py +46 -0
  1107. nemo_platform/types/shared/finetuning_type.py +48 -0
  1108. nemo_platform/types/shared/generic_sort_field.py +22 -0
  1109. nemo_platform/types/shared/http_validation_error.py +27 -0
  1110. nemo_platform/types/shared/linear_layer_spec.py +33 -0
  1111. nemo_platform/types/shared/mamba_config.py +44 -0
  1112. nemo_platform/types/shared/mo_e_config.py +41 -0
  1113. nemo_platform/types/shared/model_metadata_content.py +38 -0
  1114. nemo_platform/types/shared/model_spec.py +111 -0
  1115. nemo_platform/types/shared/oidc_discovery_response.py +42 -0
  1116. nemo_platform/types/shared/pagination_data.py +37 -0
  1117. nemo_platform/types/shared/platform_job_list_result_response.py +27 -0
  1118. nemo_platform/types/shared/platform_job_log.py +34 -0
  1119. nemo_platform/types/shared/platform_job_log_page.py +33 -0
  1120. nemo_platform/types/shared/platform_job_result_response.py +44 -0
  1121. nemo_platform/types/shared/platform_job_status.py +24 -0
  1122. nemo_platform/types/shared/platform_job_status_response.py +48 -0
  1123. nemo_platform/types/shared/platform_job_step_status_response.py +48 -0
  1124. nemo_platform/types/shared/platform_job_task_status_response.py +47 -0
  1125. nemo_platform/types/shared/prompt_data.py +47 -0
  1126. nemo_platform/types/shared/sliding_window_config.py +27 -0
  1127. nemo_platform/types/shared/tool_call_config.py +46 -0
  1128. nemo_platform/types/shared/tool_calling_metadata_content.py +48 -0
  1129. nemo_platform/types/shared/validation_error.py +34 -0
  1130. nemo_platform/types/shared_params/__init__.py +33 -0
  1131. nemo_platform/types/shared_params/api_endpoint_data.py +38 -0
  1132. nemo_platform/types/shared_params/backend_format.py +24 -0
  1133. nemo_platform/types/shared_params/datetime_filter.py +34 -0
  1134. nemo_platform/types/shared_params/file_storage_type.py +24 -0
  1135. nemo_platform/types/shared_params/finetuning_type.py +50 -0
  1136. nemo_platform/types/shared_params/generic_sort_field.py +24 -0
  1137. nemo_platform/types/shared_params/linear_layer_spec.py +35 -0
  1138. nemo_platform/types/shared_params/mamba_config.py +44 -0
  1139. nemo_platform/types/shared_params/mo_e_config.py +41 -0
  1140. nemo_platform/types/shared_params/model_metadata_content.py +39 -0
  1141. nemo_platform/types/shared_params/model_spec.py +113 -0
  1142. nemo_platform/types/shared_params/platform_job_status.py +26 -0
  1143. nemo_platform/types/shared_params/prompt_data.py +48 -0
  1144. nemo_platform/types/shared_params/sliding_window_config.py +29 -0
  1145. nemo_platform/types/shared_params/tool_call_config.py +46 -0
  1146. nemo_platform/types/shared_params/tool_calling_metadata_content.py +48 -0
  1147. nemo_platform/types/workspaces/__init__.py +24 -0
  1148. nemo_platform/types/workspaces/workspace.py +48 -0
  1149. nemo_platform/types/workspaces/workspace_create_params.py +41 -0
  1150. nemo_platform/types/workspaces/workspace_list_params.py +47 -0
  1151. nemo_platform/types/workspaces/workspace_update_params.py +27 -0
  1152. nemo_platform/types/workspaces/workspaces_page.py +37 -0
  1153. nemo_platform/ui/__init__.py +15 -0
  1154. nemo_platform/ui/output.py +109 -0
  1155. nemo_platform/ui/prompts.py +678 -0
  1156. nemo_platform_plugin/.agents/skills/creating-a-plugin/SKILL.md +275 -0
  1157. nemo_platform_plugin/.agents/skills/plugin-config/SKILL.md +168 -0
  1158. nemo_platform_plugin/.agents/skills/plugin-controller/SKILL.md +320 -0
  1159. nemo_platform_plugin/.agents/skills/plugin-entities/SKILL.md +290 -0
  1160. nemo_platform_plugin/.agents/skills/plugin-function/SKILL.md +292 -0
  1161. nemo_platform_plugin/.agents/skills/plugin-inference-middleware/SKILL.md +346 -0
  1162. nemo_platform_plugin/.agents/skills/plugin-job/SKILL.md +247 -0
  1163. nemo_platform_plugin/.agents/skills/plugin-platform-services/SKILL.md +239 -0
  1164. nemo_platform_plugin/.agents/skills/plugin-platform-services/services-reference.md +192 -0
  1165. nemo_platform_plugin/.agents/skills/plugin-service/SKILL.md +181 -0
  1166. nemo_platform_plugin/.agents/skills/plugin-service/crud-example.md +353 -0
  1167. nemo_platform_plugin/.agents/skills/plugin-testing/SKILL.md +206 -0
  1168. nemo_platform_plugin/README.md +43 -0
  1169. nemo_platform_plugin/_base.py +53 -0
  1170. nemo_platform_plugin/_spec_flags.py +573 -0
  1171. nemo_platform_plugin/api/filter.py +189 -0
  1172. nemo_platform_plugin/api/parsed_filter.py +288 -0
  1173. nemo_platform_plugin/api/text_filter.py +291 -0
  1174. nemo_platform_plugin/cli.py +152 -0
  1175. nemo_platform_plugin/cli_errors.py +232 -0
  1176. nemo_platform_plugin/cli_renderer.py +92 -0
  1177. nemo_platform_plugin/commands.py +1433 -0
  1178. nemo_platform_plugin/config.py +844 -0
  1179. nemo_platform_plugin/controller.py +148 -0
  1180. nemo_platform_plugin/dependencies.py +64 -0
  1181. nemo_platform_plugin/discovery.py +484 -0
  1182. nemo_platform_plugin/docs/ARCHITECTURE.md +160 -0
  1183. nemo_platform_plugin/docs/CONFIG.md +151 -0
  1184. nemo_platform_plugin/docs/CONTROLLER.md +209 -0
  1185. nemo_platform_plugin/docs/ENTITY.md +186 -0
  1186. nemo_platform_plugin/docs/INFERENCE_MIDDLEWARE.md +408 -0
  1187. nemo_platform_plugin/docs/JOB.md +237 -0
  1188. nemo_platform_plugin/docs/QUICKSTART.md +306 -0
  1189. nemo_platform_plugin/docs/SERVICE.md +302 -0
  1190. nemo_platform_plugin/entities.py +793 -0
  1191. nemo_platform_plugin/entity.py +79 -0
  1192. nemo_platform_plugin/entity_client.py +54 -0
  1193. nemo_platform_plugin/filter_ops.py +169 -0
  1194. nemo_platform_plugin/function.py +299 -0
  1195. nemo_platform_plugin/function_context.py +61 -0
  1196. nemo_platform_plugin/functions/frames.py +69 -0
  1197. nemo_platform_plugin/functions/routes.py +454 -0
  1198. nemo_platform_plugin/inference_middleware.py +1191 -0
  1199. nemo_platform_plugin/interface.py +28 -0
  1200. nemo_platform_plugin/job.py +370 -0
  1201. nemo_platform_plugin/job_context.py +86 -0
  1202. nemo_platform_plugin/job_results.py +209 -0
  1203. nemo_platform_plugin/jobs/_cli_options.py +204 -0
  1204. nemo_platform_plugin/jobs/api_factory.py +1178 -0
  1205. nemo_platform_plugin/jobs/constants.py +27 -0
  1206. nemo_platform_plugin/jobs/docker.py +76 -0
  1207. nemo_platform_plugin/jobs/exceptions.py +8 -0
  1208. nemo_platform_plugin/jobs/file_manager.py +238 -0
  1209. nemo_platform_plugin/jobs/openapi_utils.py +174 -0
  1210. nemo_platform_plugin/jobs/profile.py +110 -0
  1211. nemo_platform_plugin/jobs/result_manager.py +291 -0
  1212. nemo_platform_plugin/jobs/routes.py +297 -0
  1213. nemo_platform_plugin/jobs/schemas.py +174 -0
  1214. nemo_platform_plugin/refs.py +154 -0
  1215. nemo_platform_plugin/run_dependencies.py +137 -0
  1216. nemo_platform_plugin/scheduler.py +537 -0
  1217. nemo_platform_plugin/schema.py +216 -0
  1218. nemo_platform_plugin/sdk.py +34 -0
  1219. nemo_platform_plugin/seed.py +71 -0
  1220. nemo_platform_plugin/service.py +130 -0
  1221. nemo_platform_plugin/tasks/dispatcher.py +226 -0
  1222. nemo_platform_plugin-0.1.0.dist-info/METADATA +88 -0
  1223. nemo_platform_plugin-0.1.0.dist-info/RECORD +1224 -0
  1224. nemo_platform_plugin-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,1947 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ """Interactive setup wizard for NeMo Platform.
5
+
6
+ Full onboarding flow: start local services, register an inference provider,
7
+ install AI agent skills, and optionally deploy a demo agent.
8
+ Supports both interactive and non-interactive (``--auto``) modes.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import importlib.util
14
+ import logging
15
+ import os
16
+ import subprocess
17
+ import time
18
+ from dataclasses import dataclass
19
+ from importlib.resources import files
20
+ from importlib.resources.abc import Traversable
21
+ from pathlib import Path
22
+ from typing import Annotated
23
+ from urllib.parse import urlparse
24
+
25
+ import httpx
26
+ import typer
27
+ import yaml as _yaml
28
+ from nemo_platform import NeMoPlatform
29
+ from nmp.common.config import nmp_user_data_dir
30
+ from rich import box
31
+ from rich.console import Console
32
+ from rich.panel import Panel
33
+
34
+ from nemo_platform.cli.commands.skills.base import Scope, Skill
35
+ from nemo_platform.cli.commands.skills.registry import get_installer, load_skills
36
+ from nemo_platform.cli.core.context import CLIContext
37
+ from nemo_platform.cli.core.errors import handle_errors
38
+ from nemo_platform.config.config import Config
39
+ from nemo_platform.config.models import ConfigFile, ConfigParams, LocalServicesConfig
40
+ from nemo_platform.ui.prompts import (
41
+ UserCancelled,
42
+ is_interactive,
43
+ non_empty_validator,
44
+ prompt_choice,
45
+ prompt_confirm,
46
+ prompt_multiselect,
47
+ prompt_password,
48
+ prompt_select,
49
+ prompt_text,
50
+ provider_name_validator,
51
+ )
52
+
53
+ logger = logging.getLogger(__name__)
54
+ console = Console(stderr=True)
55
+
56
+ CHECK = "[green]✓[/green]"
57
+ CROSS = "[red]✗[/red]"
58
+ WARN = "[yellow]![/yellow]"
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # Known provider catalog
62
+ # ---------------------------------------------------------------------------
63
+
64
+
65
+ @dataclass(frozen=True)
66
+ class KnownProvider:
67
+ """A well-known inference provider with pre-configured connection details."""
68
+
69
+ name: str
70
+ label: str
71
+ description: str
72
+ host_url: str
73
+ auth_header_format: str | None = None
74
+ default_extra_headers: dict[str, str] | None = None
75
+ env_var: str | None = None
76
+ requires_api_key: bool = True
77
+
78
+
79
+ KNOWN_PROVIDERS: tuple[KnownProvider, ...] = (
80
+ KnownProvider(
81
+ name="nvidia-build",
82
+ label="NVIDIA Build",
83
+ description="NVIDIA-hosted models via build.nvidia.com",
84
+ host_url="https://integrate.api.nvidia.com",
85
+ env_var="NVIDIA_API_KEY",
86
+ ),
87
+ KnownProvider(
88
+ name="openai",
89
+ label="OpenAI",
90
+ description="GPT-4.1, o3, o4-mini",
91
+ host_url="https://api.openai.com/v1",
92
+ env_var="OPENAI_API_KEY",
93
+ ),
94
+ KnownProvider(
95
+ name="anthropic",
96
+ label="Anthropic",
97
+ description="Claude Opus 4, Sonnet 4, Haiku",
98
+ host_url="https://api.anthropic.com",
99
+ auth_header_format="X-Api-Key: {{ auth_secret }}",
100
+ default_extra_headers={"anthropic-version": "2023-06-01"},
101
+ env_var="ANTHROPIC_API_KEY",
102
+ ),
103
+ KnownProvider(
104
+ name="google-gemini",
105
+ label="Google Gemini",
106
+ description="Gemini 2.5 Flash, Pro",
107
+ host_url="https://generativelanguage.googleapis.com/v1beta/openai",
108
+ env_var="GEMINI_API_KEY",
109
+ ),
110
+ KnownProvider(
111
+ name="ollama",
112
+ label="Ollama (local)",
113
+ description="Local models, no API key needed",
114
+ host_url="http://localhost:11434/v1",
115
+ requires_api_key=False,
116
+ ),
117
+ )
118
+
119
+ _KNOWN_PROVIDERS_BY_NAME: dict[str, KnownProvider] = {p.name: p for p in KNOWN_PROVIDERS}
120
+
121
+ # ---------------------------------------------------------------------------
122
+ # Onboarding paths — shown after setup completes
123
+ # ---------------------------------------------------------------------------
124
+
125
+
126
+ _NEMO_DOCS_URL = "https://docs.nvidia.com/nemo/platform"
127
+
128
+
129
+ @dataclass(frozen=True)
130
+ class OnboardingPath:
131
+ """A goal-oriented onboarding option shown at the end of interactive setup."""
132
+
133
+ value: str
134
+ label: str
135
+ skill_prompt: str
136
+ docs_url: str
137
+ note: str | None = None
138
+
139
+
140
+ ONBOARDING_PATHS: tuple[OnboardingPath, ...] = (
141
+ OnboardingPath(
142
+ value="optimize",
143
+ label="Build and optimize agents",
144
+ skill_prompt="Build and optimize an agent using NeMo Platform",
145
+ docs_url=f"{_NEMO_DOCS_URL}/agents",
146
+ note="Open a coding agent session in your agent's project directory",
147
+ ),
148
+ OnboardingPath(
149
+ value="explore",
150
+ label="Explore the platform",
151
+ skill_prompt="What can I do with NeMo Platform?",
152
+ docs_url=_NEMO_DOCS_URL,
153
+ ),
154
+ )
155
+
156
+ _ONBOARDING_PATHS_BY_VALUE: dict[str, OnboardingPath] = {p.value: p for p in ONBOARDING_PATHS}
157
+
158
+
159
+ @dataclass(frozen=True)
160
+ class ProbeConfig:
161
+ """How to probe a provider's auth-required endpoint for key validation."""
162
+
163
+ method: str
164
+ path: str
165
+ body: dict | None = None
166
+
167
+
168
+ # NVIDIA's gateway routes by model name before checking auth, so a fake model
169
+ # returns 404 without ever validating the key. We use a real, stable model so
170
+ # the gateway reaches the auth layer and returns 401/403 for bad credentials.
171
+ _NVIDIA_BUILD_PROBE_MODEL = "meta/llama-3.1-8b-instruct"
172
+
173
+ _PROBE_CONFIGS: dict[str, ProbeConfig] = {
174
+ "nvidia-build": ProbeConfig(
175
+ "POST",
176
+ "v1/chat/completions",
177
+ {"model": _NVIDIA_BUILD_PROBE_MODEL, "messages": [], "max_tokens": 1},
178
+ ),
179
+ "openai": ProbeConfig("GET", "models"),
180
+ "anthropic": ProbeConfig("GET", "v1/models"),
181
+ "google-gemini": ProbeConfig("GET", "models"),
182
+ }
183
+
184
+
185
+ @dataclass(frozen=True)
186
+ class KeyValidationResult:
187
+ """Outcome of an API key validation probe."""
188
+
189
+ passed: bool
190
+ message: str
191
+
192
+
193
+ # Env vars probed during --auto mode, in priority order.
194
+ _AUTO_ENV_VARS: tuple[tuple[str, str], ...] = (
195
+ ("NEMO_DEFAULT_INFERENCE_KEY", "NEMO_DEFAULT_INFERENCE_BASE_URL"),
196
+ ("NVIDIA_API_KEY", ""),
197
+ ("OPENAI_API_KEY", ""),
198
+ ("ANTHROPIC_API_KEY", ""),
199
+ ("GEMINI_API_KEY", ""),
200
+ )
201
+
202
+ _KEY_VALIDATION_TIMEOUT = 10.0
203
+ _KEY_REJECTED_STATUS_CODES = (401, 403)
204
+ _KEY_REJECTED_MESSAGE = "API key validation failed. The provider rejected the credentials."
205
+
206
+ _MODEL_DISCOVERY_ROUND_SECONDS = 30
207
+ _MODEL_DISCOVERY_MAX_ROUNDS = 2
208
+ _MODEL_DISCOVERY_POLL_INTERVAL = 1
209
+ _SERVICE_STARTUP_TIMEOUT_SECONDS = 240
210
+ _SERVICE_STARTUP_POLL_INTERVAL = 0.5
211
+ _AGENT_DEPLOY_TIMEOUT_SECONDS = 120
212
+ _AGENT_DEPLOY_POLL_INTERVAL = 1
213
+ _AGENT_API_READINESS_TIMEOUT = 30
214
+ _AGENT_API_READINESS_POLL_INTERVAL = 1
215
+ _KILL_WAIT_TIMEOUT = 10
216
+ _CONTROLLER_HEALTH_RETRY_DELAY = 3.0
217
+ _POST_START_REACHABLE_RETRIES = 6
218
+ _POST_START_REACHABLE_DELAY = 2.0
219
+
220
+ _DEMO_AGENT_NAME = "calculator-agent"
221
+
222
+
223
+ def _pause(seconds: float) -> None:
224
+ time.sleep(seconds)
225
+
226
+
227
+ # Filesystem markers that indicate which coding agents are in use.
228
+ _AGENT_MARKERS: tuple[tuple[str, str], ...] = (
229
+ ("AGENTS.md", "codex"),
230
+ (".cursor", "cursor"),
231
+ (".opencode", "opencode"),
232
+ (".claude", "claude"),
233
+ )
234
+
235
+
236
+ # ---------------------------------------------------------------------------
237
+ # Helpers — platform reachability
238
+ # ---------------------------------------------------------------------------
239
+
240
+
241
+ def _bootstrap_config_if_missing(base_url: str, workspace: str) -> None:
242
+ """Write a minimal cluster + context into the config file when one isn't seeded.
243
+
244
+ ``nemo setup`` can run before any config is on disk (first-time install)
245
+ *or* with a partial config containing only ``local_services.data_dir``
246
+ written earlier in the same setup invocation by ``_save_data_dir``.
247
+ Later steps — in particular ``_save_default_model`` — call
248
+ ``Config.write`` with *only* a ``default_model`` param. If there's no
249
+ cluster on disk at that point, ``ensure_context`` will fail with
250
+ ``Cluster '<name>' does not exist and no base_url provided to create
251
+ it`` because it has no ``base_url`` to attach to a new cluster.
252
+
253
+ Calling this once after the platform is confirmed reachable seeds the
254
+ cluster + context so that all subsequent writes succeed. Idempotent:
255
+ if a cluster is already present, the call is a no-op. Any existing
256
+ ``local_services`` block (e.g. the persisted data dir) is preserved.
257
+ """
258
+ config_path = Config.get_default_config_path()
259
+ if config_path.exists():
260
+ try:
261
+ existing = Config.load(config_path=config_path).get_config_file()
262
+ except Exception:
263
+ # Unreadable existing config — fall through and rewrite.
264
+ logger.debug("Failed to load existing config; will reseed", exc_info=True)
265
+ else:
266
+ if existing.clusters:
267
+ # Cluster already present — assume bootstrap is done.
268
+ return
269
+ params: ConfigParams = {"base_url": base_url, "workspace": workspace}
270
+ Config.write(params)
271
+
272
+
273
+ def _check_platform_reachable(base_url: str, timeout: float = 5.0) -> bool:
274
+ """Return True if the platform health endpoint responds."""
275
+ try:
276
+ resp = httpx.get(f"{base_url.rstrip('/')}/health/ready", timeout=timeout)
277
+ return resp.status_code == 200
278
+ except Exception:
279
+ return False
280
+
281
+
282
+ def _check_platform_reachable_with_retries(
283
+ base_url: str,
284
+ retries: int = _POST_START_REACHABLE_RETRIES,
285
+ delay: float = _POST_START_REACHABLE_DELAY,
286
+ ) -> bool:
287
+ """Check platform reachability with retries.
288
+
289
+ Right after startup the platform may briefly report ready then flip back
290
+ to not-ready while controllers begin heavy work (e.g. model reconciliation).
291
+ A single-shot check can hit this window and falsely report failure.
292
+ """
293
+ for attempt in range(retries):
294
+ if _check_platform_reachable(base_url):
295
+ return True
296
+ if attempt < retries - 1:
297
+ _pause(delay)
298
+ return False
299
+
300
+
301
+ def _check_controller_health(base_url: str, timeout: float = 5.0) -> tuple[bool, str]:
302
+ """Query ``/status`` and assess controller health.
303
+
304
+ Returns ``(True, "")`` when controllers are populated and all healthy.
305
+ Returns ``(False, detail)`` when unhealthy, unreachable, or empty after retry.
306
+
307
+ If ``controllers.status`` is empty on the first call (startup timing race),
308
+ waits ``_CONTROLLER_HEALTH_RETRY_DELAY`` seconds and retries once.
309
+ """
310
+ for attempt in range(2):
311
+ try:
312
+ resp = httpx.get(f"{base_url.rstrip('/')}/status", timeout=timeout)
313
+ if resp.status_code != 200:
314
+ return False, f"Unexpected status {resp.status_code} from /status endpoint."
315
+ data = resp.json()
316
+ except httpx.RequestError:
317
+ return False, "Could not reach platform status endpoint."
318
+ except ValueError:
319
+ return False, "Invalid JSON from /status endpoint."
320
+
321
+ controllers = data.get("controllers") if isinstance(data, dict) else None
322
+ if not isinstance(controllers, dict):
323
+ return False, "Invalid /status payload (missing controllers)."
324
+ status_map = controllers.get("status")
325
+ if not isinstance(status_map, dict):
326
+ status_map = {}
327
+
328
+ if status_map:
329
+ unhealthy = [name for name, ok in status_map.items() if not ok]
330
+ if unhealthy:
331
+ return False, f"Unhealthy controllers: {', '.join(unhealthy)}"
332
+ return True, ""
333
+
334
+ if attempt == 0:
335
+ _pause(_CONTROLLER_HEALTH_RETRY_DELAY)
336
+
337
+ return False, "No controllers reported status. Controller threads may have crashed before registering."
338
+
339
+
340
+ def _verify_platform_health(base_url: str) -> bool:
341
+ """Final health gate before declaring setup complete.
342
+
343
+ Returns True if the platform is healthy (caller prints the success banner).
344
+ Returns False after printing red or yellow diagnostics to the console.
345
+ """
346
+ ok, detail = _check_controller_health(base_url)
347
+ if ok:
348
+ return True
349
+
350
+ if "no controllers" in detail.lower():
351
+ console.print(f"\n{WARN} [yellow]Could not confirm controller health ({detail}).[/yellow]")
352
+ console.print(" Setup may have succeeded, but verify with:")
353
+ console.print(" [cyan]nemo services status[/cyan]")
354
+ else:
355
+ console.print(f"\n{CROSS} [red]Platform controllers are unhealthy.[/red]")
356
+ console.print(f" {detail}")
357
+ console.print()
358
+ console.print(" The models controller may have crashed during startup.")
359
+ console.print(" Check service logs with: [cyan]nemo services logs[/cyan]")
360
+ console.print()
361
+ console.print(" Try: [cyan]nemo services run[/cyan] (restart services)")
362
+
363
+ return False
364
+
365
+
366
+ def _provider_exists(client: NeMoPlatform, name: str, workspace: str) -> bool:
367
+ """Return True if a provider with *name* already exists."""
368
+ try:
369
+ client.inference.providers.retrieve(name, workspace=workspace)
370
+ return True
371
+ except Exception:
372
+ return False
373
+
374
+
375
+ def _secret_exists(client: NeMoPlatform, name: str, workspace: str) -> bool:
376
+ """Return True if a secret with *name* already exists."""
377
+ try:
378
+ client.secrets.retrieve(name, workspace=workspace)
379
+ return True
380
+ except Exception:
381
+ return False
382
+
383
+
384
+ def _create_secret(client: NeMoPlatform, name: str, value: str, workspace: str) -> None:
385
+ client.secrets.create(name=name, value=value, workspace=workspace)
386
+
387
+
388
+ def _update_secret(client: NeMoPlatform, name: str, value: str, workspace: str) -> None:
389
+ client.secrets.update(name, value=value, workspace=workspace)
390
+
391
+
392
+ def _create_provider(
393
+ client: NeMoPlatform,
394
+ *,
395
+ name: str,
396
+ host_url: str,
397
+ secret_name: str | None,
398
+ workspace: str,
399
+ auth_header_format: str | None = None,
400
+ default_extra_headers: dict[str, str] | None = None,
401
+ ) -> None:
402
+ kwargs: dict = {
403
+ "name": name,
404
+ "host_url": host_url,
405
+ "workspace": workspace,
406
+ }
407
+ if secret_name:
408
+ kwargs["api_key_secret_name"] = secret_name
409
+ if auth_header_format:
410
+ header_name, _, header_value = auth_header_format.partition(":")
411
+ if header_name and header_value:
412
+ kwargs["required_extra_headers"] = {header_name.strip(): header_value.strip()}
413
+ if default_extra_headers:
414
+ kwargs["default_extra_headers"] = default_extra_headers
415
+ client.inference.providers.create(**kwargs)
416
+
417
+
418
+ def _update_provider(
419
+ client: NeMoPlatform,
420
+ *,
421
+ name: str,
422
+ host_url: str,
423
+ secret_name: str | None,
424
+ workspace: str,
425
+ default_extra_headers: dict[str, str] | None = None,
426
+ ) -> None:
427
+ kwargs: dict = {
428
+ "host_url": host_url,
429
+ "workspace": workspace,
430
+ }
431
+ if secret_name:
432
+ kwargs["api_key_secret_name"] = secret_name
433
+ if default_extra_headers:
434
+ kwargs["default_extra_headers"] = default_extra_headers
435
+ client.inference.providers.update(name, **kwargs)
436
+
437
+
438
+ _PROVIDER_UNHEALTHY_STATUSES = frozenset({"ERROR", "LOST"})
439
+ _NON_COMPLIANT_MARKER = "Non-OpenAI compliant"
440
+
441
+
442
+ def _wait_for_models(
443
+ client: NeMoPlatform,
444
+ provider_name: str,
445
+ workspace: str,
446
+ host_url: str = "",
447
+ round_seconds: int = _MODEL_DISCOVERY_ROUND_SECONDS,
448
+ max_rounds: int = _MODEL_DISCOVERY_MAX_ROUNDS,
449
+ ) -> list[str]:
450
+ """Poll until provider has at least one served model. Returns entity IDs.
451
+
452
+ Retries in rounds so the user sees progress rather than a long silence.
453
+ Checks provider status each poll and exits early if the provider is
454
+ flagged as non-compliant or unhealthy, so the user isn't left waiting
455
+ for models that will never arrive.
456
+ """
457
+ start = time.monotonic()
458
+ for attempt in range(max_rounds):
459
+ deadline = time.monotonic() + round_seconds
460
+ with console.status("[bold cyan]Waiting for model discovery...") as status:
461
+ while time.monotonic() < deadline:
462
+ elapsed = int(time.monotonic() - start)
463
+ status.update(f"[bold cyan]Waiting for model discovery... ({elapsed}s)")
464
+ try:
465
+ provider = client.inference.providers.retrieve(provider_name, workspace=workspace)
466
+ served = getattr(provider, "served_models", None) or []
467
+ if served:
468
+ model_ids = [m.model_entity_id for m in served if getattr(m, "model_entity_id", None)]
469
+ if model_ids:
470
+ return model_ids
471
+
472
+ provider_status = getattr(provider, "status", None) or ""
473
+ provider_msg = getattr(provider, "status_message", None) or ""
474
+
475
+ if _NON_COMPLIANT_MARKER in provider_msg:
476
+ url_hint = f" ({host_url})" if host_url else ""
477
+ console.print(
478
+ f"\n {WARN} Provider '{provider_name}'{url_hint} returned a non-OpenAI "
479
+ f"compliant response from GET /v1/models."
480
+ )
481
+ console.print(" Check that the host URL points to an OpenAI-compatible API endpoint.")
482
+ console.print(
483
+ " The provider is still registered and usable for direct inference, "
484
+ "but automatic model discovery is disabled."
485
+ )
486
+ return []
487
+
488
+ if provider_status in _PROVIDER_UNHEALTHY_STATUSES:
489
+ url_hint = f" ({host_url})" if host_url else ""
490
+ console.print(f"\n {WARN} Provider '{provider_name}'{url_hint} is in {provider_status} state.")
491
+ if provider_msg:
492
+ console.print(f" {provider_msg}")
493
+ console.print(" Check the host URL and API key, then re-run [cyan]nemo setup[/cyan].")
494
+ return []
495
+
496
+ except Exception:
497
+ logger.debug("Model discovery poll for '%s' failed", provider_name, exc_info=True)
498
+ _pause(_MODEL_DISCOVERY_POLL_INTERVAL)
499
+ if attempt < max_rounds - 1:
500
+ console.print(f" {WARN} Models not available yet, retrying...")
501
+ return []
502
+
503
+
504
+ def _get_all_model_entity_ids(client: NeMoPlatform, workspace: str) -> list[str]:
505
+ """Return all model entity IDs across all providers."""
506
+ entity_ids: list[str] = []
507
+ try:
508
+ page = client.inference.providers.list(workspace=workspace)
509
+ for provider in page.data:
510
+ for model in getattr(provider, "served_models", None) or []:
511
+ if hasattr(model, "model_entity_id") and model.model_entity_id:
512
+ entity_ids.append(model.model_entity_id)
513
+ except Exception:
514
+ logger.debug("Failed to list model entity IDs", exc_info=True)
515
+ return sorted(set(entity_ids))
516
+
517
+
518
+ def _get_all_model_choices(client: NeMoPlatform, workspace: str) -> list[tuple[str, str]]:
519
+ """Return picker choices as (entity_id, label) across all providers."""
520
+ choices: list[tuple[str, str]] = []
521
+ try:
522
+ page = client.inference.providers.list(workspace=workspace)
523
+ for provider in page.data:
524
+ provider_name = getattr(provider, "name", "unknown-provider")
525
+ for model in getattr(provider, "served_models", None) or []:
526
+ model_entity_id = getattr(model, "model_entity_id", None)
527
+ if model_entity_id:
528
+ label = f"{_display_model_name(model_entity_id)} ({provider_name})"
529
+ choices.append((model_entity_id, label))
530
+ except Exception:
531
+ logger.debug("Failed to list model choices", exc_info=True)
532
+ return sorted(set(choices), key=lambda item: item[1])
533
+
534
+
535
+ def _display_model_name(model_entity_id: str) -> str:
536
+ """Strip workspace prefix from a model entity ID for display."""
537
+ return model_entity_id.split("/", 1)[-1] if "/" in model_entity_id else model_entity_id
538
+
539
+
540
+ def _resolve_provider_for_url(base_url: str) -> KnownProvider | None:
541
+ """Find a known provider whose host_url matches *base_url*."""
542
+ normalized = base_url.rstrip("/")
543
+ for p in KNOWN_PROVIDERS:
544
+ if p.host_url.rstrip("/") == normalized:
545
+ return p
546
+ return None
547
+
548
+
549
+ # ---------------------------------------------------------------------------
550
+ # Service startup
551
+ # ---------------------------------------------------------------------------
552
+
553
+
554
+ def _load_persisted_data_dir() -> str | None:
555
+ """Return the local data directory previously chosen via ``nemo setup``."""
556
+ config_path = Config.get_default_config_path()
557
+ if not config_path.exists():
558
+ return None
559
+ try:
560
+ config = Config.load(config_path=config_path)
561
+ except Exception:
562
+ logger.debug("Failed to load config for local_services lookup", exc_info=True)
563
+ return None
564
+ local = config.get_config_file().local_services
565
+ return local.data_dir if local else None
566
+
567
+
568
+ def _save_data_dir(data_dir: str) -> None:
569
+ """Persist the chosen local data directory to the user's config file.
570
+
571
+ Reads any existing config so other fields (contexts, clusters, etc.) are
572
+ preserved, then overwrites just ``local_services.data_dir``.
573
+ """
574
+ config_path = Config.get_default_config_path()
575
+ if config_path.exists():
576
+ config = Config.load(config_path=config_path)
577
+ else:
578
+ config = Config.create(config_path, ConfigFile())
579
+ config_file = config.get_config_file()
580
+ config_file.local_services = LocalServicesConfig(data_dir=data_dir)
581
+ config.save()
582
+
583
+
584
+ def _prompt_data_dir() -> str:
585
+ """Prompt the user for a local data directory and persist the choice.
586
+
587
+ Pre-fills the prompt with the previously-persisted directory if any,
588
+ otherwise the XDG default (``~/.local/share/nemo``). The chosen
589
+ directory is where local services persist SQLite DB, encryption key,
590
+ and uploaded files.
591
+ """
592
+ persisted = _load_persisted_data_dir()
593
+ default_dir = persisted or str(nmp_user_data_dir())
594
+
595
+ chosen = prompt_text(
596
+ message="Local data directory:",
597
+ default=default_dir,
598
+ validator=non_empty_validator("Data directory"),
599
+ ).strip()
600
+
601
+ _save_data_dir(chosen)
602
+ return chosen
603
+
604
+
605
+ def _resolve_services_port(base_url: str) -> int:
606
+ """Extract the port from *base_url*, defaulting to 8080."""
607
+ parsed = urlparse(base_url)
608
+ return parsed.port or 8080
609
+
610
+
611
+ def _start_services_background(base_url: str, data_dir: str | None = None) -> subprocess.Popen:
612
+ """Launch ``nemo services run`` as a background process.
613
+
614
+ Delegates to the shared process lifecycle module which uses flock-based
615
+ instance tracking. If *data_dir* is provided, it's forwarded so the
616
+ subprocess inherits ``NMP_DATA_DIR`` (unless the parent shell already
617
+ exported it).
618
+ """
619
+ from nemo_platform.cli.commands.services._process import compute_scope, start_background
620
+
621
+ port = _resolve_services_port(base_url)
622
+ scope = compute_scope(port=port)
623
+ return start_background(scope=scope, port=port, data_dir=data_dir)
624
+
625
+
626
+ def _last_startup_service(log_path: Path | None) -> str:
627
+ """Read the most recently logged ``[STARTUP] service:<name>`` from the service log."""
628
+ if log_path is None or not log_path.exists():
629
+ return ""
630
+ try:
631
+ text = log_path.read_text(errors="replace")
632
+ except OSError:
633
+ return ""
634
+ last = ""
635
+ tag = "[STARTUP] service:"
636
+ for line in text.splitlines():
637
+ if tag in line:
638
+ last = line.split(tag, 1)[1].split(":")[0]
639
+ return last
640
+
641
+
642
+ def _wait_for_platform(
643
+ base_url: str,
644
+ timeout: int = _SERVICE_STARTUP_TIMEOUT_SECONDS,
645
+ poll_interval: float = _SERVICE_STARTUP_POLL_INTERVAL,
646
+ log_path: Path | None = None,
647
+ ) -> bool:
648
+ """Poll until the platform health endpoint responds. Returns True on success.
649
+
650
+ When *log_path* is provided, the spinner shows the last service that
651
+ finished loading so users see that progress is being made during a
652
+ slow cold start.
653
+ """
654
+ start = time.monotonic()
655
+ deadline = start + timeout
656
+ with console.status("[bold cyan]Waiting for platform...") as status:
657
+ while time.monotonic() < deadline:
658
+ elapsed = int(time.monotonic() - start)
659
+ svc = _last_startup_service(log_path)
660
+ hint = f" — loaded {svc}" if svc else ""
661
+ status.update(f"[bold cyan]Waiting for platform... ({elapsed}s){hint}")
662
+ if _check_platform_reachable(base_url, timeout=1.0):
663
+ return True
664
+ _pause(poll_interval)
665
+ return False
666
+
667
+
668
+ def _kill_existing_services(base_url: str) -> None:
669
+ """Find and kill any running ``nemo services run`` processes.
670
+
671
+ Delegates to the shared process lifecycle module.
672
+ """
673
+ from nemo_platform.cli.commands.services._process import compute_scope, stop_instance
674
+
675
+ port = _resolve_services_port(base_url)
676
+ scope = compute_scope(port=port)
677
+ stop_instance(scope, timeout=2.0, force=True)
678
+
679
+
680
+ def _maybe_start_services(
681
+ base_url: str,
682
+ auto: bool,
683
+ start_services: bool | None,
684
+ timeout: int = _SERVICE_STARTUP_TIMEOUT_SECONDS,
685
+ ) -> None:
686
+ """Start services if requested, restarting if already running.
687
+
688
+ In interactive mode (auto=False), prompts the user if start_services is None.
689
+ In auto mode, only starts if start_services is explicitly True.
690
+
691
+ When start_services is True and the platform is already running, the
692
+ existing processes are stopped and restarted so the full service set
693
+ (including any newly installed plugins) is picked up. Data lives in
694
+ SQLite so nothing is lost across restarts.
695
+ """
696
+ already_running = _check_platform_reachable(base_url)
697
+
698
+ if already_running and start_services is not True:
699
+ console.print(f"{CHECK} Platform already running at {base_url}\n")
700
+ return
701
+
702
+ should_start = start_services
703
+ if should_start is None:
704
+ if auto:
705
+ console.print(f"{CROSS} Cannot reach platform at {base_url}")
706
+ console.print(" Start the platform first, or pass --start-services:")
707
+ console.print(" [cyan]nemo setup --auto --start-services[/cyan]")
708
+ console.print(" [cyan]nemo services run[/cyan]")
709
+ raise typer.Exit(1)
710
+ should_start = (
711
+ prompt_choice(
712
+ message=f"Platform not reachable at {base_url}. Start local services?",
713
+ options=[("yes", "Yes, start services now"), ("no", "No, I'll start them myself")],
714
+ default="yes",
715
+ )
716
+ == "yes"
717
+ )
718
+
719
+ if not should_start:
720
+ console.print(f"{CROSS} Cannot reach platform at {base_url}")
721
+ console.print(" Start the platform first:")
722
+ console.print(" [cyan]nemo services run[/cyan] (local development)")
723
+ raise typer.Exit(1)
724
+
725
+ # Pick (and persist) the local data directory before launching services
726
+ # so the chosen path takes effect on this run. Interactive mode prompts;
727
+ # ``--auto`` reuses whatever was previously persisted (or service default).
728
+ if auto:
729
+ data_dir = _load_persisted_data_dir()
730
+ else:
731
+ data_dir = _prompt_data_dir()
732
+
733
+ if already_running:
734
+ console.print(" Restarting platform services...")
735
+ _kill_existing_services(base_url)
736
+ deadline = time.time() + _KILL_WAIT_TIMEOUT
737
+ while time.time() < deadline and _check_platform_reachable(base_url, timeout=1.0):
738
+ _pause(1)
739
+ else:
740
+ console.print(" Starting platform services...")
741
+ proc = _start_services_background(base_url, data_dir=data_dir)
742
+
743
+ from nemo_platform.cli.commands.services._process import compute_scope, log_path_for
744
+
745
+ port = _resolve_services_port(base_url)
746
+ log = log_path_for(compute_scope(port=port))
747
+
748
+ if not _wait_for_platform(base_url, timeout=timeout, log_path=log):
749
+ exit_code = proc.poll()
750
+ if exit_code is not None:
751
+ console.print(f"{CROSS} Service process exited early (exit code {exit_code})")
752
+ else:
753
+ proc.terminate()
754
+ console.print(f"{CROSS} Platform did not become ready within {timeout}s")
755
+ console.print(f" Check {log} for details.")
756
+ raise typer.Exit(1)
757
+
758
+ console.print(f"{CHECK} Platform running at {base_url} (pid {proc.pid})\n")
759
+
760
+
761
+ # ---------------------------------------------------------------------------
762
+ # Skills installation
763
+ # ---------------------------------------------------------------------------
764
+
765
+
766
+ def _detect_coding_agents() -> list[tuple[str, str]]:
767
+ """Detect coding agents from filesystem markers in the project root.
768
+
769
+ Returns list of (marker, agent_name) for each detected agent.
770
+ """
771
+ project_root = _find_project_root()
772
+ detected = []
773
+ for marker, agent_name in _AGENT_MARKERS:
774
+ if (project_root / marker).exists():
775
+ detected.append((marker, agent_name))
776
+ return detected
777
+
778
+
779
+ def _find_project_root() -> Path:
780
+ """Find the project root by looking for a .git directory, falling back to cwd."""
781
+ cwd = Path.cwd()
782
+ current = cwd
783
+ while current != current.parent:
784
+ if (current / ".git").exists():
785
+ return current
786
+ current = current.parent
787
+ return cwd
788
+
789
+
790
+ def _load_skills_with_warnings() -> tuple[dict[str, Skill], list[str]]:
791
+ """Load skills while capturing any plugin-discovery warnings.
792
+
793
+ The registry emits ``logger.warning`` records when a plugin's skills directory
794
+ is missing, malformed, or invalid. We capture those records so they can be
795
+ surfaced in the preview before any install happens, rather than scrolling
796
+ past mid-install.
797
+
798
+ Defensive against (a) callers that raised the registry logger's level above
799
+ WARNING (e.g. a future ``--quiet`` flag) and (b) the ``@lru_cache`` on the
800
+ underlying loader, which would otherwise replay a cached dict with no
801
+ warnings on repeat calls.
802
+ """
803
+ from nemo_platform.cli.commands.skills import registry as _registry
804
+
805
+ captured: list[str] = []
806
+
807
+ class _Capture(logging.Handler):
808
+ def emit(self, record: logging.LogRecord) -> None:
809
+ captured.append(record.getMessage())
810
+
811
+ handler = _Capture(level=logging.WARNING)
812
+ original_level = _registry.logger.level
813
+ _registry.logger.addHandler(handler)
814
+ if original_level > logging.WARNING or original_level == logging.NOTSET:
815
+ _registry.logger.setLevel(logging.WARNING)
816
+ _registry.clear_cache()
817
+ try:
818
+ skills = load_skills()
819
+ finally:
820
+ _registry.logger.removeHandler(handler)
821
+ _registry.logger.setLevel(original_level)
822
+ return skills, captured
823
+
824
+
825
+ def _print_plugin_warnings(plugin_warnings: list[str]) -> None:
826
+ """Surface plugin-discovery warnings before the interactive skills prompt."""
827
+ if not plugin_warnings:
828
+ return
829
+ console.print(" [yellow]Plugin warnings:[/yellow]")
830
+ for msg in plugin_warnings:
831
+ console.print(f" {WARN} {msg}")
832
+ console.print()
833
+
834
+
835
+ _BUILTIN_SOURCE_NAME = "nemo-platform"
836
+
837
+
838
+ def _skill_sources_of(skills: dict[str, Skill]) -> dict[str, list[Skill]]:
839
+ """Group skills by their source (built-in vs each plugin).
840
+
841
+ The built-in source is keyed by ``nemo-platform``; plugin skills are keyed
842
+ by ``Skill.source_plugin``. Returned dict preserves insertion order so the
843
+ built-in group appears first, then plugins in discovery order.
844
+ """
845
+ sources: dict[str, list[Skill]] = {}
846
+ for skill in skills.values():
847
+ key = skill.source_plugin or _BUILTIN_SOURCE_NAME
848
+ sources.setdefault(key, []).append(skill)
849
+ return sources
850
+
851
+
852
+ def _filter_agents_by_scope(agents: list[str], scope: Scope) -> tuple[list[str], list[tuple[str, str]]]:
853
+ """Split agents into (installable, skipped) based on whether each supports the chosen scope.
854
+
855
+ Returns:
856
+ (kept, skipped) where ``skipped`` is a list of (agent_name, reason) tuples.
857
+ """
858
+ kept: list[str] = []
859
+ skipped: list[tuple[str, str]] = []
860
+ for agent in agents:
861
+ installer = get_installer(agent)
862
+ if scope in installer.supported_scopes:
863
+ kept.append(agent)
864
+ else:
865
+ supported = ", ".join(s.value for s in installer.supported_scopes) or "none"
866
+ skipped.append((agent, f"does not support '{scope.value}' scope (supports: {supported})"))
867
+ return kept, skipped
868
+
869
+
870
+ def _print_final_skills_summary(agents: list[str], scope: Scope, skill_names: list[str]) -> None:
871
+ """Print the planned action before final confirmation."""
872
+ if not skill_names or not agents:
873
+ return
874
+ project_root = _find_project_root()
875
+ agent_list = ", ".join(agents)
876
+ console.print(
877
+ f" Installing [bold]{len(skill_names)}[/bold] skill(s) for "
878
+ f"[bold]{agent_list}[/bold] at [bold]{scope.value}[/bold] scope:"
879
+ )
880
+ for agent in agents:
881
+ installer = get_installer(agent)
882
+ # Show the parent directory of one representative skill so the user
883
+ # sees the destination root, not a single SKILL.md path.
884
+ example = installer.get_install_path(scope, project_root, skill_names[0])
885
+ console.print(f" {agent} → {example.parent.parent}/")
886
+ console.print()
887
+
888
+
889
+ def _run_skill_install(
890
+ *,
891
+ agents: list[str],
892
+ scope: Scope,
893
+ skill_names: list[str],
894
+ all_skills: dict[str, Skill],
895
+ project_root: Path,
896
+ ) -> None:
897
+ """Run the actual installer for each agent with the chosen skill subset.
898
+
899
+ Skill names are expected to come from a validated source-selection path
900
+ (interactive multiselect or ``--skills-from`` flag), so any name not in
901
+ ``all_skills`` would be an internal bug. If every agent's install fails,
902
+ raises ``typer.Exit(1)`` so callers in ``--auto`` see a non-zero exit.
903
+ """
904
+ chosen = {name: all_skills[name] for name in skill_names if name in all_skills}
905
+ if not chosen:
906
+ console.print(f" {WARN} No skills selected to install.")
907
+ return
908
+
909
+ successes = 0
910
+ failures = 0
911
+ for agent in agents:
912
+ try:
913
+ installer = get_installer(agent)
914
+ installer.install(scope, project_root, chosen)
915
+ console.print(f" {CHECK} Installed {len(chosen)} skill(s) for {agent}")
916
+ successes += 1
917
+ except Exception as exc:
918
+ console.print(f" {WARN} Failed to install skills for {agent}: {exc}")
919
+ failures += 1
920
+
921
+ if failures and not successes:
922
+ raise typer.Exit(1)
923
+
924
+
925
+ def _parse_csv_flag(value: str | None) -> list[str] | None:
926
+ """Parse a comma-separated CLI flag into a list, dropping empty entries."""
927
+ if value is None:
928
+ return None
929
+ parts = [p.strip() for p in value.split(",")]
930
+ cleaned = [p for p in parts if p]
931
+ return cleaned or None
932
+
933
+
934
+ def _maybe_install_skills(
935
+ auto: bool,
936
+ install_skills: bool | None,
937
+ *,
938
+ skills_agents: list[str] | None = None,
939
+ skills_scope: Scope | None = None,
940
+ skills_from: list[str] | None = None,
941
+ ) -> None:
942
+ """Install coding agent skills if requested.
943
+
944
+ ``--install-skills`` is the master opt-in. ``--skills-agents``,
945
+ ``--skills-scope``, and ``--skills-from`` are filters that narrow what
946
+ gets installed when the master is set; on their own they do nothing in
947
+ non-interactive mode. This mirrors ``_maybe_deploy_agent`` and
948
+ ``_maybe_start_services``, which also require their boolean master flag
949
+ to be explicitly True under ``--auto``.
950
+
951
+ ``--skills-from`` selects by *source* (the built-in ``nemo-platform`` set
952
+ or a plugin name) rather than by individual skill name. Picking one source
953
+ installs every skill that source provides.
954
+
955
+ Interactive mode walks the user through a source multi-select (each source
956
+ expanded to show its skills as read-only sub-labels, with ``s`` to skip the
957
+ whole step), an agent multi-select, a scope choice, and a final
958
+ confirmation; filter flags pre-populate the defaults.
959
+ """
960
+ if install_skills is False:
961
+ return
962
+
963
+ # Validate --skills-agents up-front: a typo like `--skills-agents copex` should
964
+ # fail loudly before any platform work, regardless of detection state.
965
+ if skills_agents:
966
+ for agent in skills_agents:
967
+ get_installer(agent)
968
+
969
+ detected = _detect_coding_agents()
970
+ # --skills-agents overrides detection: an explicit instruction to install for
971
+ # an agent wins over "we didn't find a marker file for it." Detection is still
972
+ # load-bearing as the default when the flag is absent.
973
+ if not detected and not skills_agents:
974
+ if not auto:
975
+ console.print(f" {WARN} No coding agents detected in project (no .cursor/, AGENTS.md, etc.)")
976
+ return
977
+
978
+ all_skills, plugin_warnings = _load_skills_with_warnings()
979
+ if not all_skills:
980
+ console.print(f" {WARN} No NeMo skills available to install.")
981
+ return
982
+
983
+ sources = _skill_sources_of(all_skills)
984
+ source_names = list(sources.keys())
985
+
986
+ # Validate --skills-from up-front, same shape as --skills-agents.
987
+ if skills_from:
988
+ unknown = [s for s in skills_from if s not in sources]
989
+ if unknown:
990
+ known = ", ".join(source_names)
991
+ raise typer.BadParameter(
992
+ f"Unknown skill source(s): {', '.join(unknown)}. Known sources: {known}",
993
+ param_hint="--skills-from",
994
+ )
995
+
996
+ detected_names = [name for _, name in detected]
997
+ # Interactive menu options: detected agents plus any extras the user explicitly
998
+ # asked for. dict.fromkeys preserves order and deduplicates.
999
+ menu_agent_names = list(dict.fromkeys(detected_names + (skills_agents or [])))
1000
+ project_root = _find_project_root()
1001
+ non_interactive = auto or not is_interactive()
1002
+
1003
+ def _skills_for_sources(chosen_sources: list[str]) -> list[str]:
1004
+ return [skill.name for source in chosen_sources for skill in sources[source]]
1005
+
1006
+ if non_interactive:
1007
+ # Non-interactive path requires the master switch to be explicitly True.
1008
+ # Filter flags alone don't opt in (matches --start-services / --deploy-agent).
1009
+ if install_skills is not True:
1010
+ return
1011
+ chosen_agents = skills_agents or detected_names
1012
+ chosen_scope = skills_scope or Scope.PROJECT
1013
+ chosen_sources = skills_from or source_names
1014
+ chosen_skills = _skills_for_sources(chosen_sources)
1015
+ chosen_agents, skipped = _filter_agents_by_scope(chosen_agents, chosen_scope)
1016
+ for agent, reason in skipped:
1017
+ console.print(f" {WARN} Skipping {agent}: {reason}")
1018
+ if not chosen_agents:
1019
+ console.print(f" {WARN} No installable agents for scope '{chosen_scope.value}'.")
1020
+ return
1021
+ _run_skill_install(
1022
+ agents=chosen_agents,
1023
+ scope=chosen_scope,
1024
+ skill_names=chosen_skills,
1025
+ all_skills=all_skills,
1026
+ project_root=project_root,
1027
+ )
1028
+ return
1029
+
1030
+ # Interactive path: sources → agents → scope → confirm.
1031
+ _print_plugin_warnings(plugin_warnings)
1032
+
1033
+ source_defaults = skills_from if skills_from else source_names
1034
+ source_options = [(name, f"{name} (built-in)" if name == _BUILTIN_SOURCE_NAME else name) for name in source_names]
1035
+ source_sub_labels = {name: [skill.name for skill in sources[name]] for name in source_names}
1036
+ chosen_sources = prompt_multiselect(
1037
+ message="Install skills:",
1038
+ options=source_options,
1039
+ defaults=source_defaults,
1040
+ sub_labels=source_sub_labels,
1041
+ min_choices=1,
1042
+ allow_skip=True,
1043
+ indent=2,
1044
+ )
1045
+ if chosen_sources is None:
1046
+ console.print(f" {WARN} Skipping skill installation.")
1047
+ return
1048
+ chosen_skills = _skills_for_sources(chosen_sources)
1049
+
1050
+ agent_defaults = skills_agents if skills_agents else detected_names
1051
+ chosen_agents = prompt_multiselect(
1052
+ message="Install skills for which agents?",
1053
+ options=[(name, get_installer(name).display_name) for name in menu_agent_names],
1054
+ defaults=agent_defaults,
1055
+ min_choices=1,
1056
+ indent=2,
1057
+ )
1058
+
1059
+ scope_default = (skills_scope or Scope.PROJECT).value
1060
+ chosen_scope = Scope(
1061
+ prompt_choice(
1062
+ message="Install scope:",
1063
+ options=[
1064
+ (Scope.PROJECT.value, "Local (this repo: .agents/, .cursor/, .claude/, ...)"),
1065
+ (Scope.USER.value, "Global (user home: ~/.agents/, ~/.claude/, ...)"),
1066
+ ],
1067
+ default=scope_default,
1068
+ indent=2,
1069
+ )
1070
+ )
1071
+
1072
+ chosen_agents, skipped = _filter_agents_by_scope(chosen_agents, chosen_scope)
1073
+ for agent, reason in skipped:
1074
+ console.print(f" {WARN} Skipping {agent}: {reason}")
1075
+ if not chosen_agents:
1076
+ console.print(f" {WARN} No installable agents for scope '{chosen_scope.value}'.")
1077
+ return
1078
+
1079
+ _print_final_skills_summary(chosen_agents, chosen_scope, chosen_skills)
1080
+ if not prompt_confirm("Proceed?", default=True, indent=2):
1081
+ return
1082
+
1083
+ _run_skill_install(
1084
+ agents=chosen_agents,
1085
+ scope=chosen_scope,
1086
+ skill_names=chosen_skills,
1087
+ all_skills=all_skills,
1088
+ project_root=project_root,
1089
+ )
1090
+
1091
+
1092
+ # ---------------------------------------------------------------------------
1093
+ # Agent deployment
1094
+ # ---------------------------------------------------------------------------
1095
+
1096
+
1097
+ def _agents_plugin_available() -> bool:
1098
+ """Return True if the nemo-agents plugin is importable."""
1099
+ return importlib.util.find_spec("nemo_agents_plugin") is not None
1100
+
1101
+
1102
+ def _agent_config_path() -> Traversable | None:
1103
+ """Return the path to the calculator-agent demo config YAML, or None."""
1104
+ try:
1105
+ candidate = files("calculator_agent").joinpath("calculator-agent.yml")
1106
+ if candidate.is_file():
1107
+ return candidate
1108
+ except (ImportError, ModuleNotFoundError):
1109
+ logger.debug("calculator_agent package not importable; demo agent config unavailable", exc_info=True)
1110
+
1111
+ return None
1112
+
1113
+
1114
+ def _agent_exists(base_url: str, workspace: str) -> bool:
1115
+ """Return True if the demo agent already exists on the platform."""
1116
+ try:
1117
+ resp = httpx.get(
1118
+ f"{base_url.rstrip('/')}/apis/agents/v2/workspaces/{workspace}/agents/{_DEMO_AGENT_NAME}",
1119
+ timeout=10.0,
1120
+ )
1121
+ return resp.status_code == 200
1122
+ except Exception:
1123
+ return False
1124
+
1125
+
1126
+ def _agents_api_ready(base_url: str, workspace: str) -> bool:
1127
+ """Return True if the agents API is responding."""
1128
+ try:
1129
+ resp = httpx.get(
1130
+ f"{base_url.rstrip('/')}/apis/agents/v2/workspaces/{workspace}/agents",
1131
+ timeout=3.0,
1132
+ )
1133
+ return resp.status_code == 200
1134
+ except Exception:
1135
+ return False
1136
+
1137
+
1138
+ def _deploy_demo_agent(base_url: str, workspace: str, config_path: Traversable, default_model: str) -> bool:
1139
+ """Create and deploy the demo calculator agent. Returns True on success."""
1140
+ from nemo_agents_plugin.utils import expand_env_vars
1141
+
1142
+ api_base = base_url.rstrip("/")
1143
+
1144
+ if not _agent_exists(base_url, workspace):
1145
+ config_dict = _yaml.safe_load(config_path.read_text(encoding="utf-8"))
1146
+ config_dict = expand_env_vars(config_dict, vars_dict={"NEMO_DEFAULT_MODEL": default_model})
1147
+ payload = {"name": _DEMO_AGENT_NAME, "description": "Demo calculator agent", "config": config_dict}
1148
+ resp = httpx.post(
1149
+ f"{api_base}/apis/agents/v2/workspaces/{workspace}/agents",
1150
+ json=payload,
1151
+ timeout=30.0,
1152
+ )
1153
+ resp.raise_for_status()
1154
+ console.print(f" {CHECK} Created agent '{_DEMO_AGENT_NAME}'")
1155
+ else:
1156
+ console.print(f" {CHECK} Agent '{_DEMO_AGENT_NAME}' already exists")
1157
+
1158
+ resp = httpx.post(
1159
+ f"{api_base}/apis/agents/v2/workspaces/{workspace}/deployments",
1160
+ json={"agent": _DEMO_AGENT_NAME},
1161
+ timeout=30.0,
1162
+ )
1163
+ if resp.status_code == 409:
1164
+ console.print(f" {CHECK} Agent '{_DEMO_AGENT_NAME}' already deployed")
1165
+ return True
1166
+
1167
+ resp.raise_for_status()
1168
+ deployment_name = resp.json().get("name", "")
1169
+ console.print(f" {CHECK} Deployed agent '{_DEMO_AGENT_NAME}'")
1170
+
1171
+ # Poll the specific deployment we just created by name, not the full
1172
+ # list. Previous runs may leave stale "failed" deployments that would
1173
+ # confuse a list-and-scan approach.
1174
+ start = time.monotonic()
1175
+ deadline = start + _AGENT_DEPLOY_TIMEOUT_SECONDS
1176
+ with console.status("[bold cyan]Waiting for agent deployment...") as spinner:
1177
+ while time.monotonic() < deadline:
1178
+ elapsed = int(time.monotonic() - start)
1179
+ spinner.update(f"[bold cyan]Waiting for agent deployment... ({elapsed}s)")
1180
+ try:
1181
+ dep_resp = httpx.get(
1182
+ f"{api_base}/apis/agents/v2/workspaces/{workspace}/deployments/{deployment_name}",
1183
+ timeout=3.0,
1184
+ )
1185
+ if dep_resp.status_code == 200:
1186
+ dep_status = dep_resp.json().get("status", "")
1187
+ if dep_status == "running":
1188
+ return True
1189
+ if dep_status == "failed":
1190
+ console.print(f" {CROSS} Agent deployment failed")
1191
+ return False
1192
+ except Exception:
1193
+ logger.debug("Agent deployment status poll failed", exc_info=True)
1194
+ _pause(_AGENT_DEPLOY_POLL_INTERVAL)
1195
+
1196
+ console.print(f" {WARN} Agent deployment did not reach running state within {_AGENT_DEPLOY_TIMEOUT_SECONDS}s")
1197
+ return False
1198
+
1199
+
1200
+ def _maybe_deploy_agent(
1201
+ base_url: str,
1202
+ workspace: str,
1203
+ auto: bool,
1204
+ deploy_agent: bool | None,
1205
+ default_model: str | None = None,
1206
+ ) -> bool:
1207
+ """Optionally deploy the demo calculator agent.
1208
+
1209
+ In interactive mode (auto=False), prompts the user if deploy_agent is None.
1210
+ Default is **no** -- the demo is opt-in for users who don't have their own
1211
+ agent yet. In auto mode, only deploys if deploy_agent is explicitly True.
1212
+
1213
+ Returns True if the agent was deployed (used by CTA messaging).
1214
+ """
1215
+ if not _agents_plugin_available():
1216
+ console.print(f" {WARN} nemo-agents plugin not installed, skipping agent deployment")
1217
+ console.print(" Run [cyan]make bootstrap[/cyan] from the repo root to install all plugins,")
1218
+ console.print(" then re-run: [cyan]nemo setup --deploy-agent[/cyan]")
1219
+ return False
1220
+
1221
+ should_deploy = deploy_agent
1222
+ if should_deploy is None:
1223
+ if auto:
1224
+ return False
1225
+ console.print(
1226
+ " NeMo Platform optimizes AI agents. If you don't have your own\n"
1227
+ " agent yet, you can deploy a demo calculator agent to try things out.\n"
1228
+ )
1229
+ should_deploy = (
1230
+ prompt_choice(
1231
+ message="Deploy the demo agent?",
1232
+ options=[("no", "No, skip"), ("yes", "Yes, deploy it")],
1233
+ default="no",
1234
+ )
1235
+ == "yes"
1236
+ )
1237
+
1238
+ if not should_deploy:
1239
+ return False
1240
+
1241
+ if not default_model:
1242
+ console.print(
1243
+ f" {WARN} No default model selected, skipping agent deployment "
1244
+ "(the demo agent template needs a resolved model)"
1245
+ )
1246
+ return False
1247
+
1248
+ config_path = _agent_config_path()
1249
+ if config_path is None:
1250
+ console.print(f" {WARN} Could not find calculator-agent config YAML, skipping agent deployment")
1251
+ return False
1252
+
1253
+ start = time.monotonic()
1254
+ deadline = start + _AGENT_API_READINESS_TIMEOUT
1255
+ api_ready = False
1256
+ with console.status("[bold cyan]Waiting for agents API...") as spinner:
1257
+ while time.monotonic() < deadline:
1258
+ elapsed = int(time.monotonic() - start)
1259
+ spinner.update(f"[bold cyan]Waiting for agents API... ({elapsed}s)")
1260
+ if _agents_api_ready(base_url, workspace):
1261
+ api_ready = True
1262
+ break
1263
+ _pause(_AGENT_API_READINESS_POLL_INTERVAL)
1264
+ if not api_ready:
1265
+ console.print(f" {WARN} Agents API not ready at {base_url}, skipping agent deployment")
1266
+ console.print(" Ensure the agents service is running (e.g. [cyan]nemo services run --services agents[/cyan])")
1267
+ return False
1268
+
1269
+ try:
1270
+ return _deploy_demo_agent(base_url, workspace, config_path, default_model=default_model)
1271
+ except Exception as exc:
1272
+ console.print(f" {WARN} Agent deployment failed: {exc}")
1273
+ return False
1274
+
1275
+
1276
+ # ---------------------------------------------------------------------------
1277
+ # Interactive flow helpers
1278
+ # ---------------------------------------------------------------------------
1279
+
1280
+
1281
+ def _select_provider() -> KnownProvider | None:
1282
+ """Prompt user to pick one provider. Returns None for 'custom'."""
1283
+ options = [(p.name, f"{p.label:<20s} {p.description}") for p in KNOWN_PROVIDERS]
1284
+ options.append(("custom", "Custom provider Enter URL and key manually"))
1285
+
1286
+ result = prompt_choice(
1287
+ message="",
1288
+ options=options,
1289
+ default=KNOWN_PROVIDERS[0].name,
1290
+ )
1291
+
1292
+ if result == "custom":
1293
+ return None
1294
+ return _KNOWN_PROVIDERS_BY_NAME[result]
1295
+
1296
+
1297
+ def _prompt_custom_provider() -> tuple[str, str, str | None]:
1298
+ """Prompt for custom provider details. Returns (name, host_url, api_key_or_none)."""
1299
+ name = prompt_text(
1300
+ "Provider name: ",
1301
+ validator=provider_name_validator(),
1302
+ hint="Start with a lowercase letter, then lowercase letters, digits, or hyphens; 2-63 chars (e.g. my-vllm-provider)",
1303
+ ).strip()
1304
+
1305
+ host_url = prompt_text("Provider base URL: ").strip()
1306
+ if not host_url:
1307
+ raise typer.Exit(1)
1308
+
1309
+ api_key = prompt_password("API key (leave empty if none): ").strip() or None
1310
+
1311
+ return name, host_url, api_key
1312
+
1313
+
1314
+ def _collect_credential(provider: KnownProvider) -> str:
1315
+ """Prompt for the API key, checking the env var first."""
1316
+ if not provider.requires_api_key:
1317
+ return ""
1318
+
1319
+ env_val = os.environ.get(provider.env_var or "") if provider.env_var else None
1320
+ if env_val:
1321
+ masked = f"***{env_val[-4:]}" if len(env_val) > 4 else "****"
1322
+ console.print(f" Found {provider.env_var} in environment ({masked})")
1323
+ key = prompt_password(f"{provider.label} API key [{masked}]: ")
1324
+ return key.strip() if key.strip() else env_val
1325
+
1326
+ key = prompt_password(
1327
+ f"{provider.label} API key: ",
1328
+ validator=non_empty_validator("API key"),
1329
+ )
1330
+ return key.strip()
1331
+
1332
+
1333
+ def _register_provider_interactive(
1334
+ client: NeMoPlatform,
1335
+ *,
1336
+ provider_name: str,
1337
+ host_url: str,
1338
+ api_key: str | None,
1339
+ workspace: str,
1340
+ auth_header_format: str | None = None,
1341
+ default_extra_headers: dict[str, str] | None = None,
1342
+ ) -> None:
1343
+ """Create or update secret + provider for idempotent re-runs."""
1344
+ secret_name = f"{provider_name}-api-key" if api_key else None
1345
+
1346
+ if secret_name:
1347
+ if _secret_exists(client, secret_name, workspace):
1348
+ _update_secret(client, secret_name, api_key, workspace)
1349
+ console.print(f" {CHECK} Updated secret '{secret_name}'")
1350
+ else:
1351
+ _create_secret(client, secret_name, api_key, workspace)
1352
+ console.print(f" {CHECK} Created secret '{secret_name}'")
1353
+
1354
+ if _provider_exists(client, provider_name, workspace):
1355
+ _update_provider(
1356
+ client,
1357
+ name=provider_name,
1358
+ host_url=host_url,
1359
+ secret_name=secret_name,
1360
+ workspace=workspace,
1361
+ default_extra_headers=default_extra_headers,
1362
+ )
1363
+ console.print(f" {CHECK} Updated provider '{provider_name}' ({host_url})")
1364
+ else:
1365
+ _create_provider(
1366
+ client,
1367
+ name=provider_name,
1368
+ host_url=host_url,
1369
+ secret_name=secret_name,
1370
+ workspace=workspace,
1371
+ auth_header_format=auth_header_format,
1372
+ default_extra_headers=default_extra_headers,
1373
+ )
1374
+ console.print(f" {CHECK} Registered provider '{provider_name}' ({host_url})")
1375
+
1376
+
1377
+ def _validate_api_key(
1378
+ provider_name: str,
1379
+ host_url: str,
1380
+ api_key: str | None,
1381
+ *,
1382
+ auth_header_format: str | None = None,
1383
+ default_extra_headers: dict[str, str] | None = None,
1384
+ timeout: float = _KEY_VALIDATION_TIMEOUT,
1385
+ ) -> KeyValidationResult:
1386
+ """Probe the provider with the API key to detect auth failures early.
1387
+
1388
+ Makes a single lightweight request to an auth-required endpoint.
1389
+ Returns ``passed=False`` only on a definitive 401/403 rejection.
1390
+ Network errors and unknown providers are treated as *passed* to avoid
1391
+ blocking setup when the provider is unreachable.
1392
+ """
1393
+ if not api_key:
1394
+ return KeyValidationResult(passed=True, message="")
1395
+
1396
+ probe = _PROBE_CONFIGS.get(provider_name)
1397
+ if probe is None:
1398
+ return KeyValidationResult(
1399
+ passed=True,
1400
+ message=f"No validation probe configured for provider '{provider_name}'; skipping key check.",
1401
+ )
1402
+
1403
+ headers: dict[str, str] = {}
1404
+ if auth_header_format:
1405
+ header_name, _, template = auth_header_format.partition(":")
1406
+ headers[header_name.strip()] = template.strip().replace("{{ auth_secret }}", api_key)
1407
+ else:
1408
+ headers["Authorization"] = f"Bearer {api_key}"
1409
+
1410
+ if default_extra_headers:
1411
+ headers.update(default_extra_headers)
1412
+
1413
+ url = f"{host_url.rstrip('/')}/{probe.path}"
1414
+
1415
+ try:
1416
+ resp = httpx.request(
1417
+ probe.method,
1418
+ url,
1419
+ headers=headers,
1420
+ json=probe.body,
1421
+ timeout=timeout,
1422
+ )
1423
+ if resp.status_code in _KEY_REJECTED_STATUS_CODES:
1424
+ return KeyValidationResult(passed=False, message=_KEY_REJECTED_MESSAGE)
1425
+ if 200 <= resp.status_code < 300:
1426
+ return KeyValidationResult(passed=True, message="")
1427
+ return KeyValidationResult(
1428
+ passed=True,
1429
+ message=f"Could not validate API key (received HTTP {resp.status_code}).",
1430
+ )
1431
+ except httpx.TimeoutException:
1432
+ logger.debug("API key validation timed out for '%s'", provider_name)
1433
+ return KeyValidationResult(passed=True, message="Could not validate API key (request timed out).")
1434
+ except Exception as exc:
1435
+ logger.debug("API key validation failed for '%s': %s", provider_name, exc)
1436
+ return KeyValidationResult(passed=True, message=f"Could not validate API key ({exc}).")
1437
+
1438
+
1439
+ def _select_default_model(client: NeMoPlatform, workspace: str) -> str | None:
1440
+ """Let the user pick a default model from discovered models."""
1441
+ display_models = _get_all_model_choices(client, workspace)
1442
+ if not display_models:
1443
+ console.print(f" {WARN} No models discovered yet. You can set a default later.")
1444
+ return None
1445
+
1446
+ result = prompt_select(
1447
+ "Choose your default model:",
1448
+ choices=display_models,
1449
+ )
1450
+ return result
1451
+
1452
+
1453
+ def _save_default_model(cli_context: CLIContext, model_entity_id: str) -> None:
1454
+ """Persist the default model to the CLI config file."""
1455
+ context = cli_context.get_sdk_context()
1456
+ Config.write({"default_model": model_entity_id}, context_name=context.context_name)
1457
+
1458
+
1459
+ def _check_ollama_running(host_url: str) -> bool:
1460
+ """Probe Ollama endpoint to check if it's running."""
1461
+ try:
1462
+ resp = httpx.get(f"{host_url.rstrip('/')}/models", timeout=3.0)
1463
+ return resp.status_code == 200
1464
+ except Exception:
1465
+ return False
1466
+
1467
+
1468
+ # ---------------------------------------------------------------------------
1469
+ # Auto (non-interactive) mode
1470
+ # ---------------------------------------------------------------------------
1471
+
1472
+
1473
+ def _auto_setup(client: NeMoPlatform, workspace: str) -> bool:
1474
+ """Register a provider from environment variables. Returns True on success."""
1475
+ for key_var, url_var in _AUTO_ENV_VARS:
1476
+ api_key = os.environ.get(key_var)
1477
+ if not api_key:
1478
+ continue
1479
+
1480
+ base_url = os.environ.get(url_var, "").strip() if url_var else ""
1481
+ if base_url:
1482
+ known = _resolve_provider_for_url(base_url)
1483
+ if known:
1484
+ provider_name = known.name
1485
+ else:
1486
+ hostname = urlparse(base_url).hostname or "custom"
1487
+ provider_name = hostname.replace(".", "-")
1488
+ host_url = base_url
1489
+ auth_header_format = known.auth_header_format if known else None
1490
+ default_extra_headers = known.default_extra_headers if known else None
1491
+ else:
1492
+ for p in KNOWN_PROVIDERS:
1493
+ if p.env_var == key_var and p.requires_api_key:
1494
+ provider_name = p.name
1495
+ host_url = p.host_url
1496
+ auth_header_format = p.auth_header_format
1497
+ default_extra_headers = p.default_extra_headers
1498
+ break
1499
+ else:
1500
+ continue
1501
+
1502
+ key_result = _validate_api_key(
1503
+ provider_name,
1504
+ host_url,
1505
+ api_key,
1506
+ auth_header_format=auth_header_format,
1507
+ default_extra_headers=default_extra_headers,
1508
+ )
1509
+ if not key_result.passed:
1510
+ console.print(f" {CROSS} {key_result.message}")
1511
+ console.print(f" Check the value of ${key_var} and try again.")
1512
+ raise typer.Exit(1)
1513
+ if key_result.message:
1514
+ console.print(f" {WARN} {key_result.message}")
1515
+
1516
+ secret_name = f"{provider_name}-api-key"
1517
+ if _secret_exists(client, secret_name, workspace):
1518
+ _update_secret(client, secret_name, api_key, workspace)
1519
+ console.print(f" {CHECK} Updated secret '{secret_name}' (from ${key_var})")
1520
+ else:
1521
+ _create_secret(client, secret_name, api_key, workspace)
1522
+ console.print(f" {CHECK} Created secret '{secret_name}' (from ${key_var})")
1523
+
1524
+ if _provider_exists(client, provider_name, workspace):
1525
+ _update_provider(
1526
+ client,
1527
+ name=provider_name,
1528
+ host_url=host_url,
1529
+ secret_name=secret_name,
1530
+ workspace=workspace,
1531
+ default_extra_headers=default_extra_headers,
1532
+ )
1533
+ console.print(f" {CHECK} Updated provider '{provider_name}' ({host_url})")
1534
+ else:
1535
+ _create_provider(
1536
+ client,
1537
+ name=provider_name,
1538
+ host_url=host_url,
1539
+ secret_name=secret_name,
1540
+ workspace=workspace,
1541
+ auth_header_format=auth_header_format,
1542
+ default_extra_headers=default_extra_headers,
1543
+ )
1544
+ console.print(f" {CHECK} Registered provider '{provider_name}' ({host_url})")
1545
+
1546
+ return True
1547
+
1548
+ return False
1549
+
1550
+
1551
+ # ---------------------------------------------------------------------------
1552
+ # Main command
1553
+ # ---------------------------------------------------------------------------
1554
+
1555
+
1556
+ @handle_errors
1557
+ def setup_command(
1558
+ ctx: typer.Context,
1559
+ auto: Annotated[
1560
+ bool,
1561
+ typer.Option("--auto", help="Non-interactive mode: register provider from environment variables"),
1562
+ ] = False,
1563
+ workspace: Annotated[
1564
+ str,
1565
+ typer.Option("--workspace", "-w", help="Target workspace"),
1566
+ ] = "default",
1567
+ start_services: Annotated[
1568
+ bool | None,
1569
+ typer.Option("--start-services/--no-start-services", help="Start local platform services"),
1570
+ ] = None,
1571
+ install_skills: Annotated[
1572
+ bool | None,
1573
+ typer.Option("--install-skills/--no-install-skills", help="Install NeMo skills for coding agents"),
1574
+ ] = None,
1575
+ skills_agents: Annotated[
1576
+ str | None,
1577
+ typer.Option(
1578
+ "--skills-agents",
1579
+ help=(
1580
+ "Comma-separated list of agents to install skills for (e.g. 'codex,cursor'). "
1581
+ "Default: all detected. Only applied when --install-skills is set."
1582
+ ),
1583
+ ),
1584
+ ] = None,
1585
+ skills_scope: Annotated[
1586
+ Scope | None,
1587
+ typer.Option(
1588
+ "--skills-scope",
1589
+ help=(
1590
+ "Install scope for skills: 'project' (this repo) or 'user' (home). "
1591
+ "Default: project. Only applied when --install-skills is set."
1592
+ ),
1593
+ case_sensitive=False,
1594
+ ),
1595
+ ] = None,
1596
+ skills_from: Annotated[
1597
+ str | None,
1598
+ typer.Option(
1599
+ "--skills-from",
1600
+ help=(
1601
+ "Comma-separated list of skill sources to install from "
1602
+ "(e.g. 'nemo-platform,nemo-evaluator-plugin'). Use 'nemo-platform' "
1603
+ "for the built-in set. Default: all sources. "
1604
+ "Only applied when --install-skills is set."
1605
+ ),
1606
+ ),
1607
+ ] = None,
1608
+ deploy_agent: Annotated[
1609
+ bool | None,
1610
+ typer.Option("--deploy-agent/--no-deploy-agent", help="Deploy the demo calculator agent"),
1611
+ ] = None,
1612
+ ready_timeout: Annotated[
1613
+ int | None,
1614
+ typer.Option(
1615
+ "--ready-timeout",
1616
+ help=f"Seconds to wait for platform readiness (default: {_SERVICE_STARTUP_TIMEOUT_SECONDS})",
1617
+ ),
1618
+ ] = None,
1619
+ ) -> None:
1620
+ """Set up NeMo Platform: start services, configure a provider, install skills.
1621
+
1622
+ Walks through starting local services, selecting a provider, entering
1623
+ credentials, registering the provider with the platform, picking a
1624
+ default model, installing coding agent skills, and optionally deploying
1625
+ a demo agent.
1626
+
1627
+ Requires an interactive terminal (TTY). In non-interactive contexts
1628
+ (CI, piped input), pass --auto to use environment variables instead.
1629
+
1630
+ Use --auto for non-interactive setup from environment variables
1631
+ (NEMO_DEFAULT_INFERENCE_KEY, NVIDIA_API_KEY, OPENAI_API_KEY,
1632
+ ANTHROPIC_API_KEY, GEMINI_API_KEY).
1633
+ Override the default model with NEMO_DEFAULT_MODEL.
1634
+
1635
+ Examples:
1636
+ nemo setup
1637
+ nemo setup --auto
1638
+ nemo setup --auto --start-services --install-skills --deploy-agent
1639
+ nemo setup --auto --start-services --ready-timeout 360
1640
+ nemo setup --workspace my-workspace
1641
+ nemo setup --no-install-skills --no-deploy-agent
1642
+ """
1643
+ cli_context: CLIContext = ctx.obj
1644
+ base_url = cli_context.get_base_url()
1645
+
1646
+ console.print("\n[bold cyan]NeMo Platform Setup[/bold cyan]\n")
1647
+
1648
+ if not auto and not is_interactive():
1649
+ console.print(f"\n{CROSS} Detected non-interactive shell. Pass [bold]--auto[/bold] or run in a TTY.\n")
1650
+ raise typer.Exit(1)
1651
+
1652
+ effective_timeout = _SERVICE_STARTUP_TIMEOUT_SECONDS if ready_timeout is None else ready_timeout
1653
+ if effective_timeout <= 0:
1654
+ raise typer.BadParameter("--ready-timeout must be greater than 0", param_hint="--ready-timeout")
1655
+ _maybe_start_services(base_url, auto, start_services, timeout=effective_timeout)
1656
+
1657
+ if not _check_platform_reachable_with_retries(base_url):
1658
+ console.print(f"\n{CROSS} Cannot reach platform at {base_url}")
1659
+ raise typer.Exit(1)
1660
+
1661
+ console.print(f"{CHECK} Platform reachable at {base_url}\n")
1662
+
1663
+ # Ensure the config file exists on disk so later Config.write() calls
1664
+ # (e.g. saving the default model) can find the cluster and context.
1665
+ # Without this, a fresh install (no config.yaml) hits "Cluster
1666
+ # 'default-cluster' does not exist" when _save_default_model runs.
1667
+ _bootstrap_config_if_missing(base_url, workspace)
1668
+ cli_context.reset_sdk_context()
1669
+
1670
+ client = cli_context.get_client()
1671
+
1672
+ try:
1673
+ client.workspaces.retrieve(workspace)
1674
+ except Exception:
1675
+ try:
1676
+ client.workspaces.create(name=workspace)
1677
+ console.print(f" {CHECK} Created workspace '{workspace}'")
1678
+ except Exception as create_err:
1679
+ # Distinguish a race (workspace appeared between retrieve and create)
1680
+ # from a real failure (permissions, server error).
1681
+ try:
1682
+ client.workspaces.retrieve(workspace)
1683
+ except Exception:
1684
+ raise create_err from None
1685
+
1686
+ skills_agents_list = _parse_csv_flag(skills_agents)
1687
+ skills_from_list = _parse_csv_flag(skills_from)
1688
+
1689
+ if auto:
1690
+ _run_auto_mode(
1691
+ cli_context,
1692
+ client,
1693
+ workspace,
1694
+ base_url,
1695
+ install_skills,
1696
+ deploy_agent,
1697
+ skills_agents=skills_agents_list,
1698
+ skills_scope=skills_scope,
1699
+ skills_from=skills_from_list,
1700
+ )
1701
+ else:
1702
+ _run_interactive_mode(
1703
+ cli_context,
1704
+ client,
1705
+ workspace,
1706
+ base_url,
1707
+ install_skills,
1708
+ deploy_agent,
1709
+ skills_agents=skills_agents_list,
1710
+ skills_scope=skills_scope,
1711
+ skills_from=skills_from_list,
1712
+ )
1713
+
1714
+
1715
+ def _run_auto_mode(
1716
+ cli_context: CLIContext,
1717
+ client: NeMoPlatform,
1718
+ workspace: str,
1719
+ base_url: str,
1720
+ install_skills: bool | None,
1721
+ deploy_agent: bool | None,
1722
+ *,
1723
+ skills_agents: list[str] | None = None,
1724
+ skills_scope: Scope | None = None,
1725
+ skills_from: list[str] | None = None,
1726
+ ) -> None:
1727
+ """Non-interactive provider registration from environment variables."""
1728
+ console.print("[bold]Auto-detecting provider from environment...[/bold]\n")
1729
+ if not _auto_setup(client, workspace):
1730
+ console.print(f"{CROSS} No provider credentials found in environment.")
1731
+ env_var_names = ", ".join(key for key, _ in _AUTO_ENV_VARS)
1732
+ console.print(f" Set one of: {env_var_names}")
1733
+ raise typer.Exit(1)
1734
+
1735
+ console.print("\n Waiting for model discovery...")
1736
+ entity_ids: list[str] = []
1737
+ for attempt in range(_MODEL_DISCOVERY_MAX_ROUNDS):
1738
+ deadline = time.time() + _MODEL_DISCOVERY_ROUND_SECONDS
1739
+ while time.time() < deadline:
1740
+ entity_ids = _get_all_model_entity_ids(client, workspace)
1741
+ if entity_ids:
1742
+ break
1743
+ _pause(_MODEL_DISCOVERY_POLL_INTERVAL)
1744
+ if entity_ids:
1745
+ break
1746
+ if attempt < _MODEL_DISCOVERY_MAX_ROUNDS - 1:
1747
+ console.print(f" {WARN} Models not available yet, retrying...")
1748
+
1749
+ default_model = os.environ.get("NEMO_DEFAULT_MODEL", "").strip()
1750
+ if not default_model and entity_ids:
1751
+ default_model = entity_ids[0]
1752
+
1753
+ if default_model:
1754
+ _save_default_model(cli_context, default_model)
1755
+ console.print(f" {CHECK} Default model: {default_model}")
1756
+ else:
1757
+ console.print(f" {WARN} No default model set (no models discovered yet)")
1758
+ console.print(" Run [cyan]nemo setup[/cyan] again after models sync, or set via env var:")
1759
+ console.print(" [cyan]export NEMO_DEFAULT_MODEL=<model>[/cyan]")
1760
+
1761
+ _maybe_install_skills(
1762
+ auto=True,
1763
+ install_skills=install_skills,
1764
+ skills_agents=skills_agents,
1765
+ skills_scope=skills_scope,
1766
+ skills_from=skills_from,
1767
+ )
1768
+ _maybe_deploy_agent(base_url, workspace, auto=True, deploy_agent=deploy_agent, default_model=default_model)
1769
+
1770
+ if _verify_platform_health(base_url):
1771
+ console.print(f"\n{CHECK} [green]Setup complete![/green]")
1772
+ else:
1773
+ raise typer.Exit(1)
1774
+
1775
+
1776
+ def _run_interactive_mode(
1777
+ cli_context: CLIContext,
1778
+ client: NeMoPlatform,
1779
+ workspace: str,
1780
+ base_url: str,
1781
+ install_skills: bool | None,
1782
+ deploy_agent: bool | None,
1783
+ *,
1784
+ skills_agents: list[str] | None = None,
1785
+ skills_scope: Scope | None = None,
1786
+ skills_from: list[str] | None = None,
1787
+ ) -> None:
1788
+ """Walk the user through provider selection, credential entry, and model choice."""
1789
+ try:
1790
+ provider_name, host_url, api_key, auth_header_format, default_extra_headers = _interactive_collect_provider()
1791
+
1792
+ if api_key:
1793
+ console.print("\n Validating API key...")
1794
+ key_result = _validate_api_key(
1795
+ provider_name,
1796
+ host_url,
1797
+ api_key,
1798
+ auth_header_format=auth_header_format,
1799
+ default_extra_headers=default_extra_headers,
1800
+ )
1801
+ if not key_result.passed:
1802
+ console.print(f" {CROSS} {key_result.message}")
1803
+ console.print(" Please check your API key and run [cyan]nemo setup[/cyan] again.")
1804
+ raise typer.Exit(1)
1805
+ if key_result.message:
1806
+ console.print(f" {WARN} {key_result.message}")
1807
+ else:
1808
+ console.print(f" {CHECK} API key validated")
1809
+
1810
+ console.print("\n[bold]Step 3: Register model provider[/bold]\n")
1811
+ _register_provider_interactive(
1812
+ client,
1813
+ provider_name=provider_name,
1814
+ host_url=host_url,
1815
+ api_key=api_key,
1816
+ workspace=workspace,
1817
+ auth_header_format=auth_header_format,
1818
+ default_extra_headers=default_extra_headers,
1819
+ )
1820
+
1821
+ console.print("\n[bold]Step 4: Discover models[/bold]\n")
1822
+ console.print(" Waiting for model discovery...")
1823
+ models = _wait_for_models(client, provider_name, workspace, host_url=host_url)
1824
+ if models:
1825
+ console.print(f" {CHECK} Found {len(models)} model(s)")
1826
+ else:
1827
+ console.print(f" {WARN} No models discovered yet (provider may still be syncing)")
1828
+
1829
+ console.print("\n[bold]Step 5: Choose default model[/bold]\n")
1830
+ fallback_model_choices = _get_all_model_choices(client, workspace) if not models else []
1831
+ if not models and fallback_model_choices:
1832
+ console.print(f" {WARN} Models from existing providers are available, but not from '{provider_name}' yet.")
1833
+
1834
+ default_model = _select_default_model(client, workspace) if models else None
1835
+ if default_model:
1836
+ _save_default_model(cli_context, default_model)
1837
+ console.print(f" {CHECK} Default model set to {_display_model_name(default_model)}")
1838
+ else:
1839
+ console.print(f" {WARN} No default model set for this provider yet.")
1840
+ console.print(" Run [cyan]nemo setup[/cyan] again after models sync")
1841
+
1842
+ console.print("\n[bold]Step 6: Install skills[/bold]\n")
1843
+ _maybe_install_skills(
1844
+ auto=False,
1845
+ install_skills=install_skills,
1846
+ skills_agents=skills_agents,
1847
+ skills_scope=skills_scope,
1848
+ skills_from=skills_from,
1849
+ )
1850
+
1851
+ console.print("\n[bold]Step 7: Demo agent (optional)[/bold]\n")
1852
+ demo_deployed = _maybe_deploy_agent(
1853
+ base_url, workspace, auto=False, deploy_agent=deploy_agent, default_model=default_model
1854
+ )
1855
+
1856
+ _print_onboarding(base_url, provider_name, default_model, demo_deployed=demo_deployed)
1857
+
1858
+ except UserCancelled:
1859
+ console.print(f"\n{WARN} Setup cancelled.")
1860
+ raise typer.Exit(0) from None
1861
+
1862
+
1863
+ def _interactive_collect_provider() -> tuple[str, str, str | None, str | None, dict[str, str] | None]:
1864
+ """Steps 1-2: select provider and collect credentials.
1865
+
1866
+ Returns (provider_name, host_url, api_key, auth_header_format, default_extra_headers).
1867
+ """
1868
+ console.print("[bold]Step 1: Choose a model provider[/bold]\n")
1869
+ selected = _select_provider()
1870
+
1871
+ if selected is None:
1872
+ name, host_url, api_key = _prompt_custom_provider()
1873
+ return name, host_url, api_key, None, None
1874
+
1875
+ if selected.name == "ollama":
1876
+ if not _check_ollama_running(selected.host_url):
1877
+ console.print(f"\n {WARN} Ollama does not appear to be running at {selected.host_url}")
1878
+ console.print(" Make sure Ollama is started before using it for inference.")
1879
+ else:
1880
+ console.print(f"\n {CHECK} Ollama detected at {selected.host_url}")
1881
+
1882
+ if selected.requires_api_key:
1883
+ console.print("\n[bold]Step 2: Enter API key[/bold]\n")
1884
+ api_key: str | None = _collect_credential(selected)
1885
+ else:
1886
+ api_key = None
1887
+
1888
+ return selected.name, selected.host_url, api_key, selected.auth_header_format, selected.default_extra_headers
1889
+
1890
+
1891
+ def _render_onboarding_card(value: str) -> None:
1892
+ """Print a Rich Panel card for the selected onboarding path."""
1893
+ path = _ONBOARDING_PATHS_BY_VALUE.get(value)
1894
+ if path is None:
1895
+ return
1896
+
1897
+ lines: list[str] = []
1898
+ if path.note:
1899
+ lines.append(f" [bold]{path.note}[/bold]")
1900
+ lines.append("")
1901
+ lines.append(" [bold]Ask your coding agent:[/bold]")
1902
+ lines.append(f' [cyan]"{path.skill_prompt}"[/cyan]')
1903
+ lines.append("")
1904
+ lines.append(f" [bold]Docs:[/bold] [link={path.docs_url}]{path.docs_url}[/link]")
1905
+
1906
+ console.print(
1907
+ Panel(
1908
+ "\n".join(lines),
1909
+ title=f"[bold]{path.label}[/bold]",
1910
+ title_align="left",
1911
+ border_style="green",
1912
+ box=box.ROUNDED,
1913
+ padding=(1, 1),
1914
+ )
1915
+ )
1916
+
1917
+
1918
+ def _print_onboarding(
1919
+ base_url: str,
1920
+ provider_name: str,
1921
+ default_model: str | None,
1922
+ *,
1923
+ demo_deployed: bool = False,
1924
+ ) -> None:
1925
+ """Print setup summary, then present goal-oriented onboarding paths."""
1926
+ if not _verify_platform_health(base_url):
1927
+ raise typer.Exit(1)
1928
+
1929
+ console.print(f"\n{CHECK} [green bold]Setup complete![/green bold]")
1930
+ console.print(f" Provider: {provider_name}")
1931
+ if default_model:
1932
+ console.print(f" Default model: {_display_model_name(default_model)}")
1933
+ if demo_deployed:
1934
+ console.print(f" Demo agent: {_DEMO_AGENT_NAME}")
1935
+
1936
+ console.print("\n[bold cyan]Getting started[/bold cyan]")
1937
+
1938
+ options = [(p.value, p.label) for p in ONBOARDING_PATHS]
1939
+ selected = prompt_choice(
1940
+ "Select how you would like to get started",
1941
+ options,
1942
+ default="optimize",
1943
+ indent=2,
1944
+ )
1945
+
1946
+ console.print()
1947
+ _render_onboarding_card(selected)