imperal-sdk 5.4.2__tar.gz → 5.4.3__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.
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/CHANGELOG.md +24 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/PKG-INFO +1 -1
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/sdk_claims.json +1 -1
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/__init__.py +1 -1
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/extension.py +4 -1
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/cli/main.py +13 -8
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/secrets/panel_handler.py +1 -1
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/testing/mock_context.py +11 -7
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/models.py +6 -4
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/validator.py +9 -3
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_cli.py +3 -2
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_data_model_kwarg.py +41 -2
- imperal_sdk-5.4.3/tests/test_http_json_and_mock.py +37 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/.github/workflows/identity-contract.yml +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/.github/workflows/publish.yml +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/.github/workflows/test.yml +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/.gitignore +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/LICENSE +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/README.md +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/api_surface.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/docs/sdl-facets.md +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/pyproject.toml +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/sdl_roles.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/.codebase-index-cache.pkl +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ai/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ai/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/auth/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/auth/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/auth/middleware.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/billing/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/billing/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/cache/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/cache/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/cache/protocol.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/action_result.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/error_codes.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/exceptions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/filters.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/guards.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/kernel_primitives.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/narration.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/narration_guard.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/prompt.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/chat/refusal.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/cli/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/config/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/config/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/context.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/devtools/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/devtools/contract_checks.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/devtools/generate_api_surface.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/devtools/generate_sdk_claims.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/devtools/validate_identity_contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/errors.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/extension.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/extensions/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/extensions/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/http/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/http/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/manifest.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/manifest_schema.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/notify/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/notify/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/prompts/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/prompts/icnli_integrity_rules.txt +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/prompts/kernel_formatting_rule.txt +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/prompts/kernel_proactivity_rule.txt +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/protocols.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/rpc/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/rpc/codec.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/rpc/contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/runtime/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/runtime/executor.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/runtime/llm_provider.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/runtime/message_adapter.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/action_result.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/balance_info.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/chat_result.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/completion_result.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/document.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/event.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/file_info.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/function_call.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/http_response.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/imperal.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/limits_result.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/subscription_info.schema.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/_generate_roles_json.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/entity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/catalog.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/comm.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/content.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/device.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/event.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/geo.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/identity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/media.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/metric.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/money.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/net.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/people.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/quantity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/rating.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/security.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/task.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/facets/time.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/field.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/sdl/roles.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/secrets/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/secrets/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/secrets/exceptions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/secrets/spec.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/security/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/security/call_token.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/skeleton/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/skeleton/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/storage/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/storage/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/store/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/store/client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/store/exceptions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/testing/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/testing/mock_secrets.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/action_result.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/chat_result.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/client_contracts.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/contracts.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/contributions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/events.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/health.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/identity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/pagination.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/types/store_contracts.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/actions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/base.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/data.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/display.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/feedback.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/graph.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/input_components.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/interactive.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/layout.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/ui/theme.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/validator_v1_6_0.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/conftest.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contract/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contract/test_artifacts_freshness.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contract/test_contract_checks_selftest.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contract/test_generate_sdk_claims.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contract/test_sample_contract_shape.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contract/test_sdk_matches_kernel_contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contracts/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/contracts/test_store_contracts.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/fixtures/contract/kernel-contract.sample.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/fixtures/openapi/auth-gateway.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/fixtures/openapi/registry.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/fixtures/openapi/sharelock-cases.json +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/rpc/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/rpc/test_codec.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/rpc/test_contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/runtime/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/runtime/test_llm_provider_config_store.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/runtime/test_llm_provider_ctx_injection.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/store/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/store/test_list_users_client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/store/test_query_all_client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_action_result_typed.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_as_user.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_auth.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_billing.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_cache_client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_cache_model.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_call_token.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_extension_deprecation.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_extension_no_llm_router.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_filters.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_function_background_flag.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_guards.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_guards_bleed.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_prompt.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_chat_result.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_client_contracts.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_config_client.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_context.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_context_background_task.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_context_deliver_chat_message.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_context_guards.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_contracts.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_contracts_live.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_contributions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_document_contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_emits_decorator.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_error_codes.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_errors.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_event_schema_v2.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_events_health.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_extension.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_extension_v2.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_extensions_emit.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_http_timeout_override.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_id_shape_guard.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_identity_contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_imperal_schema_v2.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_import_light.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_kernel_primitives.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_no_orchestrator_tool.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_roundtrip_gate.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_schema.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_v2_events.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_v2_other_sections.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_v2_webhooks.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_manifest_validator_v2.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_mock_context.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_models.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_narration_emission.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_narration_guard.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_openai_max_completion_tokens.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_pagination.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_panel_rendering_contract.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_panels.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_phase_a_dead_removal.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_phase_a_drift.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_phase_a_text.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdk_version_stamp.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_entity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_entity_marker.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_exports.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_catalog.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_collisions.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_comm.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_content.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_device.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_event.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_exports.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_field.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_geo.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_identity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_media.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_metric.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_money.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_net.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_people.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_quantity.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_rating.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_security.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_task.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facet_time.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facets_catalog.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facets_doc.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_facets_pkg.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_field.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_roles.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_roles_json.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_sdl_roles_of_facets.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_skeleton_decorator.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_spec_validation.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_ui.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_ui_fileupload_enhanced.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_ui_html.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_ui_image_enhanced.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_ui_open.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_ui_theme.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_user.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_v7_emit_refusal.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_validator.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_validator_drift.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_validator_pep563.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_validator_v1_6_0_rules.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_validator_v25.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/test_write_arg_bleed.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/tools/__init__.py +0 -0
- {imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/tests/tools/test_generate_api_surface.py +0 -0
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `imperal-sdk` are documented here.
|
|
4
4
|
|
|
5
|
+
## 5.4.3 — 2026-06-18 — Fix secrets-panel render crash
|
|
6
|
+
|
|
7
|
+
Bugfix — **nothing to migrate**.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Auto-generated `__panel__secrets` panel (created for any extension declaring
|
|
11
|
+
`@ext.secret`) called `ui.Heading(...)`, which does not exist — the display
|
|
12
|
+
element is exported as `ui.Header`. Every secrets-panel render raised
|
|
13
|
+
`AttributeError: module 'imperal_sdk.ui' has no attribute 'Heading'`. Switched
|
|
14
|
+
to `ui.Header`. No public API change.
|
|
15
|
+
|
|
16
|
+
## 5.4.2 — 2026-06-16 — BillingClient renew_subscription
|
|
17
|
+
|
|
18
|
+
Additive — **nothing to migrate**.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- `ctx.billing.renew_subscription()` — renews an **expired** subscription for
|
|
22
|
+
the same plan: charges the saved default card for one fresh period and
|
|
23
|
+
restores access immediately (POST `/v1/billing/renew`). Surfaces errors
|
|
24
|
+
(`402` no card / SCA required, `409` not expired). Returns the gateway result
|
|
25
|
+
dict (`{status, plan, expires_at, payment_intent_id}`).
|
|
26
|
+
|
|
27
|
+
`BillingProtocol` 18 → 19 methods.
|
|
28
|
+
|
|
5
29
|
## 5.4.1 — 2026-06-16 — BillingClient resume + cancel_at_period_end
|
|
6
30
|
|
|
7
31
|
Additive — **nothing to migrate**.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Imperal Cloud SDK — build extensions for the Imperal platform."""
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
|
|
4
|
-
__version__ = "5.4.
|
|
4
|
+
__version__ = "5.4.3"
|
|
5
5
|
|
|
6
6
|
# 5.2.2 (2026-06-11): the package root resolves its public surface lazily
|
|
7
7
|
# (PEP 562). The eager imports pulled the HTTP transport (Context / client
|
|
@@ -61,6 +61,7 @@ class FunctionDef:
|
|
|
61
61
|
_pydantic_model: type | None = None # auto-detected Pydantic BaseModel class
|
|
62
62
|
_pydantic_param: str = "" # parameter name that receives the model instance
|
|
63
63
|
_return_model: type | None = None # data_model kwarg OR autodetected return Pydantic model
|
|
64
|
+
_ui_builder: bool = False # @chat.function(ui_builder=True): Declarative-UI builder; exempt from the V23 data_model rule
|
|
64
65
|
|
|
65
66
|
|
|
66
67
|
class ChatExtension:
|
|
@@ -117,7 +118,8 @@ class ChatExtension:
|
|
|
117
118
|
id_projection: str | None = None,
|
|
118
119
|
background: bool = False,
|
|
119
120
|
long_running: bool = False,
|
|
120
|
-
data_model: type | None = None
|
|
121
|
+
data_model: type | None = None,
|
|
122
|
+
ui_builder: bool = False):
|
|
121
123
|
"""Register a chat function.
|
|
122
124
|
|
|
123
125
|
Args:
|
|
@@ -266,6 +268,7 @@ class ChatExtension:
|
|
|
266
268
|
long_running=long_running,
|
|
267
269
|
_pydantic_model=_detected_model, _pydantic_param=_detected_param,
|
|
268
270
|
_return_model=_detected_return_model,
|
|
271
|
+
_ui_builder=ui_builder,
|
|
269
272
|
)
|
|
270
273
|
return func
|
|
271
274
|
return decorator
|
|
@@ -9,6 +9,11 @@ import configparser
|
|
|
9
9
|
import click
|
|
10
10
|
import httpx
|
|
11
11
|
|
|
12
|
+
try:
|
|
13
|
+
from imperal_sdk import __version__ as SDK_VERSION
|
|
14
|
+
except Exception: # pragma: no cover - defensive
|
|
15
|
+
SDK_VERSION = "5.x"
|
|
16
|
+
|
|
12
17
|
|
|
13
18
|
def _load_credentials() -> dict:
|
|
14
19
|
"""Load credentials from .imperal/credentials or environment variables."""
|
|
@@ -57,7 +62,7 @@ def _validate_manifest(manifest: dict) -> list[str]:
|
|
|
57
62
|
|
|
58
63
|
|
|
59
64
|
@click.group()
|
|
60
|
-
@click.version_option(version=
|
|
65
|
+
@click.version_option(version=SDK_VERSION)
|
|
61
66
|
def cli():
|
|
62
67
|
"""Imperal Cloud SDK — build extensions for the Imperal platform."""
|
|
63
68
|
pass
|
|
@@ -67,7 +72,7 @@ def cli():
|
|
|
67
72
|
@click.argument("name")
|
|
68
73
|
@click.option("--template", type=click.Choice(["chat", "tool"]), default="chat", help="Extension template")
|
|
69
74
|
def init(name: str, template: str):
|
|
70
|
-
"""Scaffold a new extension project (federal
|
|
75
|
+
"""Scaffold a new extension project (federal v5 contract)."""
|
|
71
76
|
os.makedirs(name, exist_ok=True)
|
|
72
77
|
os.makedirs(f"{name}/tests", exist_ok=True)
|
|
73
78
|
|
|
@@ -88,7 +93,7 @@ from pydantic import BaseModel, Field
|
|
|
88
93
|
from imperal_sdk import Extension, ChatExtension, ActionResult
|
|
89
94
|
|
|
90
95
|
|
|
91
|
-
# Federal
|
|
96
|
+
# Federal v5 Extension surface — V14 (description ≥40 chars), V15
|
|
92
97
|
# (display_name ≥3 chars, ≠ app_id), V19 (actions_explicit=True), and
|
|
93
98
|
# V21 (icon.svg required, XML <svg> root + viewBox) are all satisfied
|
|
94
99
|
# by these defaults. Edit display_name + description before publish.
|
|
@@ -165,7 +170,7 @@ async def fn_default(ctx, **kwargs):
|
|
|
165
170
|
)
|
|
166
171
|
|
|
167
172
|
with open(f"{name}/requirements.txt", "w") as f:
|
|
168
|
-
f.write("imperal-sdk>=
|
|
173
|
+
f.write("imperal-sdk>=5.0.0\n")
|
|
169
174
|
|
|
170
175
|
with open(f"{name}/tests/__init__.py", "w") as f:
|
|
171
176
|
pass
|
|
@@ -212,9 +217,9 @@ async def fn_default(ctx, **kwargs):
|
|
|
212
217
|
click.echo(f"")
|
|
213
218
|
click.echo(f"Next steps:")
|
|
214
219
|
click.echo(f" cd {name}")
|
|
215
|
-
click.echo(f" pip install 'imperal-sdk>=
|
|
220
|
+
click.echo(f" pip install 'imperal-sdk>=5.0.0'")
|
|
216
221
|
click.echo(f" imperal build # generates imperal.json")
|
|
217
|
-
click.echo(f" imperal validate # runs
|
|
222
|
+
click.echo(f" imperal validate # runs V1-V24+V31 federal validators")
|
|
218
223
|
click.echo(f" imperal test # smoke-test handlers via MockContext")
|
|
219
224
|
click.echo(f" imperal deploy # upload to panel.imperal.io/developer")
|
|
220
225
|
|
|
@@ -297,7 +302,7 @@ def build(path: str):
|
|
|
297
302
|
@cli.command()
|
|
298
303
|
@click.argument("path", default=".")
|
|
299
304
|
def validate(path: str):
|
|
300
|
-
"""Validate extension against SDK
|
|
305
|
+
"""Validate extension against the current SDK federal rules (V1-V24+V31)."""
|
|
301
306
|
original_dir = os.getcwd()
|
|
302
307
|
try:
|
|
303
308
|
os.chdir(path)
|
|
@@ -346,7 +351,7 @@ def validate(path: str):
|
|
|
346
351
|
fix="Fix the JSON syntax error at the reported line",
|
|
347
352
|
))
|
|
348
353
|
|
|
349
|
-
click.echo(f"\n── Imperal Extension Validator
|
|
354
|
+
click.echo(f"\n── Imperal Extension Validator (SDK {SDK_VERSION}) {'─' * 36}")
|
|
350
355
|
click.echo(f"\nExtension: {report.app_id} v{report.version}")
|
|
351
356
|
click.echo(f"Tools: {report.tool_count}, Functions: {report.function_count}, Events: {report.event_count}")
|
|
352
357
|
|
|
@@ -114,7 +114,7 @@ async def builtin_secrets_panel_handler(ctx: Any, **_params: Any) -> dict:
|
|
|
114
114
|
))
|
|
115
115
|
|
|
116
116
|
root = ui.Stack(children=[
|
|
117
|
-
ui.
|
|
117
|
+
ui.Header(f"Secrets · {ext_id}", level=2),
|
|
118
118
|
ui.Text(
|
|
119
119
|
"Credentials this extension needs — API keys, OAuth tokens. "
|
|
120
120
|
"Stored encrypted in Vault; never visible to admins or in logs."
|
|
@@ -207,18 +207,22 @@ class MockHTTP:
|
|
|
207
207
|
"""Mock HTTP client. Register responses per URL pattern."""
|
|
208
208
|
|
|
209
209
|
def __init__(self):
|
|
210
|
-
self._mocks: list[tuple[str, str, dict, int]] = []
|
|
210
|
+
self._mocks: list[tuple[str, str, dict, int, dict]] = []
|
|
211
211
|
|
|
212
|
-
def mock_get(self, url_pattern: str, response: dict, status: int = 200
|
|
213
|
-
|
|
212
|
+
def mock_get(self, url_pattern: str, response: dict, status: int = 200,
|
|
213
|
+
headers: dict | None = None) -> None:
|
|
214
|
+
self._mocks.append(("GET", url_pattern, response, status, headers or {}))
|
|
214
215
|
|
|
215
|
-
def mock_post(self, url_pattern: str, response: dict, status: int = 200
|
|
216
|
-
|
|
216
|
+
def mock_post(self, url_pattern: str, response: dict, status: int = 200,
|
|
217
|
+
headers: dict | None = None) -> None:
|
|
218
|
+
self._mocks.append(("POST", url_pattern, response, status, headers or {}))
|
|
217
219
|
|
|
218
220
|
async def _find(self, method: str, url: str) -> HTTPResponse:
|
|
219
|
-
for
|
|
221
|
+
for entry in self._mocks:
|
|
222
|
+
m, pattern, resp, status = entry[0], entry[1], entry[2], entry[3]
|
|
223
|
+
hdrs = entry[4] if len(entry) > 4 else {} # tolerate legacy 4-tuples
|
|
220
224
|
if m == method and pattern in url:
|
|
221
|
-
return HTTPResponse(status_code=status, body=resp)
|
|
225
|
+
return HTTPResponse(status_code=status, body=resp, headers=dict(hdrs))
|
|
222
226
|
return HTTPResponse(status_code=404, body={"error": "No mock registered"})
|
|
223
227
|
|
|
224
228
|
async def get(self, url: str, **kwargs) -> HTTPResponse:
|
|
@@ -91,13 +91,15 @@ class HTTPResponse:
|
|
|
91
91
|
body: dict | str | bytes = ""
|
|
92
92
|
headers: dict = field(default_factory=dict)
|
|
93
93
|
|
|
94
|
-
def json(self) -> dict:
|
|
95
|
-
|
|
94
|
+
def json(self) -> dict | list:
|
|
95
|
+
# Already-parsed JSON (the prod http client parses on content-type: json,
|
|
96
|
+
# so an array endpoint like WP /wp/v2/posts yields a list body).
|
|
97
|
+
if isinstance(self.body, (dict, list)):
|
|
96
98
|
return self.body
|
|
97
|
-
if isinstance(self.body, str):
|
|
99
|
+
if isinstance(self.body, (str, bytes, bytearray)):
|
|
98
100
|
import json
|
|
99
101
|
return json.loads(self.body)
|
|
100
|
-
raise ValueError("
|
|
102
|
+
raise ValueError(f"Cannot parse {type(self.body).__name__} body as JSON")
|
|
101
103
|
|
|
102
104
|
def text(self) -> str:
|
|
103
105
|
if isinstance(self.body, str):
|
|
@@ -728,7 +728,7 @@ def validate_extension(ext) -> ValidationReport:
|
|
|
728
728
|
# can be promoted post-soak.
|
|
729
729
|
#
|
|
730
730
|
# Soak severity is env-toggled via IMPERAL_VALIDATOR_V23_SEVERITY
|
|
731
|
-
# (default "
|
|
731
|
+
# (default "error" since 2026-06-17 P5-final; set "warn" to opt out).
|
|
732
732
|
try:
|
|
733
733
|
_chat_exts = getattr(ext, "_chat_extensions", {}) or {}
|
|
734
734
|
for _tool_name, _chat_ext in _chat_exts.items():
|
|
@@ -744,14 +744,20 @@ def validate_extension(ext) -> ValidationReport:
|
|
|
744
744
|
def _v23_v24_check_data_model_presence(report, extensions, functions):
|
|
745
745
|
"""Apply V23 (read) + V24 (write/destructive) ``data_model`` rules to each
|
|
746
746
|
@chat.function in the given functions dict (name -> FunctionDef)."""
|
|
747
|
-
_v23_severity = os.environ.get("IMPERAL_VALIDATOR_V23_SEVERITY", "
|
|
748
|
-
|
|
747
|
+
_v23_severity = os.environ.get("IMPERAL_VALIDATOR_V23_SEVERITY", "error").lower()
|
|
748
|
+
# P5-final (2026-06-17): V23 defaults to ERROR. Only an explicit env "warn"
|
|
749
|
+
# downgrades it; anything else (including unset) resolves to ERROR.
|
|
750
|
+
_v23_level = "WARN" if _v23_severity == "warn" else "ERROR"
|
|
749
751
|
for fn_name, fn_def in (functions or {}).items():
|
|
750
752
|
_action_type = getattr(fn_def, "action_type", "read")
|
|
751
753
|
_return_model = getattr(fn_def, "_return_model", None)
|
|
752
754
|
if _return_model is not None:
|
|
753
755
|
continue
|
|
754
756
|
if _action_type == "read":
|
|
757
|
+
# Declarative-UI builders (@chat.function(ui_builder=True)) return ui.*
|
|
758
|
+
# output, not an SDL entity — exempt from the data_model requirement.
|
|
759
|
+
if getattr(fn_def, "_ui_builder", False):
|
|
760
|
+
continue
|
|
755
761
|
report.issues.append(ValidationIssue(
|
|
756
762
|
rule="V23", level=_v23_level,
|
|
757
763
|
message=(
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import os
|
|
4
4
|
import pytest
|
|
5
5
|
from click.testing import CliRunner
|
|
6
|
+
from imperal_sdk import __version__
|
|
6
7
|
from imperal_sdk.cli.main import cli
|
|
7
8
|
|
|
8
9
|
|
|
@@ -10,7 +11,7 @@ def test_cli_version():
|
|
|
10
11
|
runner = CliRunner()
|
|
11
12
|
result = runner.invoke(cli, ["--version"])
|
|
12
13
|
assert result.exit_code == 0
|
|
13
|
-
assert
|
|
14
|
+
assert __version__ in result.output # CLI reports the real SDK version
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def test_cli_init_chat_template():
|
|
@@ -40,7 +41,7 @@ def test_cli_init_chat_template():
|
|
|
40
41
|
assert "actions_explicit=True" in content
|
|
41
42
|
|
|
42
43
|
with open("my-test-ext/requirements.txt") as f:
|
|
43
|
-
assert "imperal-sdk>=
|
|
44
|
+
assert "imperal-sdk>=5.0.0" in f.read() # scaffold pins current major
|
|
44
45
|
|
|
45
46
|
with open("my-test-ext/icon.svg") as f:
|
|
46
47
|
svg = f.read()
|
|
@@ -139,8 +139,8 @@ def test_data_model_none_means_no_return_model():
|
|
|
139
139
|
|
|
140
140
|
|
|
141
141
|
def test_v23_warn_when_read_missing_data_model(monkeypatch):
|
|
142
|
-
"""``IMPERAL_VALIDATOR_V23_SEVERITY=warn`` (
|
|
143
|
-
monkeypatch.
|
|
142
|
+
"""``IMPERAL_VALIDATOR_V23_SEVERITY=warn`` (explicit opt-out) MUST emit WARN."""
|
|
143
|
+
monkeypatch.setenv("IMPERAL_VALIDATOR_V23_SEVERITY", "warn")
|
|
144
144
|
ext = _make_ext()
|
|
145
145
|
chat = _make_chat(ext)
|
|
146
146
|
|
|
@@ -159,6 +159,26 @@ def test_v23_warn_when_read_missing_data_model(monkeypatch):
|
|
|
159
159
|
assert "data_model" in v23[0].message
|
|
160
160
|
|
|
161
161
|
|
|
162
|
+
def test_v23_error_by_default(monkeypatch):
|
|
163
|
+
"""P5-final (2026-06-17): with the env unset, V23 defaults to ERROR."""
|
|
164
|
+
monkeypatch.delenv("IMPERAL_VALIDATOR_V23_SEVERITY", raising=False)
|
|
165
|
+
ext = _make_ext()
|
|
166
|
+
chat = _make_chat(ext)
|
|
167
|
+
|
|
168
|
+
@chat.function(
|
|
169
|
+
name="list_notes",
|
|
170
|
+
description="List notes — read tool deliberately missing data_model",
|
|
171
|
+
action_type="read",
|
|
172
|
+
)
|
|
173
|
+
async def list_notes(ctx, params: ListNotesParams) -> ActionResult:
|
|
174
|
+
return ActionResult.success(data={}, summary="ok")
|
|
175
|
+
|
|
176
|
+
report = validate_extension(ext)
|
|
177
|
+
v23 = [i for i in report.errors if i.rule == "V23"]
|
|
178
|
+
assert len(v23) == 1
|
|
179
|
+
assert "data_model" in v23[0].message
|
|
180
|
+
|
|
181
|
+
|
|
162
182
|
def test_v23_error_when_severity_env_set(monkeypatch):
|
|
163
183
|
"""``IMPERAL_VALIDATOR_V23_SEVERITY=error`` MUST promote to ERROR."""
|
|
164
184
|
monkeypatch.setenv("IMPERAL_VALIDATOR_V23_SEVERITY", "error")
|
|
@@ -179,6 +199,25 @@ def test_v23_error_when_severity_env_set(monkeypatch):
|
|
|
179
199
|
assert "data_model" in v23[0].message
|
|
180
200
|
|
|
181
201
|
|
|
202
|
+
def test_v23_skips_ui_builder(monkeypatch):
|
|
203
|
+
"""``ui_builder=True`` read tools are exempt from V23 even at severity=error."""
|
|
204
|
+
monkeypatch.setenv("IMPERAL_VALIDATOR_V23_SEVERITY", "error")
|
|
205
|
+
ext = _make_ext()
|
|
206
|
+
chat = _make_chat(ext)
|
|
207
|
+
|
|
208
|
+
@chat.function(
|
|
209
|
+
name="get_panel_data",
|
|
210
|
+
description="Declarative-UI builder — exempt from V23 via ui_builder flag",
|
|
211
|
+
action_type="read",
|
|
212
|
+
ui_builder=True,
|
|
213
|
+
)
|
|
214
|
+
async def get_panel_data(ctx, params: ListNotesParams) -> ActionResult:
|
|
215
|
+
return ActionResult.success(data={}, summary="ok")
|
|
216
|
+
|
|
217
|
+
report = validate_extension(ext)
|
|
218
|
+
assert not [i for i in report.issues if i.rule == "V23"]
|
|
219
|
+
|
|
220
|
+
|
|
182
221
|
def test_v23_passes_when_data_model_declared():
|
|
183
222
|
"""Reads with ``data_model=`` MUST NOT trigger V23."""
|
|
184
223
|
ext = _make_ext()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Regression tests: HTTPResponse.json() on JSON-array bodies + MockHTTP headers."""
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
from imperal_sdk.types.models import HTTPResponse
|
|
5
|
+
from imperal_sdk.testing.mock_context import MockHTTP
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_json_returns_list_for_array_body():
|
|
9
|
+
"""An array endpoint (e.g. WP /wp/v2/posts) yields a list body — must not raise."""
|
|
10
|
+
r = HTTPResponse(status_code=200, body=[{"id": 1}, {"id": 2}])
|
|
11
|
+
assert r.json() == [{"id": 1}, {"id": 2}]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_json_dict_body():
|
|
15
|
+
assert HTTPResponse(status_code=200, body={"a": 1}).json() == {"a": 1}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_json_parses_str_and_bytes():
|
|
19
|
+
assert HTTPResponse(status_code=200, body="[1, 2]").json() == [1, 2]
|
|
20
|
+
assert HTTPResponse(status_code=200, body=b'{"a": 1}').json() == {"a": 1}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_mockhttp_get_sets_response_headers():
|
|
24
|
+
mh = MockHTTP()
|
|
25
|
+
mh.mock_get("/wp/v2/posts", [{"id": 1}], status=200, headers={"X-WP-Total": "57"})
|
|
26
|
+
resp = asyncio.run(mh.get("https://example.com/wp/v2/posts"))
|
|
27
|
+
assert resp.status_code == 200
|
|
28
|
+
assert resp.headers.get("X-WP-Total") == "57"
|
|
29
|
+
assert resp.json() == [{"id": 1}]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_mockhttp_post_headers_default_empty():
|
|
33
|
+
mh = MockHTTP()
|
|
34
|
+
mh.mock_post("/x", {"ok": True})
|
|
35
|
+
resp = asyncio.run(mh.post("https://example.com/x"))
|
|
36
|
+
assert resp.headers == {}
|
|
37
|
+
assert resp.json() == {"ok": True}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/devtools/validate_identity_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/completion_result.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{imperal_sdk-5.4.2 → imperal_sdk-5.4.3}/src/imperal_sdk/schemas/subscription_info.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|