@aws/ml-container-creator 0.13.4 → 0.15.0
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.
- package/README.md +23 -5
- package/config/parameter-schema-v2.json +32 -4
- package/infra/ci-harness/lib/ci-harness-stack.ts +13 -5
- package/infra/ci-harness/package-lock.json +122 -116
- package/infra/ci-harness/package.json +1 -1
- package/package.json +5 -3
- package/pyproject.toml +21 -0
- package/requirements.txt +19 -0
- package/servers/instance-sizer/index.js +72 -4
- package/servers/instance-sizer/lib/model-resolver.js +28 -2
- package/src/app.js +17 -0
- package/src/lib/bootstrap-command-handler.js +33 -23
- package/src/lib/config-loader.js +18 -0
- package/src/lib/config-manager.js +6 -1
- package/src/lib/dataset-slug.js +152 -0
- package/src/lib/generated/cli-options.js +9 -3
- package/src/lib/generated/parameter-matrix.js +14 -3
- package/src/lib/generated/validation-rules.js +1 -1
- package/src/lib/mcp-query-runner.js +6 -0
- package/src/lib/prompt-runner.js +5 -0
- package/src/lib/prompts/feature-prompts.js +1 -1
- package/src/lib/template-manager.js +0 -7
- package/src/lib/template-variable-resolver.js +51 -1
- package/src/lib/tune-config-state.js +14 -1
- package/templates/do/.adapter_helper.py +451 -0
- package/templates/do/.benchmark_writer.py +22 -0
- package/templates/do/.register_helper.py +1163 -0
- package/templates/do/.stage_helper.py +419 -0
- package/templates/do/.tune_helper.py +379 -65
- package/templates/do/__pycache__/.adapter_helper.cpython-312.pyc +0 -0
- package/templates/do/__pycache__/.benchmark_writer.cpython-312.pyc +0 -0
- package/templates/do/__pycache__/.register_helper.cpython-312.pyc +0 -0
- package/templates/do/__pycache__/.tune_helper.cpython-312.pyc +0 -0
- package/templates/do/adapter +427 -27
- package/templates/do/add-ic +85 -3
- package/templates/do/benchmark +173 -15
- package/templates/do/config +24 -0
- package/templates/do/lib/inference-component.sh +56 -3
- package/templates/do/lib/profile.sh +5 -0
- package/templates/do/register +552 -6
- package/templates/do/stage +91 -272
- package/templates/do/test +12 -2
- package/templates/do/tune +264 -12
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/templates/do/adapter
CHANGED
|
@@ -35,6 +35,7 @@ _usage() {
|
|
|
35
35
|
echo " add <name> --weights <s3-uri> Add a new LoRA adapter from S3"
|
|
36
36
|
echo " add <name> --from-hub <hf-repo-id> Add a new LoRA adapter from HuggingFace Hub"
|
|
37
37
|
echo " add <name> --from-tune [technique] Add adapter from do/tune output"
|
|
38
|
+
echo " add <name> --from-registry [arn] Add adapter from model registry"
|
|
38
39
|
echo " list List all adapters on the endpoint"
|
|
39
40
|
echo " remove <name> Remove an adapter"
|
|
40
41
|
echo " update <name> --weights <new-s3-uri> Update adapter weights from S3"
|
|
@@ -43,12 +44,18 @@ _usage() {
|
|
|
43
44
|
echo ""
|
|
44
45
|
echo "Options:"
|
|
45
46
|
echo " --help, -h Show this help message"
|
|
47
|
+
echo " --local Use local aws s3 cp instead of Processing Job (--from-tune)"
|
|
48
|
+
echo " --no-wait Submit Processing Job and return immediately (--from-tune)"
|
|
46
49
|
echo ""
|
|
47
50
|
echo "Examples:"
|
|
48
51
|
echo " ./do/adapter add ectsum --weights s3://my-bucket/adapters/ectsum/adapter.tar.gz"
|
|
49
52
|
echo " ./do/adapter add ectsum --from-hub predibase/llama-3.1-8b-ectsum"
|
|
50
53
|
echo " ./do/adapter add tuned-sft --from-tune"
|
|
51
54
|
echo " ./do/adapter add tuned-sft --from-tune sft"
|
|
55
|
+
echo " ./do/adapter add tuned-sft --from-tune --local"
|
|
56
|
+
echo " ./do/adapter add tuned-sft --from-tune --no-wait"
|
|
57
|
+
echo " ./do/adapter add my-adapter --from-registry"
|
|
58
|
+
echo " ./do/adapter add my-adapter --from-registry arn:aws:sagemaker:...:model-package/proj/2"
|
|
52
59
|
echo " ./do/adapter list"
|
|
53
60
|
echo " ./do/adapter remove ectsum"
|
|
54
61
|
echo " ./do/adapter update ectsum --weights s3://my-bucket/adapters/ectsum-v2/adapter.tar.gz"
|
|
@@ -56,7 +63,7 @@ _usage() {
|
|
|
56
63
|
echo ""
|
|
57
64
|
echo "Adapter metadata is stored in do/adapters/<name>.conf"
|
|
58
65
|
echo ""
|
|
59
|
-
echo "Note: --weights, --from-hub, and --from-
|
|
66
|
+
echo "Note: --weights, --from-hub, --from-tune, and --from-registry are mutually exclusive."
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
# ── Validate LoRA is enabled ──────────────────────────────────────────────────
|
|
@@ -367,6 +374,10 @@ _adapter_add() {
|
|
|
367
374
|
local from_hub=""
|
|
368
375
|
local from_tune=""
|
|
369
376
|
local from_tune_technique=""
|
|
377
|
+
local from_registry=""
|
|
378
|
+
local registry_arn=""
|
|
379
|
+
local use_local=""
|
|
380
|
+
local no_wait=""
|
|
370
381
|
|
|
371
382
|
# Parse add arguments
|
|
372
383
|
shift # remove 'add' from args
|
|
@@ -400,10 +411,29 @@ _adapter_add() {
|
|
|
400
411
|
shift
|
|
401
412
|
fi
|
|
402
413
|
;;
|
|
414
|
+
--from-registry)
|
|
415
|
+
from_registry="true"
|
|
416
|
+
# Check if next argument is an ARN (starts with arn:)
|
|
417
|
+
if [ -n "${2:-}" ] && [[ "${2}" == arn:* ]]; then
|
|
418
|
+
registry_arn="$2"
|
|
419
|
+
shift 2
|
|
420
|
+
else
|
|
421
|
+
shift
|
|
422
|
+
fi
|
|
423
|
+
;;
|
|
424
|
+
--local)
|
|
425
|
+
use_local="true"
|
|
426
|
+
shift
|
|
427
|
+
;;
|
|
428
|
+
--no-wait)
|
|
429
|
+
no_wait="true"
|
|
430
|
+
shift
|
|
431
|
+
;;
|
|
403
432
|
--help|-h)
|
|
404
433
|
echo "Usage: ./do/adapter add <name> --weights <s3-uri>"
|
|
405
434
|
echo " ./do/adapter add <name> --from-hub <hf-repo-id>"
|
|
406
435
|
echo " ./do/adapter add <name> --from-tune [technique]"
|
|
436
|
+
echo " ./do/adapter add <name> --from-registry [version-arn]"
|
|
407
437
|
echo ""
|
|
408
438
|
echo "Add a new LoRA adapter to the endpoint."
|
|
409
439
|
echo ""
|
|
@@ -414,14 +444,23 @@ _adapter_add() {
|
|
|
414
444
|
echo " --from-tune [technique] Use adapter output from do/tune"
|
|
415
445
|
echo " Without technique: uses latest tune output"
|
|
416
446
|
echo " With technique (e.g., sft, dpo): uses technique-specific output"
|
|
447
|
+
echo " --from-registry [arn] Add adapter from model registry"
|
|
448
|
+
echo " Without ARN: presents interactive selection"
|
|
449
|
+
echo " With ARN: adds directly using specified version ARN"
|
|
450
|
+
echo " --local Use local aws s3 cp instead of Processing Job (--from-tune only)"
|
|
451
|
+
echo " --no-wait Submit Processing Job and return immediately (--from-tune only)"
|
|
417
452
|
echo ""
|
|
418
|
-
echo "Note: --weights, --from-hub, and --from-
|
|
453
|
+
echo "Note: --weights, --from-hub, --from-tune, and --from-registry are mutually exclusive."
|
|
419
454
|
echo ""
|
|
420
455
|
echo "Examples:"
|
|
421
456
|
echo " ./do/adapter add ectsum --weights s3://bucket/adapters/ectsum/adapter.tar.gz"
|
|
422
457
|
echo " ./do/adapter add ectsum --from-hub predibase/llama-3.1-8b-ectsum"
|
|
423
458
|
echo " ./do/adapter add tuned-sft --from-tune"
|
|
424
459
|
echo " ./do/adapter add tuned-sft --from-tune sft"
|
|
460
|
+
echo " ./do/adapter add tuned-sft --from-tune --local"
|
|
461
|
+
echo " ./do/adapter add tuned-sft --from-tune --no-wait"
|
|
462
|
+
echo " ./do/adapter add my-adapter --from-registry"
|
|
463
|
+
echo " ./do/adapter add my-adapter --from-registry arn:aws:sagemaker:...:model-package/proj/2"
|
|
425
464
|
exit 0
|
|
426
465
|
;;
|
|
427
466
|
-*)
|
|
@@ -429,6 +468,7 @@ _adapter_add() {
|
|
|
429
468
|
echo " Usage: ./do/adapter add <name> --weights <s3-uri>"
|
|
430
469
|
echo " ./do/adapter add <name> --from-hub <hf-repo-id>"
|
|
431
470
|
echo " ./do/adapter add <name> --from-tune [technique]"
|
|
471
|
+
echo " ./do/adapter add <name> --from-registry [version-arn]"
|
|
432
472
|
exit 1
|
|
433
473
|
;;
|
|
434
474
|
*)
|
|
@@ -439,6 +479,7 @@ _adapter_add() {
|
|
|
439
479
|
echo " Usage: ./do/adapter add <name> --weights <s3-uri>"
|
|
440
480
|
echo " ./do/adapter add <name> --from-hub <hf-repo-id>"
|
|
441
481
|
echo " ./do/adapter add <name> --from-tune [technique]"
|
|
482
|
+
echo " ./do/adapter add <name> --from-registry [version-arn]"
|
|
442
483
|
exit 1
|
|
443
484
|
fi
|
|
444
485
|
shift
|
|
@@ -460,46 +501,97 @@ _adapter_add() {
|
|
|
460
501
|
[ -n "${weights_uri}" ] && source_count=$((source_count + 1))
|
|
461
502
|
[ -n "${from_hub}" ] && source_count=$((source_count + 1))
|
|
462
503
|
[ -n "${from_tune}" ] && source_count=$((source_count + 1))
|
|
504
|
+
[ -n "${from_registry}" ] && source_count=$((source_count + 1))
|
|
463
505
|
|
|
464
506
|
if [ "${source_count}" -gt 1 ]; then
|
|
465
|
-
echo "❌ --weights, --from-hub, and --from-
|
|
507
|
+
echo "❌ --weights, --from-hub, --from-tune, and --from-registry are mutually exclusive"
|
|
466
508
|
echo ""
|
|
467
509
|
echo " Use one of:"
|
|
468
510
|
echo " ./do/adapter add ${adapter_name} --weights <s3-uri>"
|
|
469
511
|
echo " ./do/adapter add ${adapter_name} --from-hub <hf-repo-id>"
|
|
470
512
|
echo " ./do/adapter add ${adapter_name} --from-tune [technique]"
|
|
513
|
+
echo " ./do/adapter add ${adapter_name} --from-registry [version-arn]"
|
|
471
514
|
exit 1
|
|
472
515
|
fi
|
|
473
516
|
|
|
474
517
|
if [ "${source_count}" -eq 0 ]; then
|
|
475
|
-
echo "❌ One of --weights, --from-hub, or --from-
|
|
518
|
+
echo "❌ One of --weights, --from-hub, --from-tune, or --from-registry is required"
|
|
476
519
|
echo " Usage: ./do/adapter add <name> --weights <s3-uri>"
|
|
477
520
|
echo " ./do/adapter add <name> --from-hub <hf-repo-id>"
|
|
478
521
|
echo " ./do/adapter add <name> --from-tune [technique]"
|
|
522
|
+
echo " ./do/adapter add <name> --from-registry [version-arn]"
|
|
479
523
|
exit 1
|
|
480
524
|
fi
|
|
481
525
|
|
|
482
526
|
# ── Resolve --from-tune to weights_uri ────────────────────────────────
|
|
483
527
|
if [ -n "${from_tune}" ]; then
|
|
484
528
|
if [ -n "${from_tune_technique}" ]; then
|
|
485
|
-
#
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
echo ""
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
529
|
+
# Check if technique contains a hyphen — may be technique-dataset compound
|
|
530
|
+
if [[ "${from_tune_technique}" == *-* ]]; then
|
|
531
|
+
# Try compound key: TUNE_ADAPTER_PATH_<TECHNIQUE>_<SLUG>
|
|
532
|
+
local compound_technique="${from_tune_technique%%-*}"
|
|
533
|
+
local compound_slug="${from_tune_technique#*-}"
|
|
534
|
+
local compound_technique_upper
|
|
535
|
+
compound_technique_upper=$(echo "${compound_technique}" | tr '[:lower:]' '[:upper:]')
|
|
536
|
+
local compound_slug_upper
|
|
537
|
+
compound_slug_upper=$(echo "${compound_slug}" | tr '[:lower:]' '[:upper:]' | sed 's/-/_/g')
|
|
538
|
+
local compound_var="TUNE_ADAPTER_PATH_${compound_technique_upper}_${compound_slug_upper}"
|
|
539
|
+
local compound_path="${!compound_var:-}"
|
|
540
|
+
|
|
541
|
+
if [ -n "${compound_path}" ]; then
|
|
542
|
+
weights_uri="${compound_path}"
|
|
543
|
+
echo "📦 Using tune adapter output for technique '${compound_technique}' dataset '${compound_slug}': ${weights_uri}"
|
|
544
|
+
else
|
|
545
|
+
# Fallback: try as technique-only
|
|
546
|
+
local technique_upper
|
|
547
|
+
technique_upper=$(echo "${from_tune_technique}" | tr '[:lower:]' '[:upper:]' | sed 's/-/_/g')
|
|
548
|
+
local tune_var="TUNE_ADAPTER_PATH_${technique_upper}"
|
|
549
|
+
local tune_path="${!tune_var:-}"
|
|
550
|
+
|
|
551
|
+
if [ -n "${tune_path}" ]; then
|
|
552
|
+
echo "⚠️ ${compound_var} not found, falling back to ${tune_var}"
|
|
553
|
+
weights_uri="${tune_path}"
|
|
554
|
+
echo "📦 Using tune adapter output for technique '${from_tune_technique}': ${weights_uri}"
|
|
555
|
+
else
|
|
556
|
+
# Try the technique part alone as final fallback
|
|
557
|
+
local fallback_var="TUNE_ADAPTER_PATH_${compound_technique_upper}"
|
|
558
|
+
local fallback_path="${!fallback_var:-}"
|
|
559
|
+
|
|
560
|
+
if [ -n "${fallback_path}" ]; then
|
|
561
|
+
echo "⚠️ ${compound_var} not found, falling back to ${fallback_var}"
|
|
562
|
+
weights_uri="${fallback_path}"
|
|
563
|
+
echo "📦 Using tune adapter output for technique '${compound_technique}': ${weights_uri}"
|
|
564
|
+
else
|
|
565
|
+
echo "❌ No adapter output found for: ${from_tune_technique}"
|
|
566
|
+
echo ""
|
|
567
|
+
echo " Tried: ${compound_var}, ${fallback_var}"
|
|
568
|
+
echo ""
|
|
569
|
+
echo " Run a tune job first:"
|
|
570
|
+
echo " ./do/tune --technique ${compound_technique} --dataset <source>"
|
|
571
|
+
exit 1
|
|
572
|
+
fi
|
|
573
|
+
fi
|
|
574
|
+
fi
|
|
575
|
+
else
|
|
576
|
+
# Technique-only: read TUNE_ADAPTER_PATH_<TECHNIQUE>
|
|
577
|
+
local technique_upper
|
|
578
|
+
technique_upper=$(echo "${from_tune_technique}" | tr '[:lower:]' '[:upper:]')
|
|
579
|
+
local tune_var="TUNE_ADAPTER_PATH_${technique_upper}"
|
|
580
|
+
local tune_path="${!tune_var:-}"
|
|
581
|
+
|
|
582
|
+
if [ -z "${tune_path}" ]; then
|
|
583
|
+
echo "❌ No adapter output found for technique: ${from_tune_technique}"
|
|
584
|
+
echo ""
|
|
585
|
+
echo " ${tune_var} is not set in do/config."
|
|
586
|
+
echo ""
|
|
587
|
+
echo " Run a tune job first:"
|
|
588
|
+
echo " ./do/tune --technique ${from_tune_technique} --dataset <source>"
|
|
589
|
+
exit 1
|
|
590
|
+
fi
|
|
500
591
|
|
|
501
|
-
|
|
502
|
-
|
|
592
|
+
weights_uri="${tune_path}"
|
|
593
|
+
echo "📦 Using tune adapter output for technique '${from_tune_technique}': ${weights_uri}"
|
|
594
|
+
fi
|
|
503
595
|
else
|
|
504
596
|
# No technique: read TUNE_OUTPUT_PATH_LATEST and verify type
|
|
505
597
|
if [ -z "${TUNE_OUTPUT_PATH_LATEST:-}" ]; then
|
|
@@ -529,6 +621,95 @@ _adapter_add() {
|
|
|
529
621
|
fi
|
|
530
622
|
echo ""
|
|
531
623
|
|
|
624
|
+
# ── Route to Processing Job helper (default) or local path ────────
|
|
625
|
+
if [ -z "${use_local}" ]; then
|
|
626
|
+
# Default: use Processing Job via .adapter_helper.py
|
|
627
|
+
echo "🚀 Submitting Processing Job to stage adapter..."
|
|
628
|
+
echo ""
|
|
629
|
+
|
|
630
|
+
# Resolve execution role
|
|
631
|
+
local exec_role="${EXECUTION_ROLE_ARN:-}"
|
|
632
|
+
if [ -z "${exec_role}" ]; then
|
|
633
|
+
exec_role="${ROLE_ARN:-}"
|
|
634
|
+
fi
|
|
635
|
+
if [ -z "${exec_role}" ]; then
|
|
636
|
+
exec_role="${SAGEMAKER_ROLE_ARN:-}"
|
|
637
|
+
fi
|
|
638
|
+
if [ -z "${exec_role}" ]; then
|
|
639
|
+
echo "❌ No execution role found."
|
|
640
|
+
echo ""
|
|
641
|
+
echo " Run 'ml-container-creator bootstrap' to set up your profile,"
|
|
642
|
+
echo " or set ROLE_ARN / EXECUTION_ROLE_ARN in do/config."
|
|
643
|
+
exit 1
|
|
644
|
+
fi
|
|
645
|
+
|
|
646
|
+
# Resolve S3 bucket
|
|
647
|
+
local adapter_bucket="${ADAPTER_S3_BUCKET:-}"
|
|
648
|
+
if [ -z "${adapter_bucket}" ]; then
|
|
649
|
+
local account_id
|
|
650
|
+
account_id=$(aws sts get-caller-identity --query Account --output text 2>/dev/null || echo "")
|
|
651
|
+
if [ -z "${account_id}" ]; then
|
|
652
|
+
echo "❌ Could not determine AWS account ID."
|
|
653
|
+
echo " Ensure AWS credentials are configured."
|
|
654
|
+
exit 4
|
|
655
|
+
fi
|
|
656
|
+
adapter_bucket="mlcc-adapters-${account_id}-${AWS_REGION}"
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
# Build helper args
|
|
660
|
+
local helper_args=(
|
|
661
|
+
"stage-from-tune"
|
|
662
|
+
"--training-output-s3-uri" "${weights_uri}"
|
|
663
|
+
"--adapter-name" "${adapter_name}"
|
|
664
|
+
"--bucket" "${adapter_bucket}"
|
|
665
|
+
"--project" "${PROJECT_NAME}"
|
|
666
|
+
"--role-arn" "${exec_role}"
|
|
667
|
+
"--region" "${AWS_REGION}"
|
|
668
|
+
)
|
|
669
|
+
if [ -n "${no_wait}" ]; then
|
|
670
|
+
helper_args+=("--no-wait")
|
|
671
|
+
fi
|
|
672
|
+
|
|
673
|
+
# Invoke the Python helper
|
|
674
|
+
local helper_output
|
|
675
|
+
if ! helper_output=$(python3 "${SCRIPT_DIR}/.adapter_helper.py" "${helper_args[@]}" 2>/dev/null); then
|
|
676
|
+
echo "❌ Processing Job failed. See error above."
|
|
677
|
+
exit 1
|
|
678
|
+
fi
|
|
679
|
+
|
|
680
|
+
# Parse JSON output from helper (extract only the JSON line, skip any log noise)
|
|
681
|
+
local json_line
|
|
682
|
+
json_line=$(echo "${helper_output}" | grep -E '^\{' | tail -1)
|
|
683
|
+
local job_status
|
|
684
|
+
job_status=$(echo "${json_line}" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('status',''))" 2>/dev/null || echo "")
|
|
685
|
+
|
|
686
|
+
if [ "${job_status}" = "Completed" ] || [ "${job_status}" = "InProgress" ]; then
|
|
687
|
+
echo "${json_line}"
|
|
688
|
+
# Extract adapter_s3_uri for downstream use
|
|
689
|
+
local staged_adapter_uri
|
|
690
|
+
staged_adapter_uri=$(echo "${json_line}" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('adapter_s3_uri',''))" 2>/dev/null || echo "")
|
|
691
|
+
|
|
692
|
+
if [ -n "${no_wait}" ]; then
|
|
693
|
+
echo ""
|
|
694
|
+
echo "✅ Processing Job submitted. Check status with:"
|
|
695
|
+
echo " python3 ${SCRIPT_DIR}/.adapter_helper.py status --job-name <job-name>"
|
|
696
|
+
echo ""
|
|
697
|
+
echo " Once complete, re-run without --no-wait to register the adapter."
|
|
698
|
+
exit 0
|
|
699
|
+
fi
|
|
700
|
+
|
|
701
|
+
# Update weights_uri to point to the staged adapter
|
|
702
|
+
weights_uri="${staged_adapter_uri}"
|
|
703
|
+
echo ""
|
|
704
|
+
echo "✅ Adapter staged via Processing Job: ${weights_uri}"
|
|
705
|
+
else
|
|
706
|
+
echo "❌ Unexpected status from Processing Job helper: ${job_status}"
|
|
707
|
+
echo " Output: ${helper_output}"
|
|
708
|
+
exit 1
|
|
709
|
+
fi
|
|
710
|
+
else
|
|
711
|
+
# ── --local flag: Package tune artifacts locally (original behavior) ──
|
|
712
|
+
|
|
532
713
|
# ── Package tune artifacts as tar.gz if needed ────────────────────
|
|
533
714
|
# Tune output is an S3 path that may be:
|
|
534
715
|
# 1. Already a tar.gz file (s3://...adapter.tar.gz) → use directly
|
|
@@ -677,6 +858,137 @@ _adapter_add() {
|
|
|
677
858
|
weights_uri="${s3_tar_path}"
|
|
678
859
|
fi
|
|
679
860
|
echo ""
|
|
861
|
+
fi # end --local else branch
|
|
862
|
+
fi
|
|
863
|
+
|
|
864
|
+
# ── Resolve --from-registry to weights_uri ────────────────────────────
|
|
865
|
+
if [ -n "${from_registry}" ]; then
|
|
866
|
+
if [ -z "${registry_arn}" ]; then
|
|
867
|
+
# Interactive mode: query registry and present selection (AC-4.2)
|
|
868
|
+
# Check if stdin is a TTY (AC-4.4)
|
|
869
|
+
if [ ! -t 0 ]; then
|
|
870
|
+
echo "Error: --from-registry requires an explicit version ARN in non-interactive mode."
|
|
871
|
+
echo "Usage: ./do/adapter add <name> --from-registry <version-arn>"
|
|
872
|
+
exit 1
|
|
873
|
+
fi
|
|
874
|
+
|
|
875
|
+
echo "📦 Querying model registry for available adapters..."
|
|
876
|
+
echo ""
|
|
877
|
+
|
|
878
|
+
local adapters_json
|
|
879
|
+
adapters_json=$(python3 "${SCRIPT_DIR}/.register_helper.py" list-adapters \
|
|
880
|
+
--project-name "${PROJECT_NAME}" \
|
|
881
|
+
--region "${AWS_REGION}" 2>/dev/null)
|
|
882
|
+
|
|
883
|
+
# Extract JSON line (filter out any non-JSON noise)
|
|
884
|
+
local json_line
|
|
885
|
+
json_line=$(echo "${adapters_json}" | grep -E '^\{' | tail -1)
|
|
886
|
+
|
|
887
|
+
if [ -z "${json_line}" ]; then
|
|
888
|
+
echo "❌ Failed to query model registry."
|
|
889
|
+
echo " Check that your AWS credentials are configured and the project has registered adapters."
|
|
890
|
+
exit 1
|
|
891
|
+
fi
|
|
892
|
+
|
|
893
|
+
# Parse adapter count
|
|
894
|
+
local adapter_count
|
|
895
|
+
adapter_count=$(echo "${json_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(len(data.get('adapters',[])))" 2>/dev/null || echo "0")
|
|
896
|
+
|
|
897
|
+
if [ "${adapter_count}" -eq 0 ]; then
|
|
898
|
+
echo "❌ No adapters found in the model registry for project: ${PROJECT_NAME}"
|
|
899
|
+
echo ""
|
|
900
|
+
echo " Register an adapter first with: ./do/register (after do/tune)"
|
|
901
|
+
echo " Or use --weights or --from-hub to add an adapter manually."
|
|
902
|
+
exit 1
|
|
903
|
+
fi
|
|
904
|
+
|
|
905
|
+
# Display selection menu
|
|
906
|
+
echo "Available adapters in registry (${adapter_count} found):"
|
|
907
|
+
echo ""
|
|
908
|
+
printf ' %-4s%-10s%-12s%-20s%s\n' "#" "VERSION" "TECHNIQUE" "CREATED" "PARENT MODEL"
|
|
909
|
+
|
|
910
|
+
local i=0
|
|
911
|
+
while [ "${i}" -lt "${adapter_count}" ]; do
|
|
912
|
+
local version technique created_at parent_arn
|
|
913
|
+
version=$(echo "${json_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data['adapters'][${i}].get('version','?'))" 2>/dev/null)
|
|
914
|
+
technique=$(echo "${json_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data['adapters'][${i}].get('tuneTechnique','?'))" 2>/dev/null)
|
|
915
|
+
created_at=$(echo "${json_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); t=data['adapters'][${i}].get('createdAt',''); print(t[:10] if t else '?')" 2>/dev/null)
|
|
916
|
+
parent_arn=$(echo "${json_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); a=data['adapters'][${i}].get('parentModelVersionArn',''); print(a.split('/')[-2]+'/'+a.split('/')[-1] if '/' in a else a[:40])" 2>/dev/null)
|
|
917
|
+
|
|
918
|
+
local num=$((i + 1))
|
|
919
|
+
printf ' %-4s%-10s%-12s%-20s%s\n' "${num}" "v${version}" "${technique}" "${created_at}" "${parent_arn}"
|
|
920
|
+
i=$((i + 1))
|
|
921
|
+
done
|
|
922
|
+
|
|
923
|
+
echo ""
|
|
924
|
+
echo -n "Select adapter (1-${adapter_count}): "
|
|
925
|
+
read -r selection
|
|
926
|
+
|
|
927
|
+
# Validate selection
|
|
928
|
+
if ! echo "${selection}" | grep -qE '^[0-9]+$'; then
|
|
929
|
+
echo "❌ Invalid selection: ${selection}"
|
|
930
|
+
exit 1
|
|
931
|
+
fi
|
|
932
|
+
if [ "${selection}" -lt 1 ] || [ "${selection}" -gt "${adapter_count}" ]; then
|
|
933
|
+
echo "❌ Selection out of range. Choose 1-${adapter_count}."
|
|
934
|
+
exit 1
|
|
935
|
+
fi
|
|
936
|
+
|
|
937
|
+
# Get the ARN of the selected adapter
|
|
938
|
+
local sel_idx=$((selection - 1))
|
|
939
|
+
registry_arn=$(echo "${json_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data['adapters'][${sel_idx}]['arn'])" 2>/dev/null)
|
|
940
|
+
|
|
941
|
+
if [ -z "${registry_arn}" ]; then
|
|
942
|
+
echo "❌ Failed to retrieve ARN for selected adapter."
|
|
943
|
+
exit 1
|
|
944
|
+
fi
|
|
945
|
+
|
|
946
|
+
echo ""
|
|
947
|
+
echo "✅ Selected: ${registry_arn}"
|
|
948
|
+
echo ""
|
|
949
|
+
fi
|
|
950
|
+
|
|
951
|
+
# Direct mode (AC-4.3): use the provided or selected ARN to get version details
|
|
952
|
+
echo "📦 Retrieving adapter details from registry: ${registry_arn}"
|
|
953
|
+
echo ""
|
|
954
|
+
|
|
955
|
+
local version_json
|
|
956
|
+
version_json=$(python3 "${SCRIPT_DIR}/.register_helper.py" get-version \
|
|
957
|
+
--arn "${registry_arn}" \
|
|
958
|
+
--region "${AWS_REGION}" 2>/dev/null)
|
|
959
|
+
|
|
960
|
+
local version_line
|
|
961
|
+
version_line=$(echo "${version_json}" | grep -E '^\{' | tail -1)
|
|
962
|
+
|
|
963
|
+
if [ -z "${version_line}" ]; then
|
|
964
|
+
echo "❌ Failed to get version details for: ${registry_arn}"
|
|
965
|
+
echo ""
|
|
966
|
+
echo " Check that the ARN is correct and you have sagemaker:DescribeModelPackage permission."
|
|
967
|
+
echo " Run ./do/adapter list to see available registry adapters."
|
|
968
|
+
exit 1
|
|
969
|
+
fi
|
|
970
|
+
|
|
971
|
+
# Check for error in response
|
|
972
|
+
local version_error
|
|
973
|
+
version_error=$(echo "${version_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data.get('error',''))" 2>/dev/null || echo "")
|
|
974
|
+
if [ -n "${version_error}" ]; then
|
|
975
|
+
echo "❌ Registry error: ${version_error}"
|
|
976
|
+
exit 1
|
|
977
|
+
fi
|
|
978
|
+
|
|
979
|
+
# Extract model data URL (weights path)
|
|
980
|
+
weights_uri=$(echo "${version_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data.get('modelDataUrl',''))" 2>/dev/null || echo "")
|
|
981
|
+
|
|
982
|
+
if [ -z "${weights_uri}" ]; then
|
|
983
|
+
echo "❌ No model data URL found for registry version: ${registry_arn}"
|
|
984
|
+
echo ""
|
|
985
|
+
echo " The registered adapter does not have a model data URL."
|
|
986
|
+
echo " Use --weights with an explicit S3 URI instead."
|
|
987
|
+
exit 1
|
|
988
|
+
fi
|
|
989
|
+
|
|
990
|
+
echo "✅ Resolved adapter weights from registry: ${weights_uri}"
|
|
991
|
+
echo ""
|
|
680
992
|
fi
|
|
681
993
|
|
|
682
994
|
# ── Validate HF repo ID format (if --from-hub) ───────────────────────
|
|
@@ -705,7 +1017,7 @@ _adapter_add() {
|
|
|
705
1017
|
fi
|
|
706
1018
|
|
|
707
1019
|
# ── Validate S3 URI format (only when --weights is explicitly used) ──
|
|
708
|
-
if [ -n "${weights_uri}" ] && [ -z "${from_hub}" ] && [ -z "${from_tune}" ]; then
|
|
1020
|
+
if [ -n "${weights_uri}" ] && [ -z "${from_hub}" ] && [ -z "${from_tune}" ] && [ -z "${from_registry}" ]; then
|
|
709
1021
|
if ! echo "${weights_uri}" | grep -qE '^s3://.*\.tar\.gz$'; then
|
|
710
1022
|
echo "❌ Invalid S3 URI: ${weights_uri}"
|
|
711
1023
|
echo ""
|
|
@@ -734,6 +1046,9 @@ _adapter_add() {
|
|
|
734
1046
|
elif [ -n "${from_tune}" ]; then
|
|
735
1047
|
echo " Source: do/tune output"
|
|
736
1048
|
echo " Weights: ${weights_uri}"
|
|
1049
|
+
elif [ -n "${from_registry}" ]; then
|
|
1050
|
+
echo " Source: Model Registry (${registry_arn})"
|
|
1051
|
+
echo " Weights: ${weights_uri}"
|
|
737
1052
|
else
|
|
738
1053
|
echo " Weights: ${weights_uri}"
|
|
739
1054
|
fi
|
|
@@ -834,9 +1149,24 @@ EOF
|
|
|
834
1149
|
|
|
835
1150
|
# Add tune-specific metadata if --from-tune was used
|
|
836
1151
|
if [ -n "${from_tune}" ]; then
|
|
1152
|
+
local tune_technique_meta="${from_tune_technique:-latest}"
|
|
1153
|
+
local tune_dataset_meta=""
|
|
1154
|
+
if [ -n "${from_tune_technique}" ] && [[ "${from_tune_technique}" == *-* ]]; then
|
|
1155
|
+
tune_technique_meta="${from_tune_technique%%-*}"
|
|
1156
|
+
tune_dataset_meta="${from_tune_technique#*-}"
|
|
1157
|
+
fi
|
|
837
1158
|
cat >> "${SCRIPT_DIR}/adapters/${adapter_name}.conf" <<EOF
|
|
838
1159
|
export ADAPTER_SOURCE="tune"
|
|
839
|
-
export ADAPTER_TUNE_TECHNIQUE="${
|
|
1160
|
+
export ADAPTER_TUNE_TECHNIQUE="${tune_technique_meta}"
|
|
1161
|
+
export ADAPTER_TUNE_DATASET="${tune_dataset_meta}"
|
|
1162
|
+
EOF
|
|
1163
|
+
fi
|
|
1164
|
+
|
|
1165
|
+
# Add registry-specific metadata if --from-registry was used
|
|
1166
|
+
if [ -n "${from_registry}" ]; then
|
|
1167
|
+
cat >> "${SCRIPT_DIR}/adapters/${adapter_name}.conf" <<EOF
|
|
1168
|
+
export ADAPTER_SOURCE="registry"
|
|
1169
|
+
export ADAPTER_REGISTRY_ARN="${registry_arn}"
|
|
840
1170
|
EOF
|
|
841
1171
|
fi
|
|
842
1172
|
|
|
@@ -851,6 +1181,8 @@ EOF
|
|
|
851
1181
|
echo " Source: HuggingFace Hub (${from_hub})"
|
|
852
1182
|
elif [ -n "${from_tune}" ]; then
|
|
853
1183
|
echo " Source: do/tune (${from_tune_technique:-latest})"
|
|
1184
|
+
elif [ -n "${from_registry}" ]; then
|
|
1185
|
+
echo " Source: Model Registry (${registry_arn})"
|
|
854
1186
|
fi
|
|
855
1187
|
echo " Created: ${created_at}"
|
|
856
1188
|
echo ""
|
|
@@ -945,7 +1277,31 @@ _adapter_list() {
|
|
|
945
1277
|
ownership=" (external)"
|
|
946
1278
|
fi
|
|
947
1279
|
|
|
948
|
-
|
|
1280
|
+
# Check for tuning metadata in conf file
|
|
1281
|
+
local tune_info=""
|
|
1282
|
+
if [ -d "${SCRIPT_DIR}/adapters" ]; then
|
|
1283
|
+
for conf_file in "${SCRIPT_DIR}"/adapters/*.conf; do
|
|
1284
|
+
[ -f "${conf_file}" ] || continue
|
|
1285
|
+
local conf_ic
|
|
1286
|
+
conf_ic=$(grep "^export ADAPTER_IC_NAME=" "${conf_file}" 2>/dev/null | sed 's/^export ADAPTER_IC_NAME="//' | sed 's/"$//' || echo "")
|
|
1287
|
+
if [ "${conf_ic}" = "${ic_name}" ]; then
|
|
1288
|
+
local conf_technique
|
|
1289
|
+
conf_technique=$(grep "^export ADAPTER_TUNE_TECHNIQUE=" "${conf_file}" 2>/dev/null | sed 's/^export ADAPTER_TUNE_TECHNIQUE="//' | sed 's/"$//' || echo "")
|
|
1290
|
+
local conf_dataset
|
|
1291
|
+
conf_dataset=$(grep "^export ADAPTER_TUNE_DATASET=" "${conf_file}" 2>/dev/null | sed 's/^export ADAPTER_TUNE_DATASET="//' | sed 's/"$//' || echo "")
|
|
1292
|
+
if [ -n "${conf_technique}" ]; then
|
|
1293
|
+
if [ -n "${conf_dataset}" ]; then
|
|
1294
|
+
tune_info=" (from tune: ${conf_technique} / ${conf_dataset})"
|
|
1295
|
+
else
|
|
1296
|
+
tune_info=" (from tune: ${conf_technique})"
|
|
1297
|
+
fi
|
|
1298
|
+
fi
|
|
1299
|
+
break
|
|
1300
|
+
fi
|
|
1301
|
+
done
|
|
1302
|
+
fi
|
|
1303
|
+
|
|
1304
|
+
output_lines="${output_lines}$(printf '%-14s%-12s%s%s%s' "${display_name}" "${status}" "${weights_url}" "${ownership}" "${tune_info}")\n"
|
|
949
1305
|
found_adapters=$((found_adapters + 1))
|
|
950
1306
|
done
|
|
951
1307
|
|
|
@@ -953,12 +1309,56 @@ _adapter_list() {
|
|
|
953
1309
|
echo "No adapters found on this endpoint."
|
|
954
1310
|
echo ""
|
|
955
1311
|
echo "Add one with: ./do/adapter add <name> --weights <s3-uri>"
|
|
1312
|
+
fi
|
|
1313
|
+
|
|
1314
|
+
if [ "${found_adapters}" -gt 0 ]; then
|
|
1315
|
+
# ── Print table ───────────────────────────────────────────────────────
|
|
1316
|
+
printf '%-14s%-12s%s\n' "NAME" "STATUS" "WEIGHTS"
|
|
1317
|
+
echo -e "${output_lines}" | sed '$ { /^$/d; }'
|
|
1318
|
+
fi
|
|
1319
|
+
|
|
1320
|
+
# ── Show registry adapters (isAdapter=true) alongside local ones ──────
|
|
1321
|
+
echo ""
|
|
1322
|
+
echo "📦 Registry adapters:"
|
|
1323
|
+
echo ""
|
|
1324
|
+
|
|
1325
|
+
local registry_json
|
|
1326
|
+
registry_json=$(python3 "${SCRIPT_DIR}/.register_helper.py" list-adapters \
|
|
1327
|
+
--project-name "${PROJECT_NAME}" \
|
|
1328
|
+
--region "${AWS_REGION}" 2>/dev/null || echo "")
|
|
1329
|
+
|
|
1330
|
+
local registry_line
|
|
1331
|
+
registry_line=$(echo "${registry_json}" | grep -E '^\{' | tail -1)
|
|
1332
|
+
|
|
1333
|
+
if [ -z "${registry_line}" ]; then
|
|
1334
|
+
echo " (could not query registry — check AWS credentials)"
|
|
956
1335
|
return 0
|
|
957
1336
|
fi
|
|
958
1337
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1338
|
+
local registry_count
|
|
1339
|
+
registry_count=$(echo "${registry_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(len(data.get('adapters',[])))" 2>/dev/null || echo "0")
|
|
1340
|
+
|
|
1341
|
+
if [ "${registry_count}" -eq 0 ]; then
|
|
1342
|
+
echo " (none found)"
|
|
1343
|
+
return 0
|
|
1344
|
+
fi
|
|
1345
|
+
|
|
1346
|
+
printf ' %-10s%-12s%-14s%s\n' "VERSION" "TECHNIQUE" "CREATED" "PARENT MODEL"
|
|
1347
|
+
|
|
1348
|
+
local ri=0
|
|
1349
|
+
while [ "${ri}" -lt "${registry_count}" ]; do
|
|
1350
|
+
local rv rt rc rp
|
|
1351
|
+
rv=$(echo "${registry_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data['adapters'][${ri}].get('version','?'))" 2>/dev/null)
|
|
1352
|
+
rt=$(echo "${registry_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); print(data['adapters'][${ri}].get('tuneTechnique','?'))" 2>/dev/null)
|
|
1353
|
+
rc=$(echo "${registry_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); t=data['adapters'][${ri}].get('createdAt',''); print(t[:10] if t else '?')" 2>/dev/null)
|
|
1354
|
+
rp=$(echo "${registry_line}" | python3 -c "import sys,json; data=json.loads(sys.stdin.read()); a=data['adapters'][${ri}].get('parentModelVersionArn',''); print(a.split('/')[-2]+'/'+a.split('/')[-1] if '/' in a else a[:40])" 2>/dev/null)
|
|
1355
|
+
|
|
1356
|
+
printf ' %-10s%-12s%-14s%s\n' "v${rv}" "${rt}" "${rc}" "${rp}"
|
|
1357
|
+
ri=$((ri + 1))
|
|
1358
|
+
done
|
|
1359
|
+
|
|
1360
|
+
echo ""
|
|
1361
|
+
echo "Add from registry: ./do/adapter add <name> --from-registry [version-arn]"
|
|
962
1362
|
}
|
|
963
1363
|
|
|
964
1364
|
_adapter_remove() {
|