imperal-sdk 5.2.0__tar.gz → 5.2.1__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.2.0 → imperal_sdk-5.2.1}/CHANGELOG.md +25 -7
- imperal_sdk-5.2.1/PKG-INFO +148 -0
- imperal_sdk-5.2.1/README.md +111 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/__init__.py +1 -1
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/extension.py +14 -15
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_no_orchestrator_tool.py +29 -12
- imperal_sdk-5.2.0/PKG-INFO +0 -264
- imperal_sdk-5.2.0/README.md +0 -227
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/.github/workflows/identity-contract.yml +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/.github/workflows/publish.yml +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/.github/workflows/test.yml +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/.gitignore +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/LICENSE +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/api_surface.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/docs/sdl-facets.md +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/pyproject.toml +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/sdk_claims.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/sdl_roles.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/.codebase-index-cache.pkl +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ai/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ai/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/auth/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/auth/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/auth/middleware.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/billing/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/billing/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/cache/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/cache/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/cache/protocol.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/action_result.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/error_codes.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/exceptions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/filters.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/guards.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/kernel_primitives.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/narration.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/narration_guard.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/prompt.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/chat/refusal.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/cli/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/cli/main.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/config/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/config/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/context.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/devtools/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/devtools/contract_checks.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/devtools/generate_api_surface.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/devtools/generate_sdk_claims.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/devtools/validate_identity_contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/errors.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/extension.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/extensions/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/extensions/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/http/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/http/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/manifest.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/manifest_schema.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/notify/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/notify/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/prompts/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/prompts/icnli_integrity_rules.txt +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/prompts/kernel_formatting_rule.txt +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/prompts/kernel_proactivity_rule.txt +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/protocols.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/rpc/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/rpc/codec.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/rpc/contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/runtime/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/runtime/executor.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/runtime/llm_provider.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/runtime/message_adapter.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/action_result.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/balance_info.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/chat_result.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/completion_result.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/document.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/event.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/file_info.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/function_call.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/http_response.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/imperal.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/limits_result.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/schemas/subscription_info.schema.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/_generate_roles_json.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/entity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/catalog.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/comm.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/content.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/device.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/event.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/geo.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/identity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/media.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/metric.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/money.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/net.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/people.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/quantity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/rating.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/security.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/task.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/facets/time.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/field.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/sdl/roles.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/secrets/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/secrets/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/secrets/exceptions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/secrets/panel_handler.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/secrets/spec.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/security/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/security/call_token.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/skeleton/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/skeleton/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/storage/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/storage/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/store/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/store/client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/store/exceptions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/testing/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/testing/mock_context.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/testing/mock_secrets.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/action_result.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/chat_result.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/client_contracts.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/contracts.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/contributions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/events.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/health.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/identity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/models.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/pagination.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/types/store_contracts.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/actions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/base.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/data.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/display.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/feedback.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/graph.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/input_components.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/interactive.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/layout.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/ui/theme.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/validator.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/src/imperal_sdk/validator_v1_6_0.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/conftest.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contract/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contract/test_contract_checks_selftest.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contract/test_generate_sdk_claims.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contract/test_sample_contract_shape.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contract/test_sdk_matches_kernel_contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contracts/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/contracts/test_store_contracts.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/fixtures/contract/kernel-contract.sample.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/fixtures/openapi/auth-gateway.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/fixtures/openapi/registry.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/fixtures/openapi/sharelock-cases.json +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/rpc/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/rpc/test_codec.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/rpc/test_contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/runtime/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/runtime/test_llm_provider_config_store.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/runtime/test_llm_provider_ctx_injection.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/store/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/store/test_list_users_client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/store/test_query_all_client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_action_result_typed.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_as_user.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_auth.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_billing.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_cache_client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_cache_model.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_call_token.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_extension_deprecation.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_extension_no_llm_router.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_filters.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_function_background_flag.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_guards.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_guards_bleed.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_prompt.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_chat_result.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_cli.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_client_contracts.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_config_client.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_context.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_context_background_task.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_context_deliver_chat_message.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_context_guards.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_contracts.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_contracts_live.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_contributions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_data_model_kwarg.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_document_contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_emits_decorator.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_error_codes.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_errors.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_event_schema_v2.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_events_health.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_extension.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_extension_v2.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_extensions_emit.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_http_timeout_override.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_id_shape_guard.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_identity_contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_imperal_schema_v2.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_kernel_primitives.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_roundtrip_gate.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_schema.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_v2_events.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_v2_other_sections.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_v2_webhooks.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_manifest_validator_v2.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_mock_context.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_models.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_narration_emission.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_narration_guard.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_openai_max_completion_tokens.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_pagination.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_panel_rendering_contract.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_panels.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_phase_a_dead_removal.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_phase_a_drift.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_phase_a_text.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdk_version_stamp.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_entity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_entity_marker.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_exports.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_catalog.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_collisions.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_comm.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_content.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_device.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_event.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_exports.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_field.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_geo.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_identity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_media.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_metric.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_money.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_net.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_people.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_quantity.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_rating.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_security.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_task.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facet_time.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facets_catalog.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facets_doc.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_facets_pkg.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_field.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_roles.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_roles_json.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_sdl_roles_of_facets.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_skeleton_decorator.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_spec_validation.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_ui.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_ui_fileupload_enhanced.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_ui_html.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_ui_image_enhanced.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_ui_open.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_ui_theme.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_user.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_v7_emit_refusal.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_validator.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_validator_drift.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_validator_pep563.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_validator_v1_6_0_rules.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_validator_v25.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/test_write_arg_bleed.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/tools/__init__.py +0 -0
- {imperal_sdk-5.2.0 → imperal_sdk-5.2.1}/tests/tools/test_generate_api_surface.py +0 -0
|
@@ -2,14 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `imperal-sdk` are documented here.
|
|
4
4
|
|
|
5
|
+
## 5.2.1 — 2026-06-01 — ChatExtension ergonomics & honest deprecations
|
|
6
|
+
|
|
7
|
+
Small, fully backward-compatible cleanup of `ChatExtension`. No API removals;
|
|
8
|
+
existing extensions are unaffected.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- `ChatExtension(tool_name=...)` no longer emits a `DeprecationWarning`. The
|
|
13
|
+
kwarg is the **canonical** chat-registration key — it groups your
|
|
14
|
+
`@chat.function` tools in the manifest, anchors the per-turn prompt, and
|
|
15
|
+
labels scope-guard audit lines. It is load-bearing and not going away; the
|
|
16
|
+
prior "removed in 5.1.0" warning was incorrect and has been removed.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `ChatExtension(...)` now accepts an **optional** `tool_name`. When omitted it
|
|
21
|
+
defaults to `f"tool_{ext.app_id}_chat"`. Pass it explicitly to pin a stable
|
|
22
|
+
routing name (recommended for production extensions). `description=` is now
|
|
23
|
+
optional as well.
|
|
24
|
+
|
|
5
25
|
## 5.2.0 — 2026-05-31 — Structured Data Layer (SDL) foundation
|
|
6
26
|
|
|
7
27
|
Introduces the **SDL (`imperal_sdk.sdl`)** — a typed, semantic vocabulary for the
|
|
8
28
|
data an extension returns, so the platform can read an entity's id / title / kind
|
|
9
29
|
and its facets directly instead of inferring them from field names. This release
|
|
10
30
|
ships the SDK foundation (canonical types + the standard facet library + a schema
|
|
11
|
-
marker for platform detection)
|
|
12
|
-
flag in a later release. Fully **additive** — the existing API and existing
|
|
31
|
+
marker for platform detection). **The platform reads SDL in production today.** Fully **additive** — the existing API and existing
|
|
13
32
|
extensions are unchanged; adopting SDL is opt-in via `data_model=`.
|
|
14
33
|
|
|
15
34
|
### Added
|
|
@@ -28,8 +47,8 @@ extensions are unchanged; adopting SDL is opt-in via `data_model=`.
|
|
|
28
47
|
- `sdl.roles_of(model)` — introspect a model's field→role map.
|
|
29
48
|
|
|
30
49
|
Use it via `data_model=` on `@chat.function` (e.g.
|
|
31
|
-
`class Note(sdl.Entity): ...` → `data_model=Note`).
|
|
32
|
-
|
|
50
|
+
`class Note(sdl.Entity): ...` → `data_model=Note`). **The platform reads SDL
|
|
51
|
+
entities in production today.**
|
|
33
52
|
- **SDL — Standard Facet Library (Phase 2).** 123 composable facet mixins across
|
|
34
53
|
17 families (Identity, Time, People, Content, Communication, Media, Quantities,
|
|
35
54
|
Money, Catalog, Tasks, Location, Tech/Network, Analytics, Events, Ratings,
|
|
@@ -43,9 +62,8 @@ extensions are unchanged; adopting SDL is opt-in via `data_model=`.
|
|
|
43
62
|
|
|
44
63
|
564 standard roles are catalogued in `sdl_roles.json`. Every facet field is
|
|
45
64
|
optional; for anything not covered, use `sdl.field(role="yourapp.x")` with a
|
|
46
|
-
non-reserved namespace. Full guide: `docs/sdl-facets.md`.
|
|
47
|
-
|
|
48
|
-
them in a later phase.
|
|
65
|
+
non-reserved namespace. Full guide: `docs/sdl-facets.md`. **Live in production** —
|
|
66
|
+
extensions adopt the types and the platform reads them today.
|
|
49
67
|
- **SDL — schema marker on `Entity` / `EntityList`.** Both stamp
|
|
50
68
|
`x-sdl: "entity"` / `"entity-list"` into their JSON schema so the platform can
|
|
51
69
|
detect an SDL-typed result from a function's return schema alone. Inherited by
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: imperal-sdk
|
|
3
|
+
Version: 5.2.1
|
|
4
|
+
Summary: SDK for building Imperal Cloud extensions
|
|
5
|
+
Author: Valentin Scerbacov, Imperal, Inc.
|
|
6
|
+
License-Expression: AGPL-3.0-or-later
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Framework :: FastAPI
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: click>=8.1.0
|
|
20
|
+
Requires-Dist: httpx>=0.28.0
|
|
21
|
+
Requires-Dist: pydantic>=2.10.0
|
|
22
|
+
Requires-Dist: pyjwt[crypto]>=2.10.0
|
|
23
|
+
Provides-Extra: contract
|
|
24
|
+
Requires-Dist: schemathesis>=3.30.0; extra == 'contract'
|
|
25
|
+
Provides-Extra: db
|
|
26
|
+
Requires-Dist: aiomysql>=0.2.0; extra == 'db'
|
|
27
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.30; extra == 'db'
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: jsonschema>=4.21.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: openapi-spec-validator>=0.7.1; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.25.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: respx>=0.22.0; extra == 'dev'
|
|
34
|
+
Provides-Extra: fastapi
|
|
35
|
+
Requires-Dist: fastapi>=0.115.0; extra == 'fastapi'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
<div align="center">
|
|
39
|
+
|
|
40
|
+
# Imperal SDK
|
|
41
|
+
|
|
42
|
+
### Build extensions for Webbee 🐝 — the agent of Imperal Cloud, the world's first AI Cloud OS.
|
|
43
|
+
|
|
44
|
+
**Write a small Python function. Webbee calls it when a user asks for it — in their own words. Ship it to the Marketplace and get paid.**
|
|
45
|
+
|
|
46
|
+
[](https://pypi.org/project/imperal-sdk/)
|
|
47
|
+
[](https://pypi.org/project/imperal-sdk/)
|
|
48
|
+
[](LICENSE)
|
|
49
|
+
|
|
50
|
+
[Documentation](https://docs.imperal.io) · [Quickstart](https://docs.imperal.io/en/getting-started/quick-start/) · [PyPI](https://pypi.org/project/imperal-sdk/) · [imperal.io](https://imperal.io)
|
|
51
|
+
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## What this is
|
|
57
|
+
|
|
58
|
+
**Imperal Cloud** is the world's first AI Cloud OS — a cloud you connect the contexts of your life into (mail, money, projects, servers, notes, anything) and then run entirely in your own native language. **Webbee 🐝** is the AI agent that lives inside it and does the work for you, safely.
|
|
59
|
+
|
|
60
|
+
**The Imperal SDK is how you give Webbee a new skill.** You write a small, typed Python *extension*; Webbee picks it up and calls it whenever a user asks for what it does — in plain language. The platform handles the hard parts — authentication, billing, multi-tenancy, audit, recovery, LLM routing — so your code stays small.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install imperal-sdk
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> Python 3.11+ · AGPL-3.0-or-later
|
|
67
|
+
|
|
68
|
+
## Why build here
|
|
69
|
+
|
|
70
|
+
- **Webbee calls your function directly.** Typed, structured calls — no LLM guessing your arguments, no silent write failures.
|
|
71
|
+
- **The platform does the plumbing.** Auth, per-user isolation, billing, audit, retries and recovery, multi-tenant safety — handled for you.
|
|
72
|
+
- **You get paid.** Publish to the Imperal Marketplace, price your extension, earn on every use.
|
|
73
|
+
- **Bring any LLM.** Users connect their own model keys — Anthropic, OpenAI, Google, Ollama, any OpenAI-compatible API.
|
|
74
|
+
|
|
75
|
+
## A 60-second extension
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from imperal_sdk import Extension, ChatExtension, ActionResult
|
|
79
|
+
from pydantic import BaseModel, Field
|
|
80
|
+
|
|
81
|
+
ext = Extension(
|
|
82
|
+
"hello-world",
|
|
83
|
+
version="1.0.0",
|
|
84
|
+
display_name="Hello World",
|
|
85
|
+
description="Greets people by name with a friendly message.",
|
|
86
|
+
icon="icon.svg",
|
|
87
|
+
actions_explicit=True,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
chat = ChatExtension(ext, tool_name="hello_world", description="Friendly greetings.")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class GreetParams(BaseModel):
|
|
94
|
+
name: str = Field(..., description="Person to greet")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@chat.function("greet", description="Greet someone by name.", action_type="read")
|
|
98
|
+
async def greet(ctx, params: GreetParams) -> ActionResult:
|
|
99
|
+
return ActionResult.success(
|
|
100
|
+
data={"message": f"Hello, {params.name}! 🐝"},
|
|
101
|
+
summary=f"Greeted {params.name}",
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
That's a real, working extension. When a user types *"say hi to Alex"*, Webbee calls `greet(name="Alex")`.
|
|
106
|
+
|
|
107
|
+
→ Full walkthrough, from zero to published: **[docs.imperal.io](https://docs.imperal.io/en/getting-started/quick-start/)**
|
|
108
|
+
|
|
109
|
+
## What you can build
|
|
110
|
+
|
|
111
|
+
- **Chat tools** — typed `@chat.function`s Webbee calls straight from natural language.
|
|
112
|
+
- **Panels** — UI surfaces rendered inside the Imperal Panel.
|
|
113
|
+
- **Skeletons** — live data feeds that keep Webbee aware of a user's state.
|
|
114
|
+
- **Scheduled jobs & webhooks** — act on a timer, or react to outside events.
|
|
115
|
+
- **Typed entities (SDL)** — return `sdl.Entity` objects and the platform reads their meaning (id, title, kind, …) directly instead of guessing field names. Live in production.
|
|
116
|
+
|
|
117
|
+
Every published extension passes the **federal contract** — the validators that let Webbee call your code safely. The SDK checks it locally before you ship.
|
|
118
|
+
|
|
119
|
+
## Test without a server
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from imperal_sdk.testing import MockContext
|
|
123
|
+
|
|
124
|
+
async def test_greet():
|
|
125
|
+
ctx = MockContext()
|
|
126
|
+
result = await greet(ctx, GreetParams(name="Alex"))
|
|
127
|
+
assert result.status == "success"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
The full API, the manifest schema, every validator, recipes, and the federal contract live at **[docs.imperal.io](https://docs.imperal.io)** — that's the source of truth; this README is just the doorway.
|
|
133
|
+
|
|
134
|
+
| | |
|
|
135
|
+
|---|---|
|
|
136
|
+
| Documentation | [docs.imperal.io](https://docs.imperal.io) |
|
|
137
|
+
| Quickstart | [docs.imperal.io/en/getting-started/quick-start](https://docs.imperal.io/en/getting-started/quick-start/) |
|
|
138
|
+
| PyPI | [pypi.org/project/imperal-sdk](https://pypi.org/project/imperal-sdk/) |
|
|
139
|
+
| Changelog | [CHANGELOG.md](CHANGELOG.md) |
|
|
140
|
+
| License | [AGPL-3.0-or-later](LICENSE) |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
<div align="center">
|
|
145
|
+
|
|
146
|
+
**Built by [Imperal, Inc.](https://imperal.io) — Webbee 🐝 is its agent.**
|
|
147
|
+
|
|
148
|
+
</div>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Imperal SDK
|
|
4
|
+
|
|
5
|
+
### Build extensions for Webbee 🐝 — the agent of Imperal Cloud, the world's first AI Cloud OS.
|
|
6
|
+
|
|
7
|
+
**Write a small Python function. Webbee calls it when a user asks for it — in their own words. Ship it to the Marketplace and get paid.**
|
|
8
|
+
|
|
9
|
+
[](https://pypi.org/project/imperal-sdk/)
|
|
10
|
+
[](https://pypi.org/project/imperal-sdk/)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
[Documentation](https://docs.imperal.io) · [Quickstart](https://docs.imperal.io/en/getting-started/quick-start/) · [PyPI](https://pypi.org/project/imperal-sdk/) · [imperal.io](https://imperal.io)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What this is
|
|
20
|
+
|
|
21
|
+
**Imperal Cloud** is the world's first AI Cloud OS — a cloud you connect the contexts of your life into (mail, money, projects, servers, notes, anything) and then run entirely in your own native language. **Webbee 🐝** is the AI agent that lives inside it and does the work for you, safely.
|
|
22
|
+
|
|
23
|
+
**The Imperal SDK is how you give Webbee a new skill.** You write a small, typed Python *extension*; Webbee picks it up and calls it whenever a user asks for what it does — in plain language. The platform handles the hard parts — authentication, billing, multi-tenancy, audit, recovery, LLM routing — so your code stays small.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install imperal-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> Python 3.11+ · AGPL-3.0-or-later
|
|
30
|
+
|
|
31
|
+
## Why build here
|
|
32
|
+
|
|
33
|
+
- **Webbee calls your function directly.** Typed, structured calls — no LLM guessing your arguments, no silent write failures.
|
|
34
|
+
- **The platform does the plumbing.** Auth, per-user isolation, billing, audit, retries and recovery, multi-tenant safety — handled for you.
|
|
35
|
+
- **You get paid.** Publish to the Imperal Marketplace, price your extension, earn on every use.
|
|
36
|
+
- **Bring any LLM.** Users connect their own model keys — Anthropic, OpenAI, Google, Ollama, any OpenAI-compatible API.
|
|
37
|
+
|
|
38
|
+
## A 60-second extension
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from imperal_sdk import Extension, ChatExtension, ActionResult
|
|
42
|
+
from pydantic import BaseModel, Field
|
|
43
|
+
|
|
44
|
+
ext = Extension(
|
|
45
|
+
"hello-world",
|
|
46
|
+
version="1.0.0",
|
|
47
|
+
display_name="Hello World",
|
|
48
|
+
description="Greets people by name with a friendly message.",
|
|
49
|
+
icon="icon.svg",
|
|
50
|
+
actions_explicit=True,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
chat = ChatExtension(ext, tool_name="hello_world", description="Friendly greetings.")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class GreetParams(BaseModel):
|
|
57
|
+
name: str = Field(..., description="Person to greet")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@chat.function("greet", description="Greet someone by name.", action_type="read")
|
|
61
|
+
async def greet(ctx, params: GreetParams) -> ActionResult:
|
|
62
|
+
return ActionResult.success(
|
|
63
|
+
data={"message": f"Hello, {params.name}! 🐝"},
|
|
64
|
+
summary=f"Greeted {params.name}",
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
That's a real, working extension. When a user types *"say hi to Alex"*, Webbee calls `greet(name="Alex")`.
|
|
69
|
+
|
|
70
|
+
→ Full walkthrough, from zero to published: **[docs.imperal.io](https://docs.imperal.io/en/getting-started/quick-start/)**
|
|
71
|
+
|
|
72
|
+
## What you can build
|
|
73
|
+
|
|
74
|
+
- **Chat tools** — typed `@chat.function`s Webbee calls straight from natural language.
|
|
75
|
+
- **Panels** — UI surfaces rendered inside the Imperal Panel.
|
|
76
|
+
- **Skeletons** — live data feeds that keep Webbee aware of a user's state.
|
|
77
|
+
- **Scheduled jobs & webhooks** — act on a timer, or react to outside events.
|
|
78
|
+
- **Typed entities (SDL)** — return `sdl.Entity` objects and the platform reads their meaning (id, title, kind, …) directly instead of guessing field names. Live in production.
|
|
79
|
+
|
|
80
|
+
Every published extension passes the **federal contract** — the validators that let Webbee call your code safely. The SDK checks it locally before you ship.
|
|
81
|
+
|
|
82
|
+
## Test without a server
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from imperal_sdk.testing import MockContext
|
|
86
|
+
|
|
87
|
+
async def test_greet():
|
|
88
|
+
ctx = MockContext()
|
|
89
|
+
result = await greet(ctx, GreetParams(name="Alex"))
|
|
90
|
+
assert result.status == "success"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Documentation
|
|
94
|
+
|
|
95
|
+
The full API, the manifest schema, every validator, recipes, and the federal contract live at **[docs.imperal.io](https://docs.imperal.io)** — that's the source of truth; this README is just the doorway.
|
|
96
|
+
|
|
97
|
+
| | |
|
|
98
|
+
|---|---|
|
|
99
|
+
| Documentation | [docs.imperal.io](https://docs.imperal.io) |
|
|
100
|
+
| Quickstart | [docs.imperal.io/en/getting-started/quick-start](https://docs.imperal.io/en/getting-started/quick-start/) |
|
|
101
|
+
| PyPI | [pypi.org/project/imperal-sdk](https://pypi.org/project/imperal-sdk/) |
|
|
102
|
+
| Changelog | [CHANGELOG.md](CHANGELOG.md) |
|
|
103
|
+
| License | [AGPL-3.0-or-later](LICENSE) |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
<div align="center">
|
|
108
|
+
|
|
109
|
+
**Built by [Imperal, Inc.](https://imperal.io) — Webbee 🐝 is its agent.**
|
|
110
|
+
|
|
111
|
+
</div>
|
|
@@ -64,9 +64,16 @@ class FunctionDef:
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
class ChatExtension:
|
|
67
|
-
def __init__(self, ext, tool_name: str
|
|
67
|
+
def __init__(self, ext, tool_name: str | None = None, description: str = "",
|
|
68
|
+
system_prompt: str = "",
|
|
68
69
|
model: "str | None" = None, max_rounds: int = 10):
|
|
69
70
|
self.ext = ext
|
|
71
|
+
# tool_name is the canonical chat-registration key: it groups the
|
|
72
|
+
# extension's @chat.function tools in the manifest, anchors the per-turn
|
|
73
|
+
# system prompt, and labels scope-guard audit lines. Optional — derived
|
|
74
|
+
# from the extension app_id (``tool_<app_id>_chat``) when omitted; pass
|
|
75
|
+
# it explicitly to pin a production-stable routing name.
|
|
76
|
+
tool_name = tool_name or f"tool_{ext.app_id}_chat"
|
|
70
77
|
self.tool_name = tool_name
|
|
71
78
|
self.description = description
|
|
72
79
|
self.system_prompt = system_prompt
|
|
@@ -94,20 +101,12 @@ class ChatExtension:
|
|
|
94
101
|
"Example: 'Notes module — manage user notes and folders.'"
|
|
95
102
|
)
|
|
96
103
|
|
|
97
|
-
# v5.0.0
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
_warnings.warn(
|
|
104
|
-
f"ChatExtension(tool_name={tool_name!r}): kwarg deprecated in SDK 5.0.0 "
|
|
105
|
-
"(orchestrator-tool auto-registration removed). Move classifier-readable "
|
|
106
|
-
"text into Extension(description=...) + per-@chat.function(description=...). "
|
|
107
|
-
"Will be removed in 5.1.0.",
|
|
108
|
-
DeprecationWarning,
|
|
109
|
-
stacklevel=2,
|
|
110
|
-
)
|
|
104
|
+
# v5.0.0 removed orchestrator-tool auto-registration: ChatExtension is
|
|
105
|
+
# purely a @chat.function bundle declaration, and the platform chain
|
|
106
|
+
# executor dispatches each function directly via typed dispatch — the
|
|
107
|
+
# host LLM no longer sees a single ``tool_<app_id>_chat`` umbrella tool.
|
|
108
|
+
# ``tool_name`` is retained as the canonical registration key (see the
|
|
109
|
+
# __init__ note above) — it is NOT deprecated.
|
|
111
110
|
ext._chat_extensions = getattr(ext, "_chat_extensions", {})
|
|
112
111
|
ext._chat_extensions[tool_name] = self
|
|
113
112
|
|
|
@@ -8,10 +8,7 @@ from imperal_sdk.chat import ChatExtension
|
|
|
8
8
|
def test_chat_extension_does_not_emit_orchestrator_tool():
|
|
9
9
|
"""Building a manifest from an ext with a ChatExtension must not include tool_<name>_chat."""
|
|
10
10
|
ext = Extension(app_id="demo", description="demo ext for emitter test")
|
|
11
|
-
|
|
12
|
-
with warnings.catch_warnings():
|
|
13
|
-
warnings.simplefilter("ignore", DeprecationWarning)
|
|
14
|
-
chat = ChatExtension(ext, tool_name="demo_legacy_kwarg", description="legacy")
|
|
11
|
+
chat = ChatExtension(ext, tool_name="demo_legacy_kwarg", description="legacy")
|
|
15
12
|
|
|
16
13
|
@chat.function(name="list_items", description="list user items for the demo ext")
|
|
17
14
|
async def list_items(ctx):
|
|
@@ -53,17 +50,37 @@ def test_chat_extension_does_not_emit_orchestrator_tool():
|
|
|
53
50
|
)
|
|
54
51
|
|
|
55
52
|
|
|
56
|
-
def
|
|
57
|
-
"""ChatExtension(tool_name=...)
|
|
53
|
+
def test_chat_extension_tool_name_kwarg_does_not_warn():
|
|
54
|
+
"""ChatExtension(tool_name=...) is the canonical chat-registration key — it
|
|
55
|
+
must NOT emit a DeprecationWarning.
|
|
56
|
+
|
|
57
|
+
Reversed from the transient SDK 5.0.0 stance: the kwarg is load-bearing
|
|
58
|
+
(manifest grouping key + per-turn prompt + scope guards), has no
|
|
59
|
+
replacement API, and every first-party extension passes it. A deprecation
|
|
60
|
+
warning with no migration path is cry-wolf noise, so it was removed.
|
|
61
|
+
"""
|
|
58
62
|
ext = Extension(app_id="demo2", description="demo ext for deprecation test")
|
|
59
63
|
with warnings.catch_warnings(record=True) as caught:
|
|
60
64
|
warnings.simplefilter("always")
|
|
61
65
|
ChatExtension(ext, tool_name="legacy_name", description="legacy")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
tool_name_deprecations = [
|
|
67
|
+
w for w in caught
|
|
68
|
+
if issubclass(w.category, DeprecationWarning) and "tool_name" in str(w.message)
|
|
69
|
+
]
|
|
70
|
+
assert not tool_name_deprecations, (
|
|
71
|
+
"ChatExtension(tool_name=...) must NOT emit a tool_name DeprecationWarning; "
|
|
72
|
+
f"got: {[str(w.message) for w in tool_name_deprecations]}"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_chat_extension_tool_name_optional_defaults_to_app_id():
|
|
77
|
+
"""tool_name is optional — when omitted it derives from the extension app_id
|
|
78
|
+
(``tool_<app_id>_chat``) and is used as the manifest registration key."""
|
|
79
|
+
ext = Extension(app_id="demo3", description="demo ext for default-tool-name test")
|
|
80
|
+
chat = ChatExtension(ext, description="no explicit tool_name")
|
|
81
|
+
assert chat.tool_name == "tool_demo3_chat", (
|
|
82
|
+
f"omitted tool_name must default to tool_<app_id>_chat; got {chat.tool_name!r}"
|
|
65
83
|
)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
f"DeprecationWarning message must reference tool_name and version cutoff; got: {msg}"
|
|
84
|
+
assert "tool_demo3_chat" in ext._chat_extensions, (
|
|
85
|
+
"default tool_name must be registered as the _chat_extensions key"
|
|
69
86
|
)
|