pltr-cli 0.14.1__tar.gz → 0.15.0__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.
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/PKG-INFO +2 -1
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/mypy.ini +4 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/pyproject.toml +2 -1
- pltr_cli-0.15.0/src/pltr/__init__.py +1 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/language_models.py +147 -5
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/ontology.py +106 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/language_models.py +272 -7
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/ontology.py +170 -1
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/sql.py +26 -2
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_language_models.py +176 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_ontology.py +183 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_language_models.py +338 -7
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_ontology.py +195 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_sql.py +33 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/uv.lock +119 -1
- pltr_cli-0.14.1/src/pltr/__init__.py +0 -1
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.github/workflows/ci.yml +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.github/workflows/claude-code-review.yml +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.github/workflows/claude.yml +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.github/workflows/publish.yml +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.github/workflows/test-publish.yml +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.gitignore +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/.pre-commit-config.yaml +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/CHANGELOG.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/CLAUDE.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/LICENSE +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/README.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/RELEASE.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/README.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/SKILL.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/admin-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/aip-agents-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/connectivity-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/dataset-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/filesystem-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/functions-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/language-models-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/mediasets-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/models-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/ontology-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/orchestration-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/quick-start.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/sql-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/reference/streams-commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/workflows/data-analysis.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/workflows/data-pipeline.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/claude_skill/workflows/permission-management.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/README.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/api/wrapper.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/examples/csv-upload.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/examples/gallery.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/features/dataset-transactions.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/migration/v2-pagination.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/pagination.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/aliases.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/authentication.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/claude-skill.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/commands.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/quick-start.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/troubleshooting.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/docs/user-guide/workflows.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/scripts/release.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/__main__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/auth/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/auth/base.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/auth/manager.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/auth/oauth.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/auth/storage.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/auth/token.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/cli.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/admin.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/aip_agents.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/alias.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/audit.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/completion.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/configure.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/connectivity.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/cp.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/data_health.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/dataset.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/folder.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/functions.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/mediasets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/models.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/orchestration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/project.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/resource.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/resource_role.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/shell.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/space.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/sql.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/streams.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/third_party_applications.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/verify.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/commands/widgets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/config/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/config/aliases.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/config/profiles.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/config/settings.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/admin.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/aip_agents.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/audit.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/base.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/connectivity.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/copy.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/data_health.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/dataset.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/folder.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/functions.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/mediasets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/models.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/orchestration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/project.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/resource.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/resource_role.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/space.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/streams.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/third_party_applications.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/services/widgets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/utils/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/utils/alias_resolver.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/utils/completion.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/utils/formatting.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/utils/pagination.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/src/pltr/utils/progress.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/conftest.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/README.md +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/conftest.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/test_auth_flow.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/test_cli_integration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/test_data_workflows.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/test_data_workflows_simple.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/integration/test_simple_integration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_auth/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_auth/test_base.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_auth/test_manager.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_auth/test_oauth.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_auth/test_storage.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_auth/test_token.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_admin.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_aip_agents.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_alias.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_audit.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_completion.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_connectivity.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_data_health.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_dataset.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_folder.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_functions.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_mediasets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_models.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_orchestration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_shell.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_sql.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_streams.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_third_party_applications.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_verify_simple.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_commands/test_widgets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_config/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_config/test_aliases.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_config/test_profiles.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_config/test_settings.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_admin.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_aip_agents.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_base.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_connectivity.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_copy.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_data_health.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_dataset.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_dataset_transactions.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_folder.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_functions.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_mediasets.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_models.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_orchestration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_pagination_integration.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_project.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_resource.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_resource_role.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_space.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_services/test_streams.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_utils/__init__.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_utils/test_alias_resolver.py +0 -0
- {pltr_cli-0.14.1 → pltr_cli-0.15.0}/tests/test_utils/test_pagination.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pltr-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Command-line interface for Palantir Foundry APIs
|
|
5
5
|
Project-URL: Homepage, https://github.com/anjor/pltr-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/anjor/pltr-cli
|
|
@@ -30,6 +30,7 @@ Requires-Dist: click-repl>=0.3.0
|
|
|
30
30
|
Requires-Dist: foundry-platform-sdk<2.0.0,>=1.69.0
|
|
31
31
|
Requires-Dist: keyring>=25.6.0
|
|
32
32
|
Requires-Dist: pandas>=2.0.0
|
|
33
|
+
Requires-Dist: pyarrow>=15.0.0
|
|
33
34
|
Requires-Dist: python-dotenv>=1.1.1
|
|
34
35
|
Requires-Dist: requests>=2.32.4
|
|
35
36
|
Requires-Dist: rich>=14.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pltr-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.15.0"
|
|
4
4
|
description = "Command-line interface for Palantir Foundry APIs"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "anjor", email = "anjor@umd.edu" },
|
|
@@ -12,6 +12,7 @@ dependencies = [
|
|
|
12
12
|
"foundry-platform-sdk>=1.69.0,<2.0.0",
|
|
13
13
|
"keyring>=25.6.0",
|
|
14
14
|
"pandas>=2.0.0",
|
|
15
|
+
"pyarrow>=15.0.0",
|
|
15
16
|
"python-dotenv>=1.1.1",
|
|
16
17
|
"requests>=2.32.4",
|
|
17
18
|
"rich>=14.1.0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.15.0"
|
|
@@ -123,6 +123,148 @@ def display_openai_response(response: dict, format: str, output: Optional[str]):
|
|
|
123
123
|
formatter.display(response, format)
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
# ===== Shared Language Model Commands =====
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@app.command("list")
|
|
130
|
+
def list_models(
|
|
131
|
+
profile: Optional[str] = typer.Option(
|
|
132
|
+
None,
|
|
133
|
+
"--profile",
|
|
134
|
+
"-p",
|
|
135
|
+
help="Profile name",
|
|
136
|
+
autocompletion=complete_profile,
|
|
137
|
+
),
|
|
138
|
+
format: str = typer.Option(
|
|
139
|
+
"table",
|
|
140
|
+
"--format",
|
|
141
|
+
"-f",
|
|
142
|
+
help="Output format (table, json, csv)",
|
|
143
|
+
autocompletion=complete_output_format,
|
|
144
|
+
),
|
|
145
|
+
output: Optional[str] = typer.Option(
|
|
146
|
+
None, "--output", "-o", help="Output file path"
|
|
147
|
+
),
|
|
148
|
+
):
|
|
149
|
+
"""List available language models for the current enrollment."""
|
|
150
|
+
try:
|
|
151
|
+
from ..services.language_models import LanguageModelsService
|
|
152
|
+
|
|
153
|
+
service = LanguageModelsService(profile=profile)
|
|
154
|
+
|
|
155
|
+
with SpinnerProgressTracker().track_spinner("Fetching available models..."):
|
|
156
|
+
models = service.list_available_models()
|
|
157
|
+
|
|
158
|
+
formatter.format_table(
|
|
159
|
+
models,
|
|
160
|
+
columns=["model_rid", "status", "type", "display_name"],
|
|
161
|
+
format=format,
|
|
162
|
+
output=output,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if output:
|
|
166
|
+
formatter.print_success(f"Model list saved to {output}")
|
|
167
|
+
|
|
168
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
169
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
170
|
+
raise typer.Exit(1)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
formatter.print_error(f"Operation failed: {e}")
|
|
173
|
+
raise typer.Exit(1)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@app.command("status")
|
|
177
|
+
def model_status(
|
|
178
|
+
model_id: str = typer.Argument(
|
|
179
|
+
...,
|
|
180
|
+
help="Model Resource Identifier (ri.language-model-service..language-model.<id>)",
|
|
181
|
+
),
|
|
182
|
+
profile: Optional[str] = typer.Option(
|
|
183
|
+
None,
|
|
184
|
+
"--profile",
|
|
185
|
+
"-p",
|
|
186
|
+
help="Profile name",
|
|
187
|
+
autocompletion=complete_profile,
|
|
188
|
+
),
|
|
189
|
+
format: str = typer.Option(
|
|
190
|
+
"table",
|
|
191
|
+
"--format",
|
|
192
|
+
"-f",
|
|
193
|
+
help="Output format (table, json, csv)",
|
|
194
|
+
autocompletion=complete_output_format,
|
|
195
|
+
),
|
|
196
|
+
output: Optional[str] = typer.Option(
|
|
197
|
+
None, "--output", "-o", help="Output file path"
|
|
198
|
+
),
|
|
199
|
+
):
|
|
200
|
+
"""Check enrollment status for a language model via direct API fallback endpoints."""
|
|
201
|
+
try:
|
|
202
|
+
from ..services.language_models import LanguageModelsService
|
|
203
|
+
|
|
204
|
+
service = LanguageModelsService(profile=profile)
|
|
205
|
+
|
|
206
|
+
with SpinnerProgressTracker().track_spinner("Checking model status..."):
|
|
207
|
+
result = service.get_model_enrollment_status(model_id)
|
|
208
|
+
|
|
209
|
+
formatter.format_dict(result, format=format, output=output)
|
|
210
|
+
|
|
211
|
+
if output:
|
|
212
|
+
formatter.print_success(f"Model status saved to {output}")
|
|
213
|
+
|
|
214
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
215
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
216
|
+
raise typer.Exit(1)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
formatter.print_error(f"Operation failed: {e}")
|
|
219
|
+
raise typer.Exit(1)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@app.command("enroll")
|
|
223
|
+
def enroll_model(
|
|
224
|
+
model_id: str = typer.Argument(
|
|
225
|
+
...,
|
|
226
|
+
help="Model Resource Identifier (ri.language-model-service..language-model.<id>)",
|
|
227
|
+
),
|
|
228
|
+
profile: Optional[str] = typer.Option(
|
|
229
|
+
None,
|
|
230
|
+
"--profile",
|
|
231
|
+
"-p",
|
|
232
|
+
help="Profile name",
|
|
233
|
+
autocompletion=complete_profile,
|
|
234
|
+
),
|
|
235
|
+
format: str = typer.Option(
|
|
236
|
+
"table",
|
|
237
|
+
"--format",
|
|
238
|
+
"-f",
|
|
239
|
+
help="Output format (table, json, csv)",
|
|
240
|
+
autocompletion=complete_output_format,
|
|
241
|
+
),
|
|
242
|
+
output: Optional[str] = typer.Option(
|
|
243
|
+
None, "--output", "-o", help="Output file path"
|
|
244
|
+
),
|
|
245
|
+
):
|
|
246
|
+
"""Enroll/enable a language model via direct API fallback endpoints."""
|
|
247
|
+
try:
|
|
248
|
+
from ..services.language_models import LanguageModelsService
|
|
249
|
+
|
|
250
|
+
service = LanguageModelsService(profile=profile)
|
|
251
|
+
|
|
252
|
+
with SpinnerProgressTracker().track_spinner("Enrolling model..."):
|
|
253
|
+
result = service.enroll_model(model_id)
|
|
254
|
+
|
|
255
|
+
formatter.format_dict(result, format=format, output=output)
|
|
256
|
+
|
|
257
|
+
if output:
|
|
258
|
+
formatter.print_success(f"Enrollment result saved to {output}")
|
|
259
|
+
|
|
260
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
261
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
262
|
+
raise typer.Exit(1)
|
|
263
|
+
except Exception as e:
|
|
264
|
+
formatter.print_error(f"Operation failed: {e}")
|
|
265
|
+
raise typer.Exit(1)
|
|
266
|
+
|
|
267
|
+
|
|
126
268
|
# ===== Anthropic Commands =====
|
|
127
269
|
|
|
128
270
|
|
|
@@ -323,9 +465,9 @@ def anthropic_messages_advanced(
|
|
|
323
465
|
# conversation.json:
|
|
324
466
|
# {
|
|
325
467
|
# "messages": [
|
|
326
|
-
# {"role": "
|
|
327
|
-
# {"role": "
|
|
328
|
-
# {"role": "
|
|
468
|
+
# {"role": "USER", "content": [{"type": "text", "text": "Hi"}]},
|
|
469
|
+
# {"role": "ASSISTANT", "content": [{"type": "text", "text": "Hello!"}]},
|
|
470
|
+
# {"role": "USER", "content": [{"type": "text", "text": "Help me"}]}
|
|
329
471
|
# ],
|
|
330
472
|
# "maxTokens": 500
|
|
331
473
|
# }
|
|
@@ -334,11 +476,11 @@ def anthropic_messages_advanced(
|
|
|
334
476
|
|
|
335
477
|
# Inline JSON with system prompt
|
|
336
478
|
pltr language-models anthropic messages-advanced ri.language-models.main.model.abc123 \\
|
|
337
|
-
--request '{"messages": [{"role": "
|
|
479
|
+
--request '{"messages": [{"role": "USER", "content": [{"type": "text", "text": "Hi"}]}], "maxTokens": 100, "system": [{"type": "text", "text": "Be concise"}]}'
|
|
338
480
|
|
|
339
481
|
# With extended thinking
|
|
340
482
|
pltr language-models anthropic messages-advanced ri.language-models.main.model.abc123 \\
|
|
341
|
-
--request '{"messages": [{"role": "
|
|
483
|
+
--request '{"messages": [{"role": "USER", "content": [{"type": "text", "text": "Solve this problem"}]}], "maxTokens": 2000, "thinking": {"type": "enabled", "budget": 10000}}'
|
|
342
484
|
"""
|
|
343
485
|
try:
|
|
344
486
|
# Parse request JSON
|
|
@@ -164,6 +164,112 @@ def get_object_type(
|
|
|
164
164
|
raise typer.Exit(1)
|
|
165
165
|
|
|
166
166
|
|
|
167
|
+
@app.command("object-type-create")
|
|
168
|
+
def create_object_type(
|
|
169
|
+
ontology_rid: str = typer.Argument(..., help="Ontology Resource Identifier"),
|
|
170
|
+
api_name: str = typer.Option(..., "--api-name", help="Object type API name"),
|
|
171
|
+
display_name: str = typer.Option(
|
|
172
|
+
..., "--display-name", help="Object type display name"
|
|
173
|
+
),
|
|
174
|
+
primary_key: str = typer.Option(
|
|
175
|
+
..., "--primary-key", help="Primary key property API name"
|
|
176
|
+
),
|
|
177
|
+
backing_dataset: str = typer.Option(
|
|
178
|
+
..., "--backing-dataset", help="Backing dataset RID"
|
|
179
|
+
),
|
|
180
|
+
description: Optional[str] = typer.Option(
|
|
181
|
+
None, "--description", help="Object type description"
|
|
182
|
+
),
|
|
183
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
184
|
+
format: str = typer.Option(
|
|
185
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
186
|
+
),
|
|
187
|
+
output: Optional[str] = typer.Option(
|
|
188
|
+
None, "--output", "-o", help="Output file path"
|
|
189
|
+
),
|
|
190
|
+
):
|
|
191
|
+
"""Create a new object type in an ontology."""
|
|
192
|
+
try:
|
|
193
|
+
service = ObjectTypeService(profile=profile)
|
|
194
|
+
|
|
195
|
+
with SpinnerProgressTracker().track_spinner(
|
|
196
|
+
f"Creating object type {api_name}..."
|
|
197
|
+
):
|
|
198
|
+
result = service.create_object_type(
|
|
199
|
+
ontology_rid=ontology_rid,
|
|
200
|
+
api_name=api_name,
|
|
201
|
+
display_name=display_name,
|
|
202
|
+
primary_key=primary_key,
|
|
203
|
+
backing_dataset=backing_dataset,
|
|
204
|
+
description=description,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
formatter.format_dict(result, format=format, output=output)
|
|
208
|
+
|
|
209
|
+
if output:
|
|
210
|
+
formatter.print_success(f"Object type creation result saved to {output}")
|
|
211
|
+
|
|
212
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
213
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
214
|
+
raise typer.Exit(1)
|
|
215
|
+
except Exception as e:
|
|
216
|
+
formatter.print_error(f"Failed to create object type: {e}")
|
|
217
|
+
raise typer.Exit(1)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@app.command("link-type-create")
|
|
221
|
+
def create_link_type(
|
|
222
|
+
ontology_rid: str = typer.Argument(..., help="Ontology Resource Identifier"),
|
|
223
|
+
api_name: str = typer.Option(..., "--api-name", help="Link type API name"),
|
|
224
|
+
from_object: str = typer.Option(..., "--from", help="Source object type API name"),
|
|
225
|
+
to_object: str = typer.Option(..., "--to", help="Target object type API name"),
|
|
226
|
+
display_name: Optional[str] = typer.Option(
|
|
227
|
+
None, "--display-name", help="Link type display name"
|
|
228
|
+
),
|
|
229
|
+
description: Optional[str] = typer.Option(
|
|
230
|
+
None, "--description", help="Link type description"
|
|
231
|
+
),
|
|
232
|
+
reverse_api_name: Optional[str] = typer.Option(
|
|
233
|
+
None, "--reverse-api-name", help="Reverse direction link type API name"
|
|
234
|
+
),
|
|
235
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
236
|
+
format: str = typer.Option(
|
|
237
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
238
|
+
),
|
|
239
|
+
output: Optional[str] = typer.Option(
|
|
240
|
+
None, "--output", "-o", help="Output file path"
|
|
241
|
+
),
|
|
242
|
+
):
|
|
243
|
+
"""Create a new link type in an ontology."""
|
|
244
|
+
try:
|
|
245
|
+
service = ObjectTypeService(profile=profile)
|
|
246
|
+
|
|
247
|
+
with SpinnerProgressTracker().track_spinner(
|
|
248
|
+
f"Creating link type {api_name}..."
|
|
249
|
+
):
|
|
250
|
+
result = service.create_link_type(
|
|
251
|
+
ontology_rid=ontology_rid,
|
|
252
|
+
api_name=api_name,
|
|
253
|
+
from_object_type=from_object,
|
|
254
|
+
to_object_type=to_object,
|
|
255
|
+
display_name=display_name,
|
|
256
|
+
description=description,
|
|
257
|
+
reverse_api_name=reverse_api_name,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
formatter.format_dict(result, format=format, output=output)
|
|
261
|
+
|
|
262
|
+
if output:
|
|
263
|
+
formatter.print_success(f"Link type creation result saved to {output}")
|
|
264
|
+
|
|
265
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
266
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
267
|
+
raise typer.Exit(1)
|
|
268
|
+
except Exception as e:
|
|
269
|
+
formatter.print_error(f"Failed to create link type: {e}")
|
|
270
|
+
raise typer.Exit(1)
|
|
271
|
+
|
|
272
|
+
|
|
167
273
|
# Object operations
|
|
168
274
|
@app.command("object-list")
|
|
169
275
|
def list_objects(
|
|
@@ -3,13 +3,29 @@ LanguageModels service wrapper for Foundry SDK.
|
|
|
3
3
|
Provides access to Anthropic Claude models and OpenAI embeddings.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from typing import Any, Dict, List, Optional
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
import json
|
|
8
|
+
import requests
|
|
9
|
+
from urllib.parse import quote
|
|
7
10
|
from .base import BaseService
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class LanguageModelsService(BaseService):
|
|
11
14
|
"""Service wrapper for Foundry LanguageModels operations."""
|
|
12
15
|
|
|
16
|
+
_MODEL_LIST_ENDPOINTS = [
|
|
17
|
+
"/v2/languageModels",
|
|
18
|
+
"/api/v2/llm/proxy/openai/v1/models",
|
|
19
|
+
]
|
|
20
|
+
_MODEL_STATUS_ENDPOINTS = [
|
|
21
|
+
"/v2/languageModels/{model_id}",
|
|
22
|
+
"/api/v2/llm/models/{model_id}",
|
|
23
|
+
]
|
|
24
|
+
_MODEL_ENROLL_ENDPOINTS = [
|
|
25
|
+
"/v2/languageModels/{model_id}/enroll",
|
|
26
|
+
"/api/v2/llm/models/{model_id}/enroll",
|
|
27
|
+
]
|
|
28
|
+
|
|
13
29
|
def _get_service(self) -> Any:
|
|
14
30
|
"""Get the Foundry LanguageModels service."""
|
|
15
31
|
return self.client.language_models
|
|
@@ -71,7 +87,7 @@ class LanguageModelsService(BaseService):
|
|
|
71
87
|
# Transform simple message to SDK message format
|
|
72
88
|
messages = [
|
|
73
89
|
{
|
|
74
|
-
"role": "
|
|
90
|
+
"role": "USER",
|
|
75
91
|
"content": [{"type": "text", "text": message}],
|
|
76
92
|
}
|
|
77
93
|
]
|
|
@@ -134,7 +150,7 @@ class LanguageModelsService(BaseService):
|
|
|
134
150
|
model_id: Model Resource Identifier
|
|
135
151
|
Format: ri.language-models.main.model.<id>
|
|
136
152
|
messages: List of message objects with role and content
|
|
137
|
-
Format: [{"role": "
|
|
153
|
+
Format: [{"role": "USER|ASSISTANT", "content": [...]}]
|
|
138
154
|
max_tokens: Maximum tokens to generate
|
|
139
155
|
system: Optional system prompt blocks
|
|
140
156
|
Format: [{"type": "text", "text": "..."}]
|
|
@@ -162,9 +178,9 @@ class LanguageModelsService(BaseService):
|
|
|
162
178
|
Example:
|
|
163
179
|
>>> service = LanguageModelsService()
|
|
164
180
|
>>> messages = [
|
|
165
|
-
... {"role": "
|
|
166
|
-
... {"role": "
|
|
167
|
-
... {"role": "
|
|
181
|
+
... {"role": "USER", "content": [{"type": "text", "text": "Hi"}]},
|
|
182
|
+
... {"role": "ASSISTANT", "content": [{"type": "text", "text": "Hello!"}]},
|
|
183
|
+
... {"role": "USER", "content": [{"type": "text", "text": "Help me"}]}
|
|
168
184
|
... ]
|
|
169
185
|
>>> response = service.send_messages_advanced(
|
|
170
186
|
... "ri.language-models.main.model.abc123",
|
|
@@ -173,9 +189,17 @@ class LanguageModelsService(BaseService):
|
|
|
173
189
|
... )
|
|
174
190
|
"""
|
|
175
191
|
try:
|
|
192
|
+
normalized_messages: List[Dict[str, Any]] = []
|
|
193
|
+
for msg in messages:
|
|
194
|
+
normalized_msg = dict(msg)
|
|
195
|
+
role = normalized_msg.get("role")
|
|
196
|
+
if isinstance(role, str):
|
|
197
|
+
normalized_msg["role"] = role.upper()
|
|
198
|
+
normalized_messages.append(normalized_msg)
|
|
199
|
+
|
|
176
200
|
# Build SDK kwargs
|
|
177
201
|
request_kwargs: Dict[str, Any] = {
|
|
178
|
-
"messages":
|
|
202
|
+
"messages": normalized_messages,
|
|
179
203
|
"max_tokens": max_tokens,
|
|
180
204
|
"preview": preview,
|
|
181
205
|
}
|
|
@@ -280,3 +304,244 @@ class LanguageModelsService(BaseService):
|
|
|
280
304
|
raise RuntimeError(
|
|
281
305
|
f"Failed to generate embeddings with model {model_id}: {e}"
|
|
282
306
|
)
|
|
307
|
+
|
|
308
|
+
def list_available_models(self) -> List[Dict[str, Any]]:
|
|
309
|
+
"""
|
|
310
|
+
List language models available to the authenticated user.
|
|
311
|
+
|
|
312
|
+
Tries the platform language-model listing endpoint first, then falls back
|
|
313
|
+
to the provider-compatible OpenAI models endpoint.
|
|
314
|
+
Note: This currently reads a single response per endpoint and does not
|
|
315
|
+
follow pagination tokens.
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
List of model dictionaries with normalized keys:
|
|
319
|
+
- model_rid
|
|
320
|
+
- status
|
|
321
|
+
- type
|
|
322
|
+
- display_name
|
|
323
|
+
|
|
324
|
+
Raises:
|
|
325
|
+
RuntimeError: If no listing endpoint succeeds
|
|
326
|
+
"""
|
|
327
|
+
last_error: Optional[Exception] = None
|
|
328
|
+
|
|
329
|
+
for endpoint in self._MODEL_LIST_ENDPOINTS:
|
|
330
|
+
try:
|
|
331
|
+
response = self._make_request("GET", endpoint)
|
|
332
|
+
except (requests.RequestException, RuntimeError) as e:
|
|
333
|
+
last_error = e
|
|
334
|
+
continue
|
|
335
|
+
|
|
336
|
+
payload = response.json() if response.text else {}
|
|
337
|
+
return self._normalize_model_list(
|
|
338
|
+
payload,
|
|
339
|
+
is_openai_source=("openai/v1/models" in endpoint),
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
raise RuntimeError(f"Failed to list available language models: {last_error}")
|
|
343
|
+
|
|
344
|
+
def _normalize_model_list(
|
|
345
|
+
self, payload: Union[Dict[str, Any], List[Any]], is_openai_source: bool = False
|
|
346
|
+
) -> List[Dict[str, Any]]:
|
|
347
|
+
"""Normalize varied model list payloads into a stable CLI schema."""
|
|
348
|
+
raw_models: List[Any] = []
|
|
349
|
+
if isinstance(payload, dict):
|
|
350
|
+
if "data" in payload:
|
|
351
|
+
data = payload.get("data")
|
|
352
|
+
if isinstance(data, list):
|
|
353
|
+
raw_models = data
|
|
354
|
+
elif "models" in payload:
|
|
355
|
+
models = payload.get("models")
|
|
356
|
+
if isinstance(models, list):
|
|
357
|
+
raw_models = models
|
|
358
|
+
elif isinstance(payload, list):
|
|
359
|
+
raw_models = payload
|
|
360
|
+
|
|
361
|
+
normalized: List[Dict[str, Any]] = []
|
|
362
|
+
for model in raw_models:
|
|
363
|
+
if not isinstance(model, dict):
|
|
364
|
+
continue
|
|
365
|
+
|
|
366
|
+
model_id = (
|
|
367
|
+
model.get("rid")
|
|
368
|
+
or model.get("modelRid")
|
|
369
|
+
or model.get("id")
|
|
370
|
+
or model.get("apiName")
|
|
371
|
+
or model.get("name")
|
|
372
|
+
)
|
|
373
|
+
if not model_id:
|
|
374
|
+
continue
|
|
375
|
+
|
|
376
|
+
status = (
|
|
377
|
+
model.get("status")
|
|
378
|
+
or model.get("enrollmentStatus")
|
|
379
|
+
or ("AVAILABLE" if is_openai_source else "UNKNOWN")
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
model_type = (
|
|
383
|
+
model.get("type")
|
|
384
|
+
or model.get("provider")
|
|
385
|
+
or model.get("modelType")
|
|
386
|
+
or model.get("family")
|
|
387
|
+
or ("OPENAI" if is_openai_source else "UNKNOWN")
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
normalized.append(
|
|
391
|
+
{
|
|
392
|
+
"model_rid": str(model_id),
|
|
393
|
+
"status": str(status),
|
|
394
|
+
"type": str(model_type),
|
|
395
|
+
"display_name": (
|
|
396
|
+
model.get("displayName")
|
|
397
|
+
or model.get("name")
|
|
398
|
+
or model.get("id")
|
|
399
|
+
or str(model_id)
|
|
400
|
+
),
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
normalized.sort(key=lambda item: item["model_rid"])
|
|
405
|
+
return normalized
|
|
406
|
+
|
|
407
|
+
def get_model_enrollment_status(self, model_id: str) -> Dict[str, Any]:
|
|
408
|
+
"""
|
|
409
|
+
Get enrollment status for a language model.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
model_id: Model RID or API name
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
Dictionary with normalized keys:
|
|
416
|
+
- model_rid
|
|
417
|
+
- status
|
|
418
|
+
- type
|
|
419
|
+
- display_name
|
|
420
|
+
"""
|
|
421
|
+
encoded_model_id = quote(model_id, safe="")
|
|
422
|
+
last_error: Optional[Exception] = None
|
|
423
|
+
|
|
424
|
+
for endpoint_template in self._MODEL_STATUS_ENDPOINTS:
|
|
425
|
+
endpoint = endpoint_template.format(model_id=encoded_model_id)
|
|
426
|
+
try:
|
|
427
|
+
response = self._make_request("GET", endpoint)
|
|
428
|
+
payload = response.json() if response.text else {}
|
|
429
|
+
return self._normalize_single_model_status(model_id, payload)
|
|
430
|
+
except (
|
|
431
|
+
requests.RequestException,
|
|
432
|
+
RuntimeError,
|
|
433
|
+
json.JSONDecodeError,
|
|
434
|
+
) as e:
|
|
435
|
+
last_error = e
|
|
436
|
+
continue
|
|
437
|
+
|
|
438
|
+
# Fallback: infer availability from provider-compatible OpenAI models list.
|
|
439
|
+
try:
|
|
440
|
+
response = self._make_request("GET", "/api/v2/llm/proxy/openai/v1/models")
|
|
441
|
+
payload = response.json() if response.text else {}
|
|
442
|
+
except (
|
|
443
|
+
requests.RequestException,
|
|
444
|
+
RuntimeError,
|
|
445
|
+
json.JSONDecodeError,
|
|
446
|
+
) as fallback_error:
|
|
447
|
+
raise RuntimeError(
|
|
448
|
+
f"Failed to get model enrollment status for {model_id}. "
|
|
449
|
+
f"Primary endpoint error: {last_error}. "
|
|
450
|
+
f"Fallback endpoint error: {fallback_error}"
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
for item in payload.get("data", []) if isinstance(payload, dict) else []:
|
|
454
|
+
if isinstance(item, dict) and item.get("id") == model_id:
|
|
455
|
+
return self._normalize_single_model_status(
|
|
456
|
+
model_id,
|
|
457
|
+
item,
|
|
458
|
+
default_status="AVAILABLE_VIA_PROXY",
|
|
459
|
+
default_type="OPENAI",
|
|
460
|
+
default_display_name=model_id,
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
raise RuntimeError(
|
|
464
|
+
f"Model '{model_id}' not found via any known endpoint. "
|
|
465
|
+
f"Last primary endpoint error: {last_error}"
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
def enroll_model(self, model_id: str) -> Dict[str, Any]:
|
|
469
|
+
"""
|
|
470
|
+
Enroll or enable a language model for API usage.
|
|
471
|
+
|
|
472
|
+
Args:
|
|
473
|
+
model_id: Model RID or API name
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
Enrollment result dictionary with normalized keys:
|
|
477
|
+
- model_rid
|
|
478
|
+
- status
|
|
479
|
+
- type
|
|
480
|
+
- display_name
|
|
481
|
+
"""
|
|
482
|
+
encoded_model_id = quote(model_id, safe="")
|
|
483
|
+
last_error: Optional[Exception] = None
|
|
484
|
+
|
|
485
|
+
for endpoint_template in self._MODEL_ENROLL_ENDPOINTS:
|
|
486
|
+
endpoint = endpoint_template.format(model_id=encoded_model_id)
|
|
487
|
+
try:
|
|
488
|
+
response = self._make_request("POST", endpoint, json_data={})
|
|
489
|
+
payload = response.json() if response.text else {}
|
|
490
|
+
return self._normalize_single_model_status(
|
|
491
|
+
model_id, payload, default_status="ENROLLED"
|
|
492
|
+
)
|
|
493
|
+
except (
|
|
494
|
+
requests.RequestException,
|
|
495
|
+
RuntimeError,
|
|
496
|
+
json.JSONDecodeError,
|
|
497
|
+
) as e:
|
|
498
|
+
last_error = e
|
|
499
|
+
continue
|
|
500
|
+
|
|
501
|
+
raise RuntimeError(
|
|
502
|
+
f"Failed to enroll model {model_id}. "
|
|
503
|
+
f"Enrollment may require Model Catalog UI access for this model: {last_error}"
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
def _normalize_single_model_status(
|
|
507
|
+
self,
|
|
508
|
+
model_id: str,
|
|
509
|
+
payload: Dict[str, Any],
|
|
510
|
+
default_status: str = "UNKNOWN",
|
|
511
|
+
default_type: str = "UNKNOWN",
|
|
512
|
+
default_display_name: Optional[str] = None,
|
|
513
|
+
) -> Dict[str, Any]:
|
|
514
|
+
"""Normalize status payloads from varying endpoints."""
|
|
515
|
+
model_data = payload.get("data") if isinstance(payload, dict) else None
|
|
516
|
+
if isinstance(model_data, dict):
|
|
517
|
+
payload = model_data
|
|
518
|
+
|
|
519
|
+
if not isinstance(payload, dict):
|
|
520
|
+
payload = {}
|
|
521
|
+
|
|
522
|
+
return {
|
|
523
|
+
"model_rid": str(
|
|
524
|
+
payload.get("rid")
|
|
525
|
+
or payload.get("modelRid")
|
|
526
|
+
or payload.get("id")
|
|
527
|
+
or model_id
|
|
528
|
+
),
|
|
529
|
+
"status": str(
|
|
530
|
+
payload.get("status")
|
|
531
|
+
or payload.get("enrollmentStatus")
|
|
532
|
+
or default_status
|
|
533
|
+
),
|
|
534
|
+
"type": str(
|
|
535
|
+
payload.get("type")
|
|
536
|
+
or payload.get("provider")
|
|
537
|
+
or payload.get("modelType")
|
|
538
|
+
or default_type
|
|
539
|
+
),
|
|
540
|
+
"display_name": str(
|
|
541
|
+
payload.get("displayName")
|
|
542
|
+
or payload.get("name")
|
|
543
|
+
or payload.get("id")
|
|
544
|
+
or default_display_name
|
|
545
|
+
or model_id
|
|
546
|
+
),
|
|
547
|
+
}
|