mirrorneuron-cli 1.2.8__tar.gz → 1.2.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mirrorneuron_cli-1.2.8/mirrorneuron_cli.egg-info → mirrorneuron_cli-1.2.18}/PKG-INFO +1 -1
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18/mirrorneuron_cli.egg-info}/PKG-INFO +1 -1
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mirrorneuron_cli.egg-info/SOURCES.txt +2 -0
- mirrorneuron_cli-1.2.18/mirrorneuron_cli.egg-info/scm_file_list.json +83 -0
- mirrorneuron_cli-1.2.18/mirrorneuron_cli.egg-info/scm_version.json +8 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/job_cmds.py +3 -9
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/model_cmds.py +24 -3
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/run_cmds.py +145 -1
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/skill_dependencies.py +12 -1
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/sys_cmds.py +11 -5
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/server_cmds.py +205 -120
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_job_cmds.py +4 -4
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_model_cmds.py +35 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_run_cmds.py +117 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_run_helpers.py +3 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_server_cmds.py +207 -66
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_shared.py +12 -12
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/.github/workflows/ci.yml +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/.github/workflows/release.yml +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/.gitignore +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/.python-version +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/AGENTS.md +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/LICENSE +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/README.md +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/RELEASE.md +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mirrorneuron_cli.egg-info/dependency_links.txt +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mirrorneuron_cli.egg-info/entry_points.txt +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mirrorneuron_cli.egg-info/requires.txt +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mirrorneuron_cli.egg-info/top_level.txt +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/__init__.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/banner.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/config.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/error_handler.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/__init__.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/artifacts.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/backup_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/blueprint_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/blueprint_models.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/blueprint_observability.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/blueprint_repository.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/blueprint_resources.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/bundles.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/deployment_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/event_relay.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/resource_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/run_logs.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/run_manifest.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/runtime_health.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/schedule_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/service_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/skill_runtime.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/ui.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/workflow_progress.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/libs/workflow_validation.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/logging_config.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/main.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/runtime_mode.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/runtime_state.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/schemas/workflow_manifest.schema.json +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/sdk_path.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/shared.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/terminal.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/mn_cli/update_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/pyproject.toml +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/scripts/check-release-artifacts.sh +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/scripts/make-release-zip.sh +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/scripts/validate-version-tag.sh +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/setup.cfg +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/conftest.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_backup_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_blueprint_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_blueprint_repository.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_blueprint_resources.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_deployment_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_docker_network_integration.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_main.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_repo_hygiene.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_resource_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_runtime_health.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_runtime_mode.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_runtime_state.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_schedule_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_service_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_sys_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_terminal.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_ui.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_update_cmds.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/tests/test_workflow_validation.py +0 -0
- {mirrorneuron_cli-1.2.8 → mirrorneuron_cli-1.2.18}/uv.lock +0 -0
|
@@ -13,6 +13,8 @@ mirrorneuron_cli.egg-info/SOURCES.txt
|
|
|
13
13
|
mirrorneuron_cli.egg-info/dependency_links.txt
|
|
14
14
|
mirrorneuron_cli.egg-info/entry_points.txt
|
|
15
15
|
mirrorneuron_cli.egg-info/requires.txt
|
|
16
|
+
mirrorneuron_cli.egg-info/scm_file_list.json
|
|
17
|
+
mirrorneuron_cli.egg-info/scm_version.json
|
|
16
18
|
mirrorneuron_cli.egg-info/top_level.txt
|
|
17
19
|
mn_cli/__init__.py
|
|
18
20
|
mn_cli/banner.py
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
"README.md",
|
|
4
|
+
"uv.lock",
|
|
5
|
+
"RELEASE.md",
|
|
6
|
+
".python-version",
|
|
7
|
+
"LICENSE",
|
|
8
|
+
"pyproject.toml",
|
|
9
|
+
"AGENTS.md",
|
|
10
|
+
".gitignore",
|
|
11
|
+
"scripts/check-release-artifacts.sh",
|
|
12
|
+
"scripts/make-release-zip.sh",
|
|
13
|
+
"scripts/validate-version-tag.sh",
|
|
14
|
+
"mn_cli/runtime_state.py",
|
|
15
|
+
"mn_cli/__init__.py",
|
|
16
|
+
"mn_cli/error_handler.py",
|
|
17
|
+
"mn_cli/config.py",
|
|
18
|
+
"mn_cli/sdk_path.py",
|
|
19
|
+
"mn_cli/logging_config.py",
|
|
20
|
+
"mn_cli/banner.py",
|
|
21
|
+
"mn_cli/main.py",
|
|
22
|
+
"mn_cli/runtime_mode.py",
|
|
23
|
+
"mn_cli/server_cmds.py",
|
|
24
|
+
"mn_cli/terminal.py",
|
|
25
|
+
"mn_cli/shared.py",
|
|
26
|
+
"mn_cli/update_cmds.py",
|
|
27
|
+
"mn_cli/libs/backup_cmds.py",
|
|
28
|
+
"mn_cli/libs/model_cmds.py",
|
|
29
|
+
"mn_cli/libs/run_manifest.py",
|
|
30
|
+
"mn_cli/libs/__init__.py",
|
|
31
|
+
"mn_cli/libs/artifacts.py",
|
|
32
|
+
"mn_cli/libs/blueprint_cmds.py",
|
|
33
|
+
"mn_cli/libs/workflow_progress.py",
|
|
34
|
+
"mn_cli/libs/blueprint_models.py",
|
|
35
|
+
"mn_cli/libs/blueprint_observability.py",
|
|
36
|
+
"mn_cli/libs/deployment_cmds.py",
|
|
37
|
+
"mn_cli/libs/run_cmds.py",
|
|
38
|
+
"mn_cli/libs/skill_runtime.py",
|
|
39
|
+
"mn_cli/libs/event_relay.py",
|
|
40
|
+
"mn_cli/libs/resource_cmds.py",
|
|
41
|
+
"mn_cli/libs/skill_dependencies.py",
|
|
42
|
+
"mn_cli/libs/service_cmds.py",
|
|
43
|
+
"mn_cli/libs/run_logs.py",
|
|
44
|
+
"mn_cli/libs/runtime_health.py",
|
|
45
|
+
"mn_cli/libs/bundles.py",
|
|
46
|
+
"mn_cli/libs/blueprint_resources.py",
|
|
47
|
+
"mn_cli/libs/blueprint_repository.py",
|
|
48
|
+
"mn_cli/libs/schedule_cmds.py",
|
|
49
|
+
"mn_cli/libs/sys_cmds.py",
|
|
50
|
+
"mn_cli/libs/ui.py",
|
|
51
|
+
"mn_cli/libs/workflow_validation.py",
|
|
52
|
+
"mn_cli/libs/job_cmds.py",
|
|
53
|
+
"mn_cli/schemas/workflow_manifest.schema.json",
|
|
54
|
+
"tests/test_shared.py",
|
|
55
|
+
"tests/test_model_cmds.py",
|
|
56
|
+
"tests/test_deployment_cmds.py",
|
|
57
|
+
"tests/test_docker_network_integration.py",
|
|
58
|
+
"tests/test_service_cmds.py",
|
|
59
|
+
"tests/test_blueprint_resources.py",
|
|
60
|
+
"tests/test_backup_cmds.py",
|
|
61
|
+
"tests/test_server_cmds.py",
|
|
62
|
+
"tests/test_run_cmds.py",
|
|
63
|
+
"tests/test_blueprint_repository.py",
|
|
64
|
+
"tests/test_blueprint_cmds.py",
|
|
65
|
+
"tests/test_workflow_validation.py",
|
|
66
|
+
"tests/test_runtime_mode.py",
|
|
67
|
+
"tests/test_update_cmds.py",
|
|
68
|
+
"tests/test_schedule_cmds.py",
|
|
69
|
+
"tests/test_run_helpers.py",
|
|
70
|
+
"tests/test_sys_cmds.py",
|
|
71
|
+
"tests/conftest.py",
|
|
72
|
+
"tests/test_terminal.py",
|
|
73
|
+
"tests/test_job_cmds.py",
|
|
74
|
+
"tests/test_ui.py",
|
|
75
|
+
"tests/test_resource_cmds.py",
|
|
76
|
+
"tests/test_main.py",
|
|
77
|
+
"tests/test_runtime_health.py",
|
|
78
|
+
"tests/test_runtime_state.py",
|
|
79
|
+
"tests/test_repo_hygiene.py",
|
|
80
|
+
".github/workflows/release.yml",
|
|
81
|
+
".github/workflows/ci.yml"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
@@ -98,11 +98,6 @@ def list_jobs(running_only: bool = typer.Option(False, "--running-only", help="O
|
|
|
98
98
|
def clear():
|
|
99
99
|
"""Remove all job records except running ones"""
|
|
100
100
|
try:
|
|
101
|
-
admin_token = str(getattr(client, "admin_token", "") or config.grpc_admin_token or "").strip()
|
|
102
|
-
if not admin_token:
|
|
103
|
-
console.print("[red]Error: No local gRPC admin token was found for job clear.[/red]")
|
|
104
|
-
console.print("Start or recreate the runtime so the shared grpc_admin.token file is generated.")
|
|
105
|
-
return
|
|
106
101
|
cleared_count = client.clear_jobs()
|
|
107
102
|
logger.info("Cleared %d non-running jobs", cleared_count)
|
|
108
103
|
print_success_confirmation(
|
|
@@ -115,11 +110,10 @@ def clear():
|
|
|
115
110
|
if e.code() == grpc.StatusCode.PERMISSION_DENIED and "MN_GRPC_ADMIN_TOKEN" in str(e.details()):
|
|
116
111
|
console.print("[red]Error: ClearJobs admin authorization failed.[/red]")
|
|
117
112
|
console.print(
|
|
118
|
-
"The
|
|
119
|
-
"
|
|
120
|
-
"or the running core has not been recreated with the shared token-file mount."
|
|
113
|
+
"The running core rejected the fixed gRPC admin token. "
|
|
114
|
+
"Recreate the runtime with the current fixed-token build."
|
|
121
115
|
)
|
|
122
|
-
console.print("
|
|
116
|
+
console.print("Retry after: mn runtime stop; mn runtime start")
|
|
123
117
|
return
|
|
124
118
|
handle_cli_error(e, console, 'clear')
|
|
125
119
|
except Exception as e:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import os
|
|
4
5
|
import subprocess
|
|
5
6
|
from typing import Annotated, Any, Optional
|
|
6
7
|
|
|
@@ -250,16 +251,21 @@ def install_model_entry(
|
|
|
250
251
|
target = docker_model_name(entry)
|
|
251
252
|
if _docker_model_cli_available():
|
|
252
253
|
_ensure_runner(compatibility.backend, compatibility.accelerator)
|
|
253
|
-
|
|
254
|
+
pull_result = _pull_model(target)
|
|
254
255
|
run_command = ["model", "run", "--detach"]
|
|
255
256
|
resolved_context = context_size or entry.get("context_size")
|
|
256
257
|
if resolved_context and _docker_model_run_supports_context_size():
|
|
257
258
|
run_command.extend(["--context-size", str(resolved_context)])
|
|
258
259
|
run_command.append(target)
|
|
259
260
|
_docker(run_command, timeout=300)
|
|
260
|
-
return {
|
|
261
|
+
return {
|
|
262
|
+
"entry": entry,
|
|
263
|
+
"docker_model": target,
|
|
264
|
+
"compatibility": payload,
|
|
265
|
+
**pull_result,
|
|
266
|
+
}
|
|
261
267
|
|
|
262
|
-
api_result = dmr_api_pull_model(target, timeout=
|
|
268
|
+
api_result = dmr_api_pull_model(target, timeout=_model_pull_timeout_seconds())
|
|
263
269
|
return {
|
|
264
270
|
"entry": entry,
|
|
265
271
|
"docker_model": target,
|
|
@@ -269,6 +275,21 @@ def install_model_entry(
|
|
|
269
275
|
}
|
|
270
276
|
|
|
271
277
|
|
|
278
|
+
def _model_pull_timeout_seconds() -> float:
|
|
279
|
+
try:
|
|
280
|
+
return max(float(os.getenv("MN_DOCKER_MODEL_PULL_TIMEOUT_SECONDS", "3600")), 1.0)
|
|
281
|
+
except ValueError:
|
|
282
|
+
return 3600.0
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _pull_model(target: str) -> dict[str, Any]:
|
|
286
|
+
if _endpoint_responds():
|
|
287
|
+
api_result = dmr_api_pull_model(target, timeout=_model_pull_timeout_seconds())
|
|
288
|
+
return {"transport": "docker_model_runner_api", "api": api_result}
|
|
289
|
+
_docker_model_pull(target)
|
|
290
|
+
return {"transport": "docker_cli"}
|
|
291
|
+
|
|
292
|
+
|
|
272
293
|
def _docker_model_pull(target: str, *, attempts: int = 2) -> None:
|
|
273
294
|
last_error: RuntimeError | None = None
|
|
274
295
|
for attempt in range(1, attempts + 1):
|
|
@@ -61,14 +61,23 @@ from mn_cli.libs.workflow_validation import (
|
|
|
61
61
|
from mn_cli.libs.blueprint_observability import (
|
|
62
62
|
make_blueprint_run_id as _make_blueprint_run_id,
|
|
63
63
|
)
|
|
64
|
+
from mn_cli.libs.blueprint_models import BlueprintModelOps, blueprint_model_dependency_summary
|
|
65
|
+
from mn_cli.libs.model_cmds import install_model_entry, model_installed
|
|
64
66
|
from mn_cli.libs.blueprint_resources import cleanup_blueprint_host_hooks
|
|
65
67
|
from mn_cli.server_cmds import ensure_context_engine_runtime
|
|
66
68
|
from mn_cli.shared import console, client, logger
|
|
67
69
|
from mn_cli.terminal import use_progress
|
|
68
70
|
from mn_cli.error_handler import handle_cli_error
|
|
69
71
|
from mn_sdk import (
|
|
72
|
+
cluster_provided_model,
|
|
73
|
+
docker_model_name,
|
|
74
|
+
load_model_catalog,
|
|
75
|
+
load_model_ownership,
|
|
70
76
|
make_validation_report,
|
|
71
77
|
prepare_job_submission,
|
|
78
|
+
record_model_owner,
|
|
79
|
+
required_blueprint_models,
|
|
80
|
+
resolve_model_entry,
|
|
72
81
|
run_hardware_requirements_validation,
|
|
73
82
|
run_input_validation,
|
|
74
83
|
run_model_validation,
|
|
@@ -234,6 +243,119 @@ def _manifest_config(manifest: dict[str, Any]) -> dict[str, Any]:
|
|
|
234
243
|
return {}
|
|
235
244
|
|
|
236
245
|
|
|
246
|
+
def _prepare_runtime_models_for_run_or_exit(
|
|
247
|
+
bundle_dir: Path,
|
|
248
|
+
manifest: dict[str, Any],
|
|
249
|
+
*,
|
|
250
|
+
env_overrides: Optional[dict[str, str]] = None,
|
|
251
|
+
config_overrides: Optional[dict[str, Any]] = None,
|
|
252
|
+
force: bool = False,
|
|
253
|
+
) -> dict[str, Any]:
|
|
254
|
+
config = load_blueprint_config(bundle_dir, config_overrides=config_overrides) or {}
|
|
255
|
+
validation_manifest = _manifest_for_model_validation(manifest, config)
|
|
256
|
+
summary = blueprint_model_dependency_summary(
|
|
257
|
+
blueprint_id=_runtime_model_blueprint_id(bundle_dir, manifest, config),
|
|
258
|
+
blueprint_revision=_runtime_model_blueprint_revision(manifest, config),
|
|
259
|
+
bundle_root=bundle_dir,
|
|
260
|
+
manifest=validation_manifest,
|
|
261
|
+
config=config,
|
|
262
|
+
install_source=str(bundle_dir),
|
|
263
|
+
force=force,
|
|
264
|
+
ops=BlueprintModelOps(
|
|
265
|
+
load_model_catalog=load_model_catalog,
|
|
266
|
+
required_blueprint_models=required_blueprint_models,
|
|
267
|
+
load_model_ownership=load_model_ownership,
|
|
268
|
+
resolve_model_entry=resolve_model_entry,
|
|
269
|
+
docker_model_name=docker_model_name,
|
|
270
|
+
cluster_provided_model=cluster_provided_model,
|
|
271
|
+
record_model_owner=record_model_owner,
|
|
272
|
+
model_installed=model_installed,
|
|
273
|
+
install_model_entry=install_model_entry,
|
|
274
|
+
notify_model_install_start=_print_runtime_model_install_start,
|
|
275
|
+
),
|
|
276
|
+
)
|
|
277
|
+
_print_runtime_model_install_summary(summary)
|
|
278
|
+
if summary["errors"]:
|
|
279
|
+
raise typer.Exit(1)
|
|
280
|
+
return summary
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _runtime_model_blueprint_id(
|
|
284
|
+
bundle_dir: Path,
|
|
285
|
+
manifest: dict[str, Any],
|
|
286
|
+
config: dict[str, Any],
|
|
287
|
+
) -> str:
|
|
288
|
+
metadata = manifest.get("metadata") if isinstance(manifest.get("metadata"), dict) else {}
|
|
289
|
+
identity = config.get("identity") if isinstance(config.get("identity"), dict) else {}
|
|
290
|
+
for value in (
|
|
291
|
+
metadata.get("blueprint_id"),
|
|
292
|
+
metadata.get("blueprintId"),
|
|
293
|
+
identity.get("blueprint_id"),
|
|
294
|
+
identity.get("blueprintId"),
|
|
295
|
+
manifest.get("id"),
|
|
296
|
+
manifest.get("graph_id"),
|
|
297
|
+
manifest.get("job_name"),
|
|
298
|
+
):
|
|
299
|
+
text = str(value or "").strip()
|
|
300
|
+
if text:
|
|
301
|
+
return text
|
|
302
|
+
return bundle_dir.name
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _runtime_model_blueprint_revision(
|
|
306
|
+
manifest: dict[str, Any],
|
|
307
|
+
config: dict[str, Any],
|
|
308
|
+
) -> str | None:
|
|
309
|
+
metadata = manifest.get("metadata") if isinstance(manifest.get("metadata"), dict) else {}
|
|
310
|
+
identity = config.get("identity") if isinstance(config.get("identity"), dict) else {}
|
|
311
|
+
for value in (
|
|
312
|
+
metadata.get("blueprint_revision"),
|
|
313
|
+
metadata.get("blueprintRevision"),
|
|
314
|
+
identity.get("blueprint_revision"),
|
|
315
|
+
identity.get("blueprintRevision"),
|
|
316
|
+
manifest.get("revision"),
|
|
317
|
+
manifest.get("version"),
|
|
318
|
+
):
|
|
319
|
+
text = str(value or "").strip()
|
|
320
|
+
if text:
|
|
321
|
+
return text
|
|
322
|
+
return None
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _print_runtime_model_install_start(model: dict[str, Any]) -> None:
|
|
326
|
+
label = str(model.get("id") or model.get("model") or "runtime model")
|
|
327
|
+
docker_model = str(model.get("model") or "")
|
|
328
|
+
backend = str(model.get("backend") or "auto")
|
|
329
|
+
detail = f"{label} ({docker_model})" if docker_model and docker_model != label else label
|
|
330
|
+
console.print(
|
|
331
|
+
f"[yellow]Runtime model {detail} is not installed. "
|
|
332
|
+
f"Installing with backend {backend}; this may take a few minutes the first time.[/yellow]"
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _print_runtime_model_install_summary(summary: dict[str, Any]) -> None:
|
|
337
|
+
models = summary.get("models") or []
|
|
338
|
+
if not models:
|
|
339
|
+
return
|
|
340
|
+
|
|
341
|
+
prepared = [
|
|
342
|
+
item
|
|
343
|
+
for item in models
|
|
344
|
+
if str(item.get("status") or "")
|
|
345
|
+
in {"installed", "already_installed", "service_required", "cluster_provided"}
|
|
346
|
+
]
|
|
347
|
+
if prepared:
|
|
348
|
+
labels = ", ".join(
|
|
349
|
+
str(item.get("id") or item.get("model") or "runtime model")
|
|
350
|
+
for item in prepared[:4]
|
|
351
|
+
)
|
|
352
|
+
if len(prepared) > 4:
|
|
353
|
+
labels = f"{labels}, +{len(prepared) - 4} more"
|
|
354
|
+
console.print(f"[green]Runtime models ready:[/green] {labels}")
|
|
355
|
+
for error in summary.get("errors") or []:
|
|
356
|
+
console.print(f"[red]Runtime model install failed: {error}[/red]")
|
|
357
|
+
|
|
358
|
+
|
|
237
359
|
def _ensure_context_engine_for_run_if_needed(
|
|
238
360
|
bundle_dir: Path,
|
|
239
361
|
manifest: dict[str, Any],
|
|
@@ -1609,6 +1731,17 @@ def run_bundle(
|
|
|
1609
1731
|
env_overrides=env_overrides,
|
|
1610
1732
|
config_overrides=config_overrides,
|
|
1611
1733
|
)
|
|
1734
|
+
_print_launch_progress(
|
|
1735
|
+
"Prepare runtime models",
|
|
1736
|
+
"installing any missing Docker Model Runner models required by this blueprint.",
|
|
1737
|
+
)
|
|
1738
|
+
_prepare_runtime_models_for_run_or_exit(
|
|
1739
|
+
bundle_dir,
|
|
1740
|
+
manifest_dict,
|
|
1741
|
+
env_overrides=env_overrides,
|
|
1742
|
+
config_overrides=config_overrides,
|
|
1743
|
+
force=force,
|
|
1744
|
+
)
|
|
1612
1745
|
_validate_manifest_models_or_exit(
|
|
1613
1746
|
bundle_dir,
|
|
1614
1747
|
manifest_dict,
|
|
@@ -1623,7 +1756,18 @@ def run_bundle(
|
|
|
1623
1756
|
)
|
|
1624
1757
|
else:
|
|
1625
1758
|
console.print(
|
|
1626
|
-
"[yellow]Validation skipped because --force was provided; service checks, model checks, input checks, and non-hard runtime requirements will be bypassed
|
|
1759
|
+
"[yellow]Validation skipped because --force was provided; service checks, model checks, input checks, and non-hard runtime requirements will be bypassed, but required runtime models will still be prepared.[/yellow]"
|
|
1760
|
+
)
|
|
1761
|
+
_print_launch_progress(
|
|
1762
|
+
"Prepare runtime models",
|
|
1763
|
+
"installing any missing Docker Model Runner models required by this blueprint.",
|
|
1764
|
+
)
|
|
1765
|
+
_prepare_runtime_models_for_run_or_exit(
|
|
1766
|
+
bundle_dir,
|
|
1767
|
+
manifest_dict,
|
|
1768
|
+
env_overrides=env_overrides,
|
|
1769
|
+
config_overrides=config_overrides,
|
|
1770
|
+
force=force,
|
|
1627
1771
|
)
|
|
1628
1772
|
_print_launch_progress(
|
|
1629
1773
|
"Package workflow",
|
|
@@ -79,8 +79,19 @@ def gar_requirement_lines(manifest: dict[str, Any] | None) -> list[str]:
|
|
|
79
79
|
]
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def gar_requirements_file_lines(manifest: dict[str, Any] | None) -> list[str]:
|
|
83
|
+
requirements = pinned_skill_dependency_requirements(manifest)
|
|
84
|
+
if not requirements:
|
|
85
|
+
return []
|
|
86
|
+
return [
|
|
87
|
+
f"--index-url {GAR_PIP_INDEX_URL}",
|
|
88
|
+
f"--extra-index-url {PYPI_PIP_INDEX_URL}",
|
|
89
|
+
*requirements,
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
|
|
82
93
|
def gar_requirements_text(manifest: dict[str, Any] | None) -> str:
|
|
83
|
-
lines =
|
|
94
|
+
lines = gar_requirements_file_lines(manifest)
|
|
84
95
|
return "\n".join(lines).strip() + ("\n" if lines else "")
|
|
85
96
|
|
|
86
97
|
|
|
@@ -310,15 +310,21 @@ def ensure_context_engine(
|
|
|
310
310
|
)
|
|
311
311
|
summary = ensure_context_engine_runtime(force=force)
|
|
312
312
|
progress.update(task, description="[green]Context memory is ready.")
|
|
313
|
+
details = [
|
|
314
|
+
("Service", summary["service"]),
|
|
315
|
+
("Model", summary["model"]),
|
|
316
|
+
("Model status", summary.get("model_status", "unknown")),
|
|
317
|
+
]
|
|
318
|
+
if summary.get("membrane_dir"):
|
|
319
|
+
details.append(("Membrane", summary["membrane_dir"]))
|
|
320
|
+
if summary.get("engine_image"):
|
|
321
|
+
details.append(("Engine image", summary["engine_image"]))
|
|
322
|
+
|
|
313
323
|
print_success_confirmation(
|
|
314
324
|
console,
|
|
315
325
|
"Context engine",
|
|
316
326
|
status=summary["status"],
|
|
317
|
-
details=
|
|
318
|
-
("Service", summary["service"]),
|
|
319
|
-
("Model", summary["model"]),
|
|
320
|
-
("Membrane", summary["membrane_dir"]),
|
|
321
|
-
],
|
|
327
|
+
details=details,
|
|
322
328
|
next_steps="mn runtime health",
|
|
323
329
|
)
|
|
324
330
|
except Exception as exc:
|