@elizaos/plugin-training 2.0.3-beta.5 → 2.0.3-beta.7

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 (363) hide show
  1. package/dist/backends/native.d.ts +96 -0
  2. package/dist/backends/native.d.ts.map +1 -0
  3. package/dist/backends/native.js +308 -0
  4. package/dist/backends/native.js.map +1 -0
  5. package/dist/cli/train.d.ts +22 -0
  6. package/dist/cli/train.d.ts.map +1 -0
  7. package/dist/cli/train.js +219 -0
  8. package/dist/cli/train.js.map +1 -0
  9. package/dist/core/action-benchmark-runner.d.ts +55 -0
  10. package/dist/core/action-benchmark-runner.d.ts.map +1 -0
  11. package/dist/core/action-benchmark-runner.js +341 -0
  12. package/dist/core/action-benchmark-runner.js.map +1 -0
  13. package/dist/core/artifact-store.d.ts +72 -0
  14. package/dist/core/artifact-store.d.ts.map +1 -0
  15. package/dist/core/artifact-store.js +50 -0
  16. package/dist/core/artifact-store.js.map +1 -0
  17. package/dist/core/benchmark-matrix-artifact.d.ts +102 -0
  18. package/dist/core/benchmark-matrix-artifact.d.ts.map +1 -0
  19. package/dist/core/benchmark-matrix-artifact.js +381 -0
  20. package/dist/core/benchmark-matrix-artifact.js.map +1 -0
  21. package/dist/core/benchmark-vs-cerebras-runner.d.ts +37 -0
  22. package/dist/core/benchmark-vs-cerebras-runner.d.ts.map +1 -0
  23. package/dist/core/benchmark-vs-cerebras-runner.js +151 -0
  24. package/dist/core/benchmark-vs-cerebras-runner.js.map +1 -0
  25. package/dist/core/cerebras-eval-model.d.ts +54 -0
  26. package/dist/core/cerebras-eval-model.d.ts.map +1 -0
  27. package/dist/core/cerebras-eval-model.js +249 -0
  28. package/dist/core/cerebras-eval-model.js.map +1 -0
  29. package/dist/core/cli.d.ts +15 -0
  30. package/dist/core/cli.d.ts.map +1 -0
  31. package/dist/core/cli.js +1003 -0
  32. package/dist/core/cli.js.map +1 -0
  33. package/dist/core/context-audit.d.ts +51 -0
  34. package/dist/core/context-audit.d.ts.map +1 -0
  35. package/dist/core/context-audit.js +166 -0
  36. package/dist/core/context-audit.js.map +1 -0
  37. package/dist/core/context-catalog.d.ts +47 -0
  38. package/dist/core/context-catalog.d.ts.map +1 -0
  39. package/dist/core/context-catalog.js +269 -0
  40. package/dist/core/context-catalog.js.map +1 -0
  41. package/dist/core/context-types.d.ts +3 -0
  42. package/dist/core/context-types.d.ts.map +1 -0
  43. package/dist/core/context-types.js +18 -0
  44. package/dist/core/context-types.js.map +1 -0
  45. package/dist/core/dataset-generator.d.ts +135 -0
  46. package/dist/core/dataset-generator.d.ts.map +1 -0
  47. package/dist/core/dataset-generator.js +895 -0
  48. package/dist/core/dataset-generator.js.map +1 -0
  49. package/dist/core/eliza1-benchmark-recipe.d.ts +18 -0
  50. package/dist/core/eliza1-benchmark-recipe.d.ts.map +1 -0
  51. package/dist/core/eliza1-benchmark-recipe.js +64 -0
  52. package/dist/core/eliza1-benchmark-recipe.js.map +1 -0
  53. package/dist/core/eliza1-bundle-stager.d.ts +57 -0
  54. package/dist/core/eliza1-bundle-stager.d.ts.map +1 -0
  55. package/dist/core/eliza1-bundle-stager.js +149 -0
  56. package/dist/core/eliza1-bundle-stager.js.map +1 -0
  57. package/dist/core/ensure-cron-job.d.ts +53 -0
  58. package/dist/core/ensure-cron-job.d.ts.map +1 -0
  59. package/dist/core/ensure-cron-job.js +51 -0
  60. package/dist/core/ensure-cron-job.js.map +1 -0
  61. package/dist/core/eval-comparison-artifact.d.ts +72 -0
  62. package/dist/core/eval-comparison-artifact.d.ts.map +1 -0
  63. package/dist/core/eval-comparison-artifact.js +281 -0
  64. package/dist/core/eval-comparison-artifact.js.map +1 -0
  65. package/dist/core/feed-generation-runner.d.ts +37 -0
  66. package/dist/core/feed-generation-runner.d.ts.map +1 -0
  67. package/dist/core/feed-generation-runner.js +232 -0
  68. package/dist/core/feed-generation-runner.js.map +1 -0
  69. package/dist/core/html-escape.d.ts +5 -0
  70. package/dist/core/html-escape.d.ts.map +1 -0
  71. package/dist/core/html-escape.js +11 -0
  72. package/dist/core/html-escape.js.map +1 -0
  73. package/dist/core/huggingface-dataset-ingest.d.ts +52 -0
  74. package/dist/core/huggingface-dataset-ingest.d.ts.map +1 -0
  75. package/dist/core/huggingface-dataset-ingest.js +134 -0
  76. package/dist/core/huggingface-dataset-ingest.js.map +1 -0
  77. package/dist/core/index.d.ts +29 -0
  78. package/dist/core/index.d.ts.map +1 -0
  79. package/dist/core/index.js +204 -0
  80. package/dist/core/index.js.map +1 -0
  81. package/dist/core/privacy-filter.d.ts +95 -0
  82. package/dist/core/privacy-filter.d.ts.map +1 -0
  83. package/dist/core/privacy-filter.js +324 -0
  84. package/dist/core/privacy-filter.js.map +1 -0
  85. package/dist/core/promotion-gate.d.ts +117 -0
  86. package/dist/core/promotion-gate.d.ts.map +1 -0
  87. package/dist/core/promotion-gate.js +85 -0
  88. package/dist/core/promotion-gate.js.map +1 -0
  89. package/dist/core/promotion-persist.d.ts +116 -0
  90. package/dist/core/promotion-persist.d.ts.map +1 -0
  91. package/dist/core/promotion-persist.js +93 -0
  92. package/dist/core/promotion-persist.js.map +1 -0
  93. package/dist/core/prompt-compare.d.ts +99 -0
  94. package/dist/core/prompt-compare.d.ts.map +1 -0
  95. package/dist/core/prompt-compare.js +210 -0
  96. package/dist/core/prompt-compare.js.map +1 -0
  97. package/dist/core/replay-validator.d.ts +136 -0
  98. package/dist/core/replay-validator.d.ts.map +1 -0
  99. package/dist/core/replay-validator.js +312 -0
  100. package/dist/core/replay-validator.js.map +1 -0
  101. package/dist/core/roleplay-executor.d.ts +123 -0
  102. package/dist/core/roleplay-executor.d.ts.map +1 -0
  103. package/dist/core/roleplay-executor.js +675 -0
  104. package/dist/core/roleplay-executor.js.map +1 -0
  105. package/dist/core/roleplay-trajectories.d.ts +54 -0
  106. package/dist/core/roleplay-trajectories.d.ts.map +1 -0
  107. package/dist/core/roleplay-trajectories.js +88 -0
  108. package/dist/core/roleplay-trajectories.js.map +1 -0
  109. package/dist/core/scenario-blueprints.d.ts +62 -0
  110. package/dist/core/scenario-blueprints.d.ts.map +1 -0
  111. package/dist/core/scenario-blueprints.js +850 -0
  112. package/dist/core/scenario-blueprints.js.map +1 -0
  113. package/dist/core/scenario-runner.d.ts +36 -0
  114. package/dist/core/scenario-runner.d.ts.map +1 -0
  115. package/dist/core/scenario-runner.js +216 -0
  116. package/dist/core/scenario-runner.js.map +1 -0
  117. package/dist/core/skill-scoring-cron.d.ts +57 -0
  118. package/dist/core/skill-scoring-cron.d.ts.map +1 -0
  119. package/dist/core/skill-scoring-cron.js +180 -0
  120. package/dist/core/skill-scoring-cron.js.map +1 -0
  121. package/dist/core/test-trajectory-collector.d.ts +37 -0
  122. package/dist/core/test-trajectory-collector.d.ts.map +1 -0
  123. package/dist/core/test-trajectory-collector.js +225 -0
  124. package/dist/core/test-trajectory-collector.js.map +1 -0
  125. package/dist/core/track-c-queue-task.d.ts +37 -0
  126. package/dist/core/track-c-queue-task.d.ts.map +1 -0
  127. package/dist/core/track-c-queue-task.js +104 -0
  128. package/dist/core/track-c-queue-task.js.map +1 -0
  129. package/dist/core/training-analysis-index.d.ts +104 -0
  130. package/dist/core/training-analysis-index.d.ts.map +1 -0
  131. package/dist/core/training-analysis-index.js +3297 -0
  132. package/dist/core/training-analysis-index.js.map +1 -0
  133. package/dist/core/training-collection-runner.d.ts +508 -0
  134. package/dist/core/training-collection-runner.d.ts.map +1 -0
  135. package/dist/core/training-collection-runner.js +2299 -0
  136. package/dist/core/training-collection-runner.js.map +1 -0
  137. package/dist/core/training-config.d.ts +52 -0
  138. package/dist/core/training-config.d.ts.map +1 -0
  139. package/dist/core/training-config.js +117 -0
  140. package/dist/core/training-config.js.map +1 -0
  141. package/dist/core/training-orchestrator.d.ts +112 -0
  142. package/dist/core/training-orchestrator.d.ts.map +1 -0
  143. package/dist/core/training-orchestrator.js +729 -0
  144. package/dist/core/training-orchestrator.js.map +1 -0
  145. package/dist/core/training-readiness-report.d.ts +52 -0
  146. package/dist/core/training-readiness-report.d.ts.map +1 -0
  147. package/dist/core/training-readiness-report.js +765 -0
  148. package/dist/core/training-readiness-report.js.map +1 -0
  149. package/dist/core/trajectory-consumer.d.ts +15 -0
  150. package/dist/core/trajectory-consumer.d.ts.map +1 -0
  151. package/dist/core/trajectory-consumer.js +61 -0
  152. package/dist/core/trajectory-consumer.js.map +1 -0
  153. package/dist/core/trajectory-export-bundle.d.ts +95 -0
  154. package/dist/core/trajectory-export-bundle.d.ts.map +1 -0
  155. package/dist/core/trajectory-export-bundle.js +561 -0
  156. package/dist/core/trajectory-export-bundle.js.map +1 -0
  157. package/dist/core/trajectory-export-cron.d.ts +57 -0
  158. package/dist/core/trajectory-export-cron.d.ts.map +1 -0
  159. package/dist/core/trajectory-export-cron.js +170 -0
  160. package/dist/core/trajectory-export-cron.js.map +1 -0
  161. package/dist/core/trajectory-hf-upload.d.ts +50 -0
  162. package/dist/core/trajectory-hf-upload.d.ts.map +1 -0
  163. package/dist/core/trajectory-hf-upload.js +111 -0
  164. package/dist/core/trajectory-hf-upload.js.map +1 -0
  165. package/dist/core/trajectory-task-datasets.d.ts +62 -0
  166. package/dist/core/trajectory-task-datasets.d.ts.map +1 -0
  167. package/dist/core/trajectory-task-datasets.js +427 -0
  168. package/dist/core/trajectory-task-datasets.js.map +1 -0
  169. package/dist/core/wait-for-service.d.ts +25 -0
  170. package/dist/core/wait-for-service.d.ts.map +1 -0
  171. package/dist/core/wait-for-service.js +19 -0
  172. package/dist/core/wait-for-service.js.map +1 -0
  173. package/dist/core/workspace-runtime.d.ts +4 -0
  174. package/dist/core/workspace-runtime.d.ts.map +1 -0
  175. package/dist/core/workspace-runtime.js +25 -0
  176. package/dist/core/workspace-runtime.js.map +1 -0
  177. package/dist/dspy/artifact.d.ts +54 -0
  178. package/dist/dspy/artifact.d.ts.map +1 -0
  179. package/dist/dspy/artifact.js +61 -0
  180. package/dist/dspy/artifact.js.map +1 -0
  181. package/dist/dspy/chain-of-thought.d.ts +27 -0
  182. package/dist/dspy/chain-of-thought.d.ts.map +1 -0
  183. package/dist/dspy/chain-of-thought.js +43 -0
  184. package/dist/dspy/chain-of-thought.js.map +1 -0
  185. package/dist/dspy/examples.d.ts +72 -0
  186. package/dist/dspy/examples.d.ts.map +1 -0
  187. package/dist/dspy/examples.js +105 -0
  188. package/dist/dspy/examples.js.map +1 -0
  189. package/dist/dspy/index.d.ts +15 -0
  190. package/dist/dspy/index.d.ts.map +1 -0
  191. package/dist/dspy/index.js +40 -0
  192. package/dist/dspy/index.js.map +1 -0
  193. package/dist/dspy/lm-adapter.d.ts +100 -0
  194. package/dist/dspy/lm-adapter.d.ts.map +1 -0
  195. package/dist/dspy/lm-adapter.js +81 -0
  196. package/dist/dspy/lm-adapter.js.map +1 -0
  197. package/dist/dspy/optimizers/dspy-bootstrap-fewshot.d.ts +23 -0
  198. package/dist/dspy/optimizers/dspy-bootstrap-fewshot.d.ts.map +1 -0
  199. package/dist/dspy/optimizers/dspy-bootstrap-fewshot.js +85 -0
  200. package/dist/dspy/optimizers/dspy-bootstrap-fewshot.js.map +1 -0
  201. package/dist/dspy/optimizers/dspy-copro.d.ts +29 -0
  202. package/dist/dspy/optimizers/dspy-copro.d.ts.map +1 -0
  203. package/dist/dspy/optimizers/dspy-copro.js +141 -0
  204. package/dist/dspy/optimizers/dspy-copro.js.map +1 -0
  205. package/dist/dspy/optimizers/dspy-mipro.d.ts +37 -0
  206. package/dist/dspy/optimizers/dspy-mipro.d.ts.map +1 -0
  207. package/dist/dspy/optimizers/dspy-mipro.js +194 -0
  208. package/dist/dspy/optimizers/dspy-mipro.js.map +1 -0
  209. package/dist/dspy/optimizers/index.d.ts +5 -0
  210. package/dist/dspy/optimizers/index.d.ts.map +1 -0
  211. package/dist/dspy/optimizers/index.js +11 -0
  212. package/dist/dspy/optimizers/index.js.map +1 -0
  213. package/dist/dspy/optimizers/types.d.ts +39 -0
  214. package/dist/dspy/optimizers/types.d.ts.map +1 -0
  215. package/dist/dspy/optimizers/types.js +1 -0
  216. package/dist/dspy/optimizers/types.js.map +1 -0
  217. package/dist/dspy/predict.d.ts +49 -0
  218. package/dist/dspy/predict.d.ts.map +1 -0
  219. package/dist/dspy/predict.js +73 -0
  220. package/dist/dspy/predict.js.map +1 -0
  221. package/dist/dspy/signature.d.ts +88 -0
  222. package/dist/dspy/signature.d.ts.map +1 -0
  223. package/dist/dspy/signature.js +205 -0
  224. package/dist/dspy/signature.js.map +1 -0
  225. package/dist/index.d.ts +15 -0
  226. package/dist/index.d.ts.map +1 -0
  227. package/dist/index.js +15 -0
  228. package/dist/index.js.map +1 -0
  229. package/dist/optimizers/bootstrap-fewshot.d.ts +42 -0
  230. package/dist/optimizers/bootstrap-fewshot.d.ts.map +1 -0
  231. package/dist/optimizers/bootstrap-fewshot.js +92 -0
  232. package/dist/optimizers/bootstrap-fewshot.js.map +1 -0
  233. package/dist/optimizers/gepa.d.ts +63 -0
  234. package/dist/optimizers/gepa.d.ts.map +1 -0
  235. package/dist/optimizers/gepa.js +232 -0
  236. package/dist/optimizers/gepa.js.map +1 -0
  237. package/dist/optimizers/index.d.ts +7 -0
  238. package/dist/optimizers/index.d.ts.map +1 -0
  239. package/dist/optimizers/index.js +51 -0
  240. package/dist/optimizers/index.js.map +1 -0
  241. package/dist/optimizers/instruction-search.d.ts +39 -0
  242. package/dist/optimizers/instruction-search.d.ts.map +1 -0
  243. package/dist/optimizers/instruction-search.js +108 -0
  244. package/dist/optimizers/instruction-search.js.map +1 -0
  245. package/dist/optimizers/prompt-evolution.d.ts +39 -0
  246. package/dist/optimizers/prompt-evolution.d.ts.map +1 -0
  247. package/dist/optimizers/prompt-evolution.js +101 -0
  248. package/dist/optimizers/prompt-evolution.js.map +1 -0
  249. package/dist/optimizers/scoring.d.ts +139 -0
  250. package/dist/optimizers/scoring.d.ts.map +1 -0
  251. package/dist/optimizers/scoring.js +299 -0
  252. package/dist/optimizers/scoring.js.map +1 -0
  253. package/dist/optimizers/types.d.ts +105 -0
  254. package/dist/optimizers/types.d.ts.map +1 -0
  255. package/dist/optimizers/types.js +1 -0
  256. package/dist/optimizers/types.js.map +1 -0
  257. package/dist/register-runtime.d.ts +3 -0
  258. package/dist/register-runtime.d.ts.map +1 -0
  259. package/dist/register-runtime.js +60 -0
  260. package/dist/register-runtime.js.map +1 -0
  261. package/dist/register-terminal-view.d.ts +15 -0
  262. package/dist/register-terminal-view.d.ts.map +1 -0
  263. package/dist/register-terminal-view.js +31 -0
  264. package/dist/register-terminal-view.js.map +1 -0
  265. package/dist/routes/experience-routes.d.ts +21 -0
  266. package/dist/routes/experience-routes.d.ts.map +1 -0
  267. package/dist/routes/experience-routes.js +513 -0
  268. package/dist/routes/experience-routes.js.map +1 -0
  269. package/dist/routes/index.d.ts +5 -0
  270. package/dist/routes/index.d.ts.map +1 -0
  271. package/dist/routes/index.js +17 -0
  272. package/dist/routes/index.js.map +1 -0
  273. package/dist/routes/training-routes.d.ts +10 -0
  274. package/dist/routes/training-routes.d.ts.map +1 -0
  275. package/dist/routes/training-routes.js +1239 -0
  276. package/dist/routes/training-routes.js.map +1 -0
  277. package/dist/routes/training-vast-routes.d.ts +35 -0
  278. package/dist/routes/training-vast-routes.d.ts.map +1 -0
  279. package/dist/routes/training-vast-routes.js +249 -0
  280. package/dist/routes/training-vast-routes.js.map +1 -0
  281. package/dist/routes/trajectory-routes.d.ts +19 -0
  282. package/dist/routes/trajectory-routes.d.ts.map +1 -0
  283. package/dist/routes/trajectory-routes.js +1122 -0
  284. package/dist/routes/trajectory-routes.js.map +1 -0
  285. package/dist/services/index.d.ts +9 -0
  286. package/dist/services/index.d.ts.map +1 -0
  287. package/dist/services/index.js +63 -0
  288. package/dist/services/index.js.map +1 -0
  289. package/dist/services/training-backend-check.d.ts +8 -0
  290. package/dist/services/training-backend-check.d.ts.map +1 -0
  291. package/dist/services/training-backend-check.js +31 -0
  292. package/dist/services/training-backend-check.js.map +1 -0
  293. package/dist/services/training-service-like.d.ts +40 -0
  294. package/dist/services/training-service-like.d.ts.map +1 -0
  295. package/dist/services/training-service-like.js +1 -0
  296. package/dist/services/training-service-like.js.map +1 -0
  297. package/dist/services/training-service-registry.d.ts +4 -0
  298. package/dist/services/training-service-registry.d.ts.map +1 -0
  299. package/dist/services/training-service-registry.js +12 -0
  300. package/dist/services/training-service-registry.js.map +1 -0
  301. package/dist/services/training-service.d.ts +59 -0
  302. package/dist/services/training-service.d.ts.map +1 -0
  303. package/dist/services/training-service.js +154 -0
  304. package/dist/services/training-service.js.map +1 -0
  305. package/dist/services/training-trigger.d.ts +177 -0
  306. package/dist/services/training-trigger.d.ts.map +1 -0
  307. package/dist/services/training-trigger.js +300 -0
  308. package/dist/services/training-trigger.js.map +1 -0
  309. package/dist/services/training-vast-service.d.ts +149 -0
  310. package/dist/services/training-vast-service.d.ts.map +1 -0
  311. package/dist/services/training-vast-service.js +648 -0
  312. package/dist/services/training-vast-service.js.map +1 -0
  313. package/dist/services/vast-inference-stats.d.ts +37 -0
  314. package/dist/services/vast-inference-stats.d.ts.map +1 -0
  315. package/dist/services/vast-inference-stats.js +81 -0
  316. package/dist/services/vast-inference-stats.js.map +1 -0
  317. package/dist/services/vast-job-store.d.ts +74 -0
  318. package/dist/services/vast-job-store.d.ts.map +1 -0
  319. package/dist/services/vast-job-store.js +194 -0
  320. package/dist/services/vast-job-store.js.map +1 -0
  321. package/dist/services/vast-subprocess.d.ts +27 -0
  322. package/dist/services/vast-subprocess.d.ts.map +1 -0
  323. package/dist/services/vast-subprocess.js +78 -0
  324. package/dist/services/vast-subprocess.js.map +1 -0
  325. package/dist/setup-routes.d.ts +17 -0
  326. package/dist/setup-routes.d.ts.map +1 -0
  327. package/dist/setup-routes.js +319 -0
  328. package/dist/setup-routes.js.map +1 -0
  329. package/dist/ui/FineTuningSpatialView.d.ts +49 -0
  330. package/dist/ui/FineTuningSpatialView.d.ts.map +1 -0
  331. package/dist/ui/FineTuningSpatialView.js +154 -0
  332. package/dist/ui/FineTuningSpatialView.js.map +1 -0
  333. package/dist/ui/FineTuningView.d.ts +7 -0
  334. package/dist/ui/FineTuningView.d.ts.map +1 -0
  335. package/dist/ui/FineTuningView.helpers.d.ts +17 -0
  336. package/dist/ui/FineTuningView.helpers.d.ts.map +1 -0
  337. package/dist/ui/FineTuningView.helpers.js +30 -0
  338. package/dist/ui/FineTuningView.helpers.js.map +1 -0
  339. package/dist/ui/FineTuningView.interact.d.ts +2 -0
  340. package/dist/ui/FineTuningView.interact.d.ts.map +1 -0
  341. package/dist/ui/FineTuningView.interact.js +300 -0
  342. package/dist/ui/FineTuningView.interact.js.map +1 -0
  343. package/dist/ui/FineTuningView.js +4653 -0
  344. package/dist/ui/FineTuningView.js.map +1 -0
  345. package/dist/ui/fine-tuning-panels.d.ts +100 -0
  346. package/dist/ui/fine-tuning-panels.d.ts.map +1 -0
  347. package/dist/ui/fine-tuning-panels.helpers.d.ts +19 -0
  348. package/dist/ui/fine-tuning-panels.helpers.d.ts.map +1 -0
  349. package/dist/ui/fine-tuning-panels.helpers.js +77 -0
  350. package/dist/ui/fine-tuning-panels.helpers.js.map +1 -0
  351. package/dist/ui/fine-tuning-panels.js +928 -0
  352. package/dist/ui/fine-tuning-panels.js.map +1 -0
  353. package/dist/ui/index.d.ts +5 -0
  354. package/dist/ui/index.d.ts.map +1 -0
  355. package/dist/ui/index.js +5 -0
  356. package/dist/ui/index.js.map +1 -0
  357. package/dist/ui/training-view-bundle.d.ts +3 -0
  358. package/dist/ui/training-view-bundle.d.ts.map +1 -0
  359. package/dist/ui/training-view-bundle.js +7 -0
  360. package/dist/ui/training-view-bundle.js.map +1 -0
  361. package/dist/views/bundle.js +5312 -0
  362. package/dist/views/bundle.js.map +1 -0
  363. package/package.json +7 -7
@@ -0,0 +1,648 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync, promises as fs } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { logger } from "@elizaos/core";
6
+ import {
7
+ aggregateInferenceStats,
8
+ emptyInferenceStatsAggregate,
9
+ parseStatRow
10
+ } from "./vast-inference-stats.js";
11
+ import {
12
+ inferenceStatsPath,
13
+ readInferenceEndpoints,
14
+ readJobLogTail,
15
+ VastJobStore,
16
+ writeInferenceEndpoints
17
+ } from "./vast-job-store.js";
18
+ import {
19
+ runCapture,
20
+ runDetachedToLog,
21
+ VastServiceError
22
+ } from "./vast-subprocess.js";
23
+ import { VastServiceError as VastServiceError2 } from "./vast-subprocess.js";
24
+ const DEFAULT_PYTHON = {
25
+ command: "uv",
26
+ preArgs: ["run", "--quiet", "python"]
27
+ };
28
+ const HERE = fileURLToPath(import.meta.url);
29
+ const TRAINING_ROOT_DEFAULT = resolve(
30
+ HERE,
31
+ "..",
32
+ "..",
33
+ "..",
34
+ "..",
35
+ "..",
36
+ "packages",
37
+ "training"
38
+ );
39
+ const RUN_NAME_PATTERN = /^[A-Za-z0-9._-]{1,64}$/;
40
+ const LABEL_PATTERN = /^[A-Za-z0-9._-]{1,64}$/;
41
+ const REGISTRY_KEY_PATTERN = /^[A-Za-z0-9._-]{1,64}$/;
42
+ class VastTrainingService {
43
+ store;
44
+ trainingRoot;
45
+ python;
46
+ spawnImpl;
47
+ registryCache = null;
48
+ registryLoadedAt = null;
49
+ constructor(options = {}) {
50
+ this.store = options.store ?? new VastJobStore();
51
+ this.trainingRoot = options.trainingRoot ?? TRAINING_ROOT_DEFAULT;
52
+ this.python = options.pythonLauncher ?? DEFAULT_PYTHON;
53
+ this.spawnImpl = options.spawnImpl ?? spawn;
54
+ }
55
+ // ── Registry ──────────────────────────────────────────────────────────
56
+ async getRegistry(refresh = false) {
57
+ if (this.registryCache && !refresh) return this.registryCache;
58
+ const dumpScript = join(
59
+ this.trainingRoot,
60
+ "scripts",
61
+ "dump_registry_json.py"
62
+ );
63
+ if (!existsSync(dumpScript)) {
64
+ throw new VastServiceError(
65
+ `Registry dump script not found at ${dumpScript}`,
66
+ 503
67
+ );
68
+ }
69
+ const stdout = await this.runCapture(
70
+ this.python.command,
71
+ [...this.python.preArgs, dumpScript],
72
+ { cwd: this.trainingRoot }
73
+ );
74
+ let parsed;
75
+ try {
76
+ parsed = JSON.parse(stdout);
77
+ } catch (err) {
78
+ throw new VastServiceError(
79
+ `Registry dump produced non-JSON output: ${err instanceof Error ? err.message : String(err)}`,
80
+ 500
81
+ );
82
+ }
83
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
84
+ throw new VastServiceError(
85
+ "Registry dump returned unexpected shape",
86
+ 500
87
+ );
88
+ }
89
+ const out = {};
90
+ for (const [key, value] of Object.entries(
91
+ parsed
92
+ )) {
93
+ const entry = narrowRegistryEntry(value);
94
+ if (entry) out[key] = entry;
95
+ }
96
+ this.registryCache = out;
97
+ this.registryLoadedAt = (/* @__PURE__ */ new Date()).toISOString();
98
+ return out;
99
+ }
100
+ async listRegistry(refresh = false) {
101
+ const registry = await this.getRegistry(refresh);
102
+ const entries = Object.entries(registry).map(([short_name, entry]) => ({
103
+ short_name,
104
+ entry
105
+ }));
106
+ return { loaded_at: this.registryLoadedAt, entries };
107
+ }
108
+ async ensureRegistryKey(key) {
109
+ if (!REGISTRY_KEY_PATTERN.test(key)) {
110
+ throw new VastServiceError(
111
+ "registry_key must match [A-Za-z0-9._-]{1,64}",
112
+ 400
113
+ );
114
+ }
115
+ const registry = await this.getRegistry(false);
116
+ const entry = registry[key];
117
+ if (!entry) {
118
+ throw new VastServiceError(
119
+ `Unknown registry_key '${key}'. Refresh /api/training/vast/models to update the cache.`,
120
+ 400
121
+ );
122
+ }
123
+ return entry;
124
+ }
125
+ // ── Jobs ──────────────────────────────────────────────────────────────
126
+ async listJobs() {
127
+ return this.store.list();
128
+ }
129
+ async getJob(jobId) {
130
+ return this.store.get(jobId);
131
+ }
132
+ async createJob(input) {
133
+ await this.ensureRegistryKey(input.registry_key);
134
+ if (!Number.isInteger(input.epochs) || input.epochs < 1 || input.epochs > 64) {
135
+ throw new VastServiceError(
136
+ "epochs must be an integer between 1 and 64",
137
+ 400
138
+ );
139
+ }
140
+ if (input.run_name !== void 0 && !RUN_NAME_PATTERN.test(input.run_name)) {
141
+ throw new VastServiceError(
142
+ "run_name must match [A-Za-z0-9._-]{1,64}",
143
+ 400
144
+ );
145
+ }
146
+ const job_id = makeJobId();
147
+ const run_name = input.run_name ?? defaultRunName(input.registry_key);
148
+ const now = (/* @__PURE__ */ new Date()).toISOString();
149
+ const record = {
150
+ job_id,
151
+ run_name,
152
+ registry_key: input.registry_key,
153
+ status: "queued",
154
+ epochs: input.epochs,
155
+ created_at: now,
156
+ updated_at: now,
157
+ started_at: null,
158
+ ended_at: null,
159
+ vast_instance_id: null,
160
+ exit_code: null,
161
+ error: null
162
+ };
163
+ await this.store.insert(record);
164
+ void this.dispatchJob(record);
165
+ return record;
166
+ }
167
+ async cancelJob(jobId) {
168
+ const job = await this.store.get(jobId);
169
+ if (!job) throw new VastServiceError("Job not found", 404);
170
+ if (job.status === "completed" || job.status === "failed") {
171
+ throw new VastServiceError(
172
+ `Cannot cancel job in terminal state '${job.status}'`,
173
+ 409
174
+ );
175
+ }
176
+ if (job.status === "cancelled") return job;
177
+ return this.store.update(jobId, {
178
+ status: "cancelled",
179
+ ended_at: (/* @__PURE__ */ new Date()).toISOString()
180
+ });
181
+ }
182
+ async readJobLog(jobId, tailLines) {
183
+ const job = await this.store.get(jobId);
184
+ if (!job) throw new VastServiceError("Job not found", 404);
185
+ return readJobLogTail(jobId, tailLines);
186
+ }
187
+ async runEval(jobId, input) {
188
+ const job = await this.store.get(jobId);
189
+ if (!job) throw new VastServiceError("Job not found", 404);
190
+ const evalScript = join(this.trainingRoot, "scripts", "eval_checkpoint.py");
191
+ if (!existsSync(evalScript)) {
192
+ throw new VastServiceError(
193
+ `eval_checkpoint.py not found at ${evalScript} \u2014 CheckpointSyncAgent has not landed it yet`,
194
+ 503
195
+ );
196
+ }
197
+ const checkpointDir = input.checkpoint_dir ?? join(this.trainingRoot, "checkpoints", job.run_name, "final");
198
+ if (!isSafeCheckpointPath(checkpointDir, this.trainingRoot)) {
199
+ throw new VastServiceError(
200
+ "checkpoint_dir must resolve under the training root",
201
+ 400
202
+ );
203
+ }
204
+ const valJsonl = input.val_jsonl ?? "data/smoke/val.jsonl";
205
+ if (!isSafeRelativePath(valJsonl)) {
206
+ throw new VastServiceError(
207
+ "val_jsonl must be a relative path without traversal",
208
+ 400
209
+ );
210
+ }
211
+ const maxExamples = input.max_examples ?? 50;
212
+ if (!Number.isInteger(maxExamples) || maxExamples < 1 || maxExamples > 5e3) {
213
+ throw new VastServiceError(
214
+ "max_examples must be an integer between 1 and 5000",
215
+ 400
216
+ );
217
+ }
218
+ const outPath = join(
219
+ this.trainingRoot,
220
+ "checkpoints",
221
+ job.run_name,
222
+ `eval-${Date.now()}.json`
223
+ );
224
+ const args = [
225
+ ...this.python.preArgs,
226
+ evalScript,
227
+ "--checkpoint",
228
+ checkpointDir,
229
+ "--registry-key",
230
+ job.registry_key,
231
+ "--val-jsonl",
232
+ valJsonl,
233
+ "--max-examples",
234
+ String(maxExamples),
235
+ "--out",
236
+ outPath
237
+ ];
238
+ const exitCode = await this.runDetachedToLog(
239
+ jobId,
240
+ this.python.command,
241
+ args,
242
+ this.trainingRoot
243
+ );
244
+ let summary = null;
245
+ if (existsSync(outPath)) {
246
+ try {
247
+ const raw = await fs.readFile(outPath, "utf8");
248
+ const parsed = JSON.parse(raw);
249
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
250
+ summary = parsed;
251
+ }
252
+ } catch (err) {
253
+ logger.warn(
254
+ `[VastTrainingService] failed to read eval output ${outPath}: ${err instanceof Error ? err.message : String(err)}`
255
+ );
256
+ }
257
+ }
258
+ return { job_id: jobId, exit_code: exitCode, out_path: outPath, summary };
259
+ }
260
+ // ── Checkpoints ───────────────────────────────────────────────────────
261
+ async listCheckpointsForRegistryKey(registryKey) {
262
+ await this.ensureRegistryKey(registryKey);
263
+ const checkpointsRoot = join(this.trainingRoot, "checkpoints");
264
+ if (!existsSync(checkpointsRoot)) return [];
265
+ const out = [];
266
+ const runDirs = await fs.readdir(checkpointsRoot, { withFileTypes: true });
267
+ for (const runDir of runDirs) {
268
+ if (!runDir.isDirectory()) continue;
269
+ if (!runDir.name.startsWith(registryKey.replace(/\./g, "-"))) continue;
270
+ const runPath = join(checkpointsRoot, runDir.name);
271
+ const status = join(runPath, "STATUS.md");
272
+ if (existsSync(status)) {
273
+ try {
274
+ const body = await fs.readFile(status, "utf8");
275
+ if (body.includes("FAILED RUN")) continue;
276
+ } catch {
277
+ continue;
278
+ }
279
+ }
280
+ const ckptEntries = await fs.readdir(runPath, { withFileTypes: true });
281
+ for (const ckpt of ckptEntries) {
282
+ if (!ckpt.isDirectory()) continue;
283
+ if (!/^checkpoint-\d+$|^final$/.test(ckpt.name)) continue;
284
+ const ckptPath = join(runPath, ckpt.name);
285
+ const stepMatch = /^checkpoint-(\d+)$/.exec(ckpt.name);
286
+ const evalDoneFile = join(ckptPath, "_eval.json");
287
+ let evalSummary = null;
288
+ const evaluated = existsSync(evalDoneFile);
289
+ if (evaluated) {
290
+ try {
291
+ const raw = await fs.readFile(evalDoneFile, "utf8");
292
+ const parsed = JSON.parse(raw);
293
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
294
+ evalSummary = parsed;
295
+ }
296
+ } catch {
297
+ evalSummary = null;
298
+ }
299
+ }
300
+ out.push({
301
+ name: `${runDir.name}/${ckpt.name}`,
302
+ path: ckptPath,
303
+ step: stepMatch ? Number(stepMatch[1]) : null,
304
+ evaluated,
305
+ eval_summary: evalSummary
306
+ });
307
+ }
308
+ }
309
+ out.sort((a, b) => (b.step ?? -1) - (a.step ?? -1));
310
+ return out;
311
+ }
312
+ // ── Inference endpoints ───────────────────────────────────────────────
313
+ async listInferenceEndpoints() {
314
+ return readInferenceEndpoints();
315
+ }
316
+ async createInferenceEndpoint(input) {
317
+ if (!LABEL_PATTERN.test(input.label)) {
318
+ throw new VastServiceError("label must match [A-Za-z0-9._-]{1,64}", 400);
319
+ }
320
+ let url;
321
+ try {
322
+ url = new URL(input.base_url);
323
+ } catch {
324
+ throw new VastServiceError("base_url must be a valid URL", 400);
325
+ }
326
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
327
+ throw new VastServiceError("base_url must use http:// or https://", 400);
328
+ }
329
+ await this.ensureRegistryKey(input.registry_key);
330
+ const endpoints = await readInferenceEndpoints();
331
+ if (endpoints.some((e) => e.label === input.label)) {
332
+ throw new VastServiceError(
333
+ `Inference endpoint with label '${input.label}' already exists`,
334
+ 409
335
+ );
336
+ }
337
+ const record = {
338
+ id: `ep_${makeShortId()}`,
339
+ label: input.label,
340
+ base_url: input.base_url,
341
+ registry_key: input.registry_key,
342
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
343
+ };
344
+ endpoints.push(record);
345
+ await writeInferenceEndpoints(endpoints);
346
+ return record;
347
+ }
348
+ async deleteInferenceEndpoint(id) {
349
+ const endpoints = await readInferenceEndpoints();
350
+ const next = endpoints.filter((e) => e.id !== id);
351
+ if (next.length === endpoints.length) return false;
352
+ await writeInferenceEndpoints(next);
353
+ return true;
354
+ }
355
+ /**
356
+ * Read a per-job budget snapshot via `scripts.lib.vast_budget snapshot
357
+ * --json`. Returns `null` when the job has no provisioned instance
358
+ * yet (the UI shows a "not provisioned" state in that case).
359
+ *
360
+ * The python module is the single source of truth — it both renders
361
+ * the watcher's status line and answers this endpoint, so the UI and
362
+ * the watcher never disagree about the budget state.
363
+ */
364
+ async getJobBudget(jobId) {
365
+ const job = await this.store.get(jobId);
366
+ if (!job) throw new VastServiceError("Job not found", 404);
367
+ const instanceIdRaw = job.vast_instance_id;
368
+ if (!instanceIdRaw) return null;
369
+ const instanceId = Number(instanceIdRaw);
370
+ if (!Number.isFinite(instanceId) || instanceId <= 0) return null;
371
+ const dumpScript = "-m";
372
+ let stdout;
373
+ try {
374
+ stdout = await this.runCapture(
375
+ this.python.command,
376
+ [
377
+ ...this.python.preArgs,
378
+ dumpScript,
379
+ "scripts.lib.vast_budget",
380
+ "snapshot",
381
+ String(instanceId),
382
+ "--pipeline",
383
+ job.registry_key,
384
+ "--run-name",
385
+ job.run_name,
386
+ "--json"
387
+ ],
388
+ { cwd: this.trainingRoot }
389
+ );
390
+ } catch (err) {
391
+ logger.warn(
392
+ `[VastTrainingService] budget snapshot failed for ${jobId}: ${err instanceof Error ? err.message : String(err)}`
393
+ );
394
+ return null;
395
+ }
396
+ const trimmed = stdout.trim();
397
+ if (!trimmed) return null;
398
+ let parsed;
399
+ try {
400
+ parsed = JSON.parse(trimmed);
401
+ } catch {
402
+ return null;
403
+ }
404
+ return narrowBudgetSnapshot(parsed, jobId);
405
+ }
406
+ async getInferenceStats(label, lastMinutes) {
407
+ if (!Number.isFinite(lastMinutes) || lastMinutes <= 0 || lastMinutes > 24 * 60) {
408
+ throw new VastServiceError(
409
+ "last_minutes must be a positive number \u2264 1440",
410
+ 400
411
+ );
412
+ }
413
+ if (label !== null && !LABEL_PATTERN.test(label)) {
414
+ throw new VastServiceError("label must match [A-Za-z0-9._-]{1,64}", 400);
415
+ }
416
+ const path = inferenceStatsPath();
417
+ if (!existsSync(path)) {
418
+ return emptyInferenceStatsAggregate(label, lastMinutes);
419
+ }
420
+ const cutoffMs = Date.now() - lastMinutes * 6e4;
421
+ const raw = await fs.readFile(path, "utf8");
422
+ const samples = [];
423
+ for (const line of raw.split("\n")) {
424
+ const trimmed = line.trim();
425
+ if (!trimmed) continue;
426
+ const row = parseStatRow(trimmed);
427
+ if (!row) continue;
428
+ if (label !== null && row.label !== label) continue;
429
+ const ts = Date.parse(row.ts);
430
+ if (!Number.isFinite(ts) || ts < cutoffMs) continue;
431
+ samples.push(row);
432
+ }
433
+ return aggregateInferenceStats(samples, label, lastMinutes);
434
+ }
435
+ // ── Internals ─────────────────────────────────────────────────────────
436
+ async dispatchJob(record) {
437
+ const trainScript = join(this.trainingRoot, "scripts", "train_vast.sh");
438
+ if (!existsSync(trainScript)) {
439
+ logger.error(
440
+ `[VastTrainingService] train_vast.sh not found at ${trainScript}`
441
+ );
442
+ await this.store.update(record.job_id, {
443
+ status: "failed",
444
+ ended_at: (/* @__PURE__ */ new Date()).toISOString(),
445
+ error: "train_vast.sh not found"
446
+ });
447
+ return;
448
+ }
449
+ await this.store.update(record.job_id, {
450
+ status: "provisioning",
451
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
452
+ });
453
+ const args = [
454
+ trainScript,
455
+ "provision-and-train",
456
+ "--registry-key",
457
+ record.registry_key,
458
+ "--epochs",
459
+ String(record.epochs)
460
+ ];
461
+ try {
462
+ const exitCode = await this.runDetachedToLog(
463
+ record.job_id,
464
+ "bash",
465
+ args,
466
+ this.trainingRoot,
467
+ {
468
+ RUN_NAME: record.run_name
469
+ }
470
+ );
471
+ const instanceId = await this.discoverInstanceIdForRun(record);
472
+ if (exitCode === 0) {
473
+ await this.store.update(record.job_id, {
474
+ status: "completed",
475
+ ended_at: (/* @__PURE__ */ new Date()).toISOString(),
476
+ exit_code: exitCode,
477
+ vast_instance_id: instanceId
478
+ });
479
+ } else {
480
+ await this.store.update(record.job_id, {
481
+ status: "failed",
482
+ ended_at: (/* @__PURE__ */ new Date()).toISOString(),
483
+ exit_code: exitCode,
484
+ vast_instance_id: instanceId,
485
+ error: `train_vast.sh exited with code ${exitCode}`
486
+ });
487
+ }
488
+ } catch (err) {
489
+ logger.error(
490
+ `[VastTrainingService] dispatch failure for ${record.job_id}: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
491
+ );
492
+ await this.store.update(record.job_id, {
493
+ status: "failed",
494
+ ended_at: (/* @__PURE__ */ new Date()).toISOString(),
495
+ error: err instanceof Error ? err.message : String(err)
496
+ });
497
+ }
498
+ }
499
+ async discoverInstanceIdForRun(record) {
500
+ const stateFile = join(
501
+ this.trainingRoot,
502
+ ".eliza",
503
+ "vast-state",
504
+ `${record.run_name}.json`
505
+ );
506
+ if (existsSync(stateFile)) {
507
+ try {
508
+ const raw = await fs.readFile(stateFile, "utf8");
509
+ const parsed = JSON.parse(raw);
510
+ if (parsed && typeof parsed === "object") {
511
+ const obj = parsed;
512
+ const id = obj.instance_id ?? obj.vast_instance_id;
513
+ if (typeof id === "string" && id.trim()) return id.trim();
514
+ if (typeof id === "number") return String(id);
515
+ }
516
+ } catch (err) {
517
+ logger.warn(
518
+ `[VastTrainingService] could not parse vast-state file ${stateFile}: ${err instanceof Error ? err.message : String(err)}`
519
+ );
520
+ }
521
+ }
522
+ const logTail = await readJobLogTail(record.job_id, 200);
523
+ for (const line of logTail) {
524
+ const match = /ELIZA_VAST_INSTANCE_ID=([A-Za-z0-9_-]+)/.exec(line);
525
+ if (match) return match[1];
526
+ }
527
+ return null;
528
+ }
529
+ runCapture(command, args, options) {
530
+ return runCapture(this.spawnImpl, command, args, options);
531
+ }
532
+ runDetachedToLog(jobId, command, args, cwd, extraEnv = {}) {
533
+ return runDetachedToLog(
534
+ this.spawnImpl,
535
+ jobId,
536
+ command,
537
+ args,
538
+ cwd,
539
+ extraEnv
540
+ );
541
+ }
542
+ }
543
+ function defaultRunName(registryKey) {
544
+ return `${registryKey.replace(/\./g, "-")}-apollo`;
545
+ }
546
+ function makeJobId() {
547
+ return `vjob_${makeShortId()}`;
548
+ }
549
+ function makeShortId() {
550
+ const buf = new Uint8Array(8);
551
+ if (typeof globalThis.crypto.getRandomValues === "function") {
552
+ globalThis.crypto.getRandomValues(buf);
553
+ } else {
554
+ for (let i = 0; i < buf.length; i += 1)
555
+ buf[i] = Math.floor(Math.random() * 256);
556
+ }
557
+ let n = 0n;
558
+ for (const byte of buf) n = n << 8n | BigInt(byte);
559
+ return n.toString(36).padStart(12, "0").slice(0, 12);
560
+ }
561
+ function narrowRegistryEntry(value) {
562
+ if (!value || typeof value !== "object") return null;
563
+ const obj = value;
564
+ if (typeof obj.eliza_short_name === "string" && typeof obj.eliza_repo_id === "string" && typeof obj.gguf_repo_id === "string" && typeof obj.base_hf_id === "string" && typeof obj.tier === "string" && typeof obj.inference_max_context === "number") {
565
+ return {
566
+ eliza_short_name: obj.eliza_short_name,
567
+ eliza_repo_id: obj.eliza_repo_id,
568
+ gguf_repo_id: obj.gguf_repo_id,
569
+ base_hf_id: obj.base_hf_id,
570
+ tier: obj.tier,
571
+ inference_max_context: obj.inference_max_context
572
+ };
573
+ }
574
+ return null;
575
+ }
576
+ function narrowBudgetSnapshot(raw, jobId) {
577
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
578
+ const obj = raw;
579
+ const num = (k) => {
580
+ const v = obj[k];
581
+ if (typeof v !== "number" || !Number.isFinite(v)) return null;
582
+ return v;
583
+ };
584
+ const str = (k) => {
585
+ const v = obj[k];
586
+ return typeof v === "string" ? v : null;
587
+ };
588
+ const bool = (k) => {
589
+ const v = obj[k];
590
+ return typeof v === "boolean" ? v : null;
591
+ };
592
+ const instanceId = num("instance_id");
593
+ const pipeline = str("pipeline");
594
+ const runName = str("run_name");
595
+ const gpuName = str("gpu_name");
596
+ const gpuSku = str("gpu_sku");
597
+ const state = str("state");
598
+ const uptime = num("uptime_seconds");
599
+ const uptimePretty = str("uptime_pretty");
600
+ const dph = num("dph_total");
601
+ const total = num("total_so_far_usd");
602
+ const fetchedAt = num("fetched_at");
603
+ const numGpus = num("num_gpus");
604
+ const overSoft = bool("over_soft");
605
+ const overHard = bool("over_hard");
606
+ if (instanceId === null || !pipeline || runName === null || !gpuName || !gpuSku || !state || uptime === null || !uptimePretty || dph === null || total === null || fetchedAt === null || numGpus === null || overSoft === null || overHard === null) {
607
+ return null;
608
+ }
609
+ const softRaw = obj.soft_cap_usd;
610
+ const hardRaw = obj.hard_cap_usd;
611
+ const soft = typeof softRaw === "number" && Number.isFinite(softRaw) ? softRaw : null;
612
+ const hard = typeof hardRaw === "number" && Number.isFinite(hardRaw) ? hardRaw : null;
613
+ return {
614
+ job_id: jobId,
615
+ instance_id: instanceId,
616
+ pipeline,
617
+ run_name: runName,
618
+ gpu_name: gpuName,
619
+ num_gpus: numGpus,
620
+ gpu_sku: gpuSku,
621
+ state,
622
+ uptime_seconds: uptime,
623
+ uptime_pretty: uptimePretty,
624
+ dph_total: dph,
625
+ total_so_far_usd: total,
626
+ soft_cap_usd: soft,
627
+ hard_cap_usd: hard,
628
+ over_soft: overSoft,
629
+ over_hard: overHard,
630
+ fetched_at: fetchedAt
631
+ };
632
+ }
633
+ function isSafeRelativePath(p) {
634
+ if (typeof p !== "string" || !p.trim()) return false;
635
+ if (p.startsWith("/") || p.includes("..")) return false;
636
+ return true;
637
+ }
638
+ function isSafeCheckpointPath(checkpointDir, trainingRoot) {
639
+ if (typeof checkpointDir !== "string" || !checkpointDir.trim()) return false;
640
+ const root = resolve(trainingRoot);
641
+ const resolved = resolve(checkpointDir);
642
+ return resolved === root || resolved.startsWith(`${root}/`);
643
+ }
644
+ export {
645
+ VastServiceError2 as VastServiceError,
646
+ VastTrainingService
647
+ };
648
+ //# sourceMappingURL=training-vast-service.js.map