cortexdbai 0.13.0__tar.gz → 0.13.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.
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/COVERAGE.md +3 -1
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/PKG-INFO +49 -11
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/README.md +48 -10
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/__init__.py +1 -1
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/__init__.py +6 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/_transport.py +15 -1
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/auth.py +33 -20
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/client.py +14 -7
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/errors.py +42 -11
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/exceptions.py +27 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/models.py +51 -7
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/access.py +150 -15
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/admin.py +10 -2
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/core.py +16 -9
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/rest.py +14 -2
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/pyproject.toml +1 -1
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/scripts/error_codes.json +22 -8
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/live/test_live_shared_memory.py +13 -3
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_access_api.py +106 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_errors_and_auth.py +23 -3
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/LICENSE +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/ag2/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/ag2/agent.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/ag2/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/agno/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/agno/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/agno/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/autogen/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/autogen/agent.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/autogen/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/beeai/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/beeai/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/beeai/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/camel/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/camel/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/camel/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/controlflow/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/controlflow/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/crewai/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/crewai/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/crewai/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/deepinfra/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/deepinfra/config.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/deepinfra/embeddings.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/deepinfra/openai_compat.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/dify/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/dify/manifest.yaml +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/dify/tool.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/dspy/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/dspy/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/dspy/retriever.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/fireworks/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/fireworks/config.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/fireworks/embeddings.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/fireworks/openai_compat.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/flowise/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/flowise/node.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/google_adk/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/google_adk/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/groq/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/groq/config.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/groq/embeddings.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/groq/openai_compat.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/hermes/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/hermes/provider.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/instructor/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/instructor/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/langchain/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/langchain/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/langchain/retriever.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/langchain/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/langgraph/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/langgraph/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/letta/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/letta/storage.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/llamaindex/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/llamaindex/memory.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/nemo_guardrails/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/nemo_guardrails/actions.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/nemo_guardrails/knowledge_base.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/ollama/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/ollama/config.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/ollama/embeddings.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/openai_agents/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/openai_agents/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/prefect/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/prefect/blocks.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/prefect/tasks.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/pydanticai/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/pydanticai/dependencies.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/pydanticai/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/smolagents/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/smolagents/tools.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/temporal/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/temporal/activities.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/temporal/interceptor.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/together/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/together/config.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/together/embeddings.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/together/openai_compat.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/vllm/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/vllm/config.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/vllm/embeddings.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/integrations/vllm/openai_compat.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/py.typed +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/_wire.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/consistency.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/diagnostics.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/fragments.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/code.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/erasure.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/native.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/org.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/ops/scim.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/records.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/cortexdb/v1/source.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/scripts/generate_errors.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/scripts/generate_models.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/_harness.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/conftest.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/live/__init__.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/live/conftest.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_admin_and_rest.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_admin_retention.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_answer_unavailable.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_client_parity.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_code_namespace.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_conflicts.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_consistency.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_delete_blob.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_erasures_forget.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_integration_write_barriers.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_matched_fragments.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_org_routes.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_read_write_fields.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_readme_examples.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_recall_hints_capabilities.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_scim.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_signup.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_source.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_streams.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_unknown_method_guidance.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_v093_surfaces.py +0 -0
- {cortexdbai-0.13.0 → cortexdbai-0.13.1}/tests/test_with_options.py +0 -0
|
@@ -320,8 +320,10 @@ Before the 0.14.0 work (`cortexdbai` 0.12.0), 67 operations were reached, 49 of
|
|
|
320
320
|
| `idempotency_key` on a declared belief; `owner` on `POST /v1/scopes`; `scope` on a temporal phrase; `batch_id` on the lifecycle stream | those routes | `idempotency_key=`, `owner=`, `scope=`, `batch_id=` | covered |
|
|
321
321
|
| `events_under_legal_hold`, `derived_under_legal_hold`, and `matched` counting what a hold kept | `POST /v1/forget`, `/v1/forget/preview` | in the answer (documented on both methods) | covered |
|
|
322
322
|
| `in_band`, `in_band_parts` of a change set's preview; the operator key's in-band activation under `deny` (`BREAK_GLASS_REQUIRED` class `in_band`, `NOTICE_UNAVAILABLE`, `REGISTRY_STALE`) | `POST /v1/access/changes/{id}/preview`, `/activate` | `ChangeSetPreview` in `cortexdb.v1.models`; `client.break_glass(...).changeset_activate(...)` | covered |
|
|
323
|
+
| A change set's 202 while its evaluation runs (0.14.1; `Retry-After`, a preview's `{state: "previewing"}`) | `POST /v1/access/changes`, `/{id}/parts`, `/{id}/preview`, `/{id}/activate` | sent again after `Retry-After` for at most `wait` seconds (`CHANGESET_WAIT_SECONDS`), then `V1EvaluationPendingError`; `wait=0` returns `EvaluationPending` | covered |
|
|
324
|
+
| `operator_plane` of a tenant binding, its dry run's included (0.14.1) | `POST /v1/admin/access/tenant-binding` | `TenantBindingResponse` in `cortexdb.v1.models`; `admin_tenant_binding` | covered |
|
|
323
325
|
| `deployment_mode` (`tenant_access_settings_v1`) | `GET`, `PUT /v1/admin/access/tenant-settings`; the access report's `tenant_settings` | `TenantAccessSettings` in `cortexdb.v1.models` | covered |
|
|
324
326
|
| `resend` of a write status (`"no"` for a failed write, never re-sent; `"new_key"` gone) | `GET /v1/experience/status` | `write_status(...)`; `IndexingFailedError` says never to re-send | covered |
|
|
325
327
|
| An omitted `X-Cortex-Actor` (issuers-file `prefix`, `hash` and `directory` tokens; SCIM clients) | every route | `actor=None`, `with_options(actor=None)`; derived from a token's `sub` when no `actor` is given (none for a mapped subject) | covered |
|
|
326
328
|
| `view` left to the server (granular at an org tree's shared scope) | `/v1/recall`, `/v1/answer`, `/v1/compose` | `view=None` (the default) | covered |
|
|
327
|
-
| Typed errors with `retriable` and `details` | every route | one class per code (`cortexdb.v1.errors`,
|
|
329
|
+
| Typed errors with `retriable` and `details` | every route | one class per code (`cortexdb.v1.errors`, 363 codes from `scripts/error_codes.json`, built from the error catalog, `docs/API_REFERENCE_V1.md` §16) under status-family classes; documented `details` keys as properties; `retry_after` | covered |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cortexdbai
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.1
|
|
4
4
|
Summary: The Long-Term Memory Layer for AI Systems
|
|
5
5
|
Project-URL: Homepage, https://cortexdb.ai
|
|
6
6
|
Project-URL: Documentation, https://docs.cortexdb.ai
|
|
@@ -319,6 +319,27 @@ sending it, with the code the server would answer. A value a route always
|
|
|
319
319
|
refuses (an `extra_scopes` list past 40, a malformed break-glass header, a mint
|
|
320
320
|
the server never accepts) raises `ValueError` before anything is sent.
|
|
321
321
|
|
|
322
|
+
## What's new in 0.13.1 for CortexDB 0.14.1
|
|
323
|
+
|
|
324
|
+
- **Long change-set evaluations are waited for.** A staging, a preview or an
|
|
325
|
+
activation whose evaluation runs past the server's own wait answers 202
|
|
326
|
+
with `Retry-After`; each change-set method sends the same call again until
|
|
327
|
+
the answer comes, for at most `wait` seconds (120 by default,
|
|
328
|
+
`CHANGESET_WAIT_SECONDS`; `changeset_apply`'s bounds its three steps
|
|
329
|
+
together), then raises `V1EvaluationPendingError`. `wait=0` returns the
|
|
330
|
+
raw 202 as an `EvaluationPending`. The preview waited 60 s by default.
|
|
331
|
+
- **A version downgrade names what it drops**: `INVALID_ACCESS_RECORD` (a
|
|
332
|
+
change set without `convert`) or `INVALID_SCOPE_TREE` (a legacy registry
|
|
333
|
+
write), `reason == "version_downgrade"`, with `path` and `dropped`.
|
|
334
|
+
- **A tenant binding's dry run** answers `operator_plane`
|
|
335
|
+
`{registers_root, in_band, mode, break_glass_required}`.
|
|
336
|
+
- **Lifetime ceilings are the server's settings**: `lifetime_ceiling()` gives
|
|
337
|
+
the defaults, now 90 days for a person (a week for an agent, 30 days for a
|
|
338
|
+
service, a day for a chain token), `admin_metrics()["auth"]
|
|
339
|
+
["lifetime_ceilings"]` the server's own, and `check_mint` leaves a chain
|
|
340
|
+
token's lifetime to the server. `InvalidBodyError` and
|
|
341
|
+
`InvalidTokenClaimError` read `lifetime_s` and `ceiling_s`.
|
|
342
|
+
|
|
322
343
|
## What's new in 0.13.0 for CortexDB 0.14.0
|
|
323
344
|
|
|
324
345
|
`cortexdbai` 0.13.0 covers the whole v1 API of CortexDB 0.14.0
|
|
@@ -478,8 +499,20 @@ print(status["state"], status["consistency_token"][:4]) # activated ct1.
|
|
|
478
499
|
A refusal raises its typed error: `PREVIEW_CHANGED` (the registry moved since
|
|
479
500
|
the preview), `ACCESS_ASSERTION_FAILED` (a widening breaks one of the tenant's
|
|
480
501
|
policy cases), `CHANGESET_STALE` (a record changed after staging),
|
|
481
|
-
`ACCESS_LIMIT_REACHED
|
|
482
|
-
|
|
502
|
+
`ACCESS_LIMIT_REACHED`, and since 0.14.1 `INVALID_ACCESS_RECORD` with
|
|
503
|
+
`reason == "version_downgrade"` for a put that would make a version-2 record a
|
|
504
|
+
version-1 one (`err.dropped` lists the stored record's version-2 fields the put
|
|
505
|
+
leaves out: state them, or stage with `convert=True`). `changeset_get` and
|
|
506
|
+
`changeset_discard` read and drop a staged change set.
|
|
507
|
+
|
|
508
|
+
A large evaluation can run past the server's own wait (20 s by default): from
|
|
509
|
+
0.14.1 a staging, a preview or an activation then answers 202 with
|
|
510
|
+
`Retry-After`, and each method sends the same call again until the answer
|
|
511
|
+
comes, for at most `wait` seconds in all (`CHANGESET_WAIT_SECONDS`, 120, by
|
|
512
|
+
default; `changeset_apply`'s `wait` bounds its three steps together). Past it
|
|
513
|
+
the method raises `V1EvaluationPendingError`, and the same call sent again
|
|
514
|
+
joins the evaluation. `wait=0` returns the first answer as it came, a 202 as
|
|
515
|
+
an `EvaluationPending` (its body, `status` and `retry_after`).
|
|
483
516
|
|
|
484
517
|
Under a tenant whose operator mode is `deny`, the operator key's activation of
|
|
485
518
|
a change set that registers a record, names a `service:` principal or widens
|
|
@@ -917,20 +950,25 @@ principal; its chain fields say who is acting for whom: `act` (an agent acting
|
|
|
917
950
|
for the subject; it writes only with a `run`), `app` and `client` (an
|
|
918
951
|
application, and whether a person or an agent drives it), `run` and
|
|
919
952
|
`run_start`, and `taint` tags. `mint_agent_token` and `mint_app_token` mint
|
|
920
|
-
the two common chains. A token with a chain field lives at most a day
|
|
921
|
-
(`CHAIN_TOKEN_MAX_TTL_SECONDS`), and an agent chain token names its
|
|
922
|
-
with `scopes` that confine each; the SDK refuses before sending what
|
|
923
|
-
server always refuses (`check_mint`, a `ValueError`). Other tokens live at
|
|
924
|
-
most `lifetime_ceiling(subject)`:
|
|
925
|
-
a
|
|
926
|
-
|
|
953
|
+
the two common chains. A token with a chain field lives at most a day by
|
|
954
|
+
default (`CHAIN_TOKEN_MAX_TTL_SECONDS`), and an agent chain token names its
|
|
955
|
+
`caps` with `scopes` that confine each; the SDK refuses before sending what
|
|
956
|
+
the server always refuses (`check_mint`, a `ValueError`). Other tokens live at
|
|
957
|
+
most their kind's ceiling, by default `lifetime_ceiling(subject)`: 90 days for
|
|
958
|
+
a person (a week on a 0.14.0 server), a week for an agent, 30 days for a
|
|
959
|
+
service. Since 0.14.1 each ceiling is a server setting
|
|
960
|
+
(`CORTEX_MINT_MAX_LIFETIME_PERSON`, `_AGENT`, `_SERVICE`, `_CHAIN`):
|
|
961
|
+
`admin_metrics()["auth"]["lifetime_ceilings"]` reports the server's, and a
|
|
962
|
+
mint over one is 422 `INVALID_BODY` `ttl_too_long` with `ceiling_s`.
|
|
963
|
+
`with_token` derives a client that uses another token over the same
|
|
964
|
+
connections.
|
|
927
965
|
|
|
928
966
|
<!-- example: tokens -->
|
|
929
967
|
```python
|
|
930
968
|
from cortexdb.v1 import lifetime_ceiling
|
|
931
969
|
|
|
932
970
|
erin = Cortex(URL, bearer=operator.mint_token(subject="user:erin", scope=ROOT)["token"])
|
|
933
|
-
print(erin.actor, lifetime_ceiling("user:erin")) # user:erin
|
|
971
|
+
print(erin.actor, lifetime_ceiling("user:erin")) # user:erin 7776000
|
|
934
972
|
|
|
935
973
|
home = f"{ROOT}/user:alice"
|
|
936
974
|
planner = alice.with_token(alice.mint_agent_token(
|
|
@@ -204,6 +204,27 @@ sending it, with the code the server would answer. A value a route always
|
|
|
204
204
|
refuses (an `extra_scopes` list past 40, a malformed break-glass header, a mint
|
|
205
205
|
the server never accepts) raises `ValueError` before anything is sent.
|
|
206
206
|
|
|
207
|
+
## What's new in 0.13.1 for CortexDB 0.14.1
|
|
208
|
+
|
|
209
|
+
- **Long change-set evaluations are waited for.** A staging, a preview or an
|
|
210
|
+
activation whose evaluation runs past the server's own wait answers 202
|
|
211
|
+
with `Retry-After`; each change-set method sends the same call again until
|
|
212
|
+
the answer comes, for at most `wait` seconds (120 by default,
|
|
213
|
+
`CHANGESET_WAIT_SECONDS`; `changeset_apply`'s bounds its three steps
|
|
214
|
+
together), then raises `V1EvaluationPendingError`. `wait=0` returns the
|
|
215
|
+
raw 202 as an `EvaluationPending`. The preview waited 60 s by default.
|
|
216
|
+
- **A version downgrade names what it drops**: `INVALID_ACCESS_RECORD` (a
|
|
217
|
+
change set without `convert`) or `INVALID_SCOPE_TREE` (a legacy registry
|
|
218
|
+
write), `reason == "version_downgrade"`, with `path` and `dropped`.
|
|
219
|
+
- **A tenant binding's dry run** answers `operator_plane`
|
|
220
|
+
`{registers_root, in_band, mode, break_glass_required}`.
|
|
221
|
+
- **Lifetime ceilings are the server's settings**: `lifetime_ceiling()` gives
|
|
222
|
+
the defaults, now 90 days for a person (a week for an agent, 30 days for a
|
|
223
|
+
service, a day for a chain token), `admin_metrics()["auth"]
|
|
224
|
+
["lifetime_ceilings"]` the server's own, and `check_mint` leaves a chain
|
|
225
|
+
token's lifetime to the server. `InvalidBodyError` and
|
|
226
|
+
`InvalidTokenClaimError` read `lifetime_s` and `ceiling_s`.
|
|
227
|
+
|
|
207
228
|
## What's new in 0.13.0 for CortexDB 0.14.0
|
|
208
229
|
|
|
209
230
|
`cortexdbai` 0.13.0 covers the whole v1 API of CortexDB 0.14.0
|
|
@@ -363,8 +384,20 @@ print(status["state"], status["consistency_token"][:4]) # activated ct1.
|
|
|
363
384
|
A refusal raises its typed error: `PREVIEW_CHANGED` (the registry moved since
|
|
364
385
|
the preview), `ACCESS_ASSERTION_FAILED` (a widening breaks one of the tenant's
|
|
365
386
|
policy cases), `CHANGESET_STALE` (a record changed after staging),
|
|
366
|
-
`ACCESS_LIMIT_REACHED
|
|
367
|
-
|
|
387
|
+
`ACCESS_LIMIT_REACHED`, and since 0.14.1 `INVALID_ACCESS_RECORD` with
|
|
388
|
+
`reason == "version_downgrade"` for a put that would make a version-2 record a
|
|
389
|
+
version-1 one (`err.dropped` lists the stored record's version-2 fields the put
|
|
390
|
+
leaves out: state them, or stage with `convert=True`). `changeset_get` and
|
|
391
|
+
`changeset_discard` read and drop a staged change set.
|
|
392
|
+
|
|
393
|
+
A large evaluation can run past the server's own wait (20 s by default): from
|
|
394
|
+
0.14.1 a staging, a preview or an activation then answers 202 with
|
|
395
|
+
`Retry-After`, and each method sends the same call again until the answer
|
|
396
|
+
comes, for at most `wait` seconds in all (`CHANGESET_WAIT_SECONDS`, 120, by
|
|
397
|
+
default; `changeset_apply`'s `wait` bounds its three steps together). Past it
|
|
398
|
+
the method raises `V1EvaluationPendingError`, and the same call sent again
|
|
399
|
+
joins the evaluation. `wait=0` returns the first answer as it came, a 202 as
|
|
400
|
+
an `EvaluationPending` (its body, `status` and `retry_after`).
|
|
368
401
|
|
|
369
402
|
Under a tenant whose operator mode is `deny`, the operator key's activation of
|
|
370
403
|
a change set that registers a record, names a `service:` principal or widens
|
|
@@ -802,20 +835,25 @@ principal; its chain fields say who is acting for whom: `act` (an agent acting
|
|
|
802
835
|
for the subject; it writes only with a `run`), `app` and `client` (an
|
|
803
836
|
application, and whether a person or an agent drives it), `run` and
|
|
804
837
|
`run_start`, and `taint` tags. `mint_agent_token` and `mint_app_token` mint
|
|
805
|
-
the two common chains. A token with a chain field lives at most a day
|
|
806
|
-
(`CHAIN_TOKEN_MAX_TTL_SECONDS`), and an agent chain token names its
|
|
807
|
-
with `scopes` that confine each; the SDK refuses before sending what
|
|
808
|
-
server always refuses (`check_mint`, a `ValueError`). Other tokens live at
|
|
809
|
-
most `lifetime_ceiling(subject)`:
|
|
810
|
-
a
|
|
811
|
-
|
|
838
|
+
the two common chains. A token with a chain field lives at most a day by
|
|
839
|
+
default (`CHAIN_TOKEN_MAX_TTL_SECONDS`), and an agent chain token names its
|
|
840
|
+
`caps` with `scopes` that confine each; the SDK refuses before sending what
|
|
841
|
+
the server always refuses (`check_mint`, a `ValueError`). Other tokens live at
|
|
842
|
+
most their kind's ceiling, by default `lifetime_ceiling(subject)`: 90 days for
|
|
843
|
+
a person (a week on a 0.14.0 server), a week for an agent, 30 days for a
|
|
844
|
+
service. Since 0.14.1 each ceiling is a server setting
|
|
845
|
+
(`CORTEX_MINT_MAX_LIFETIME_PERSON`, `_AGENT`, `_SERVICE`, `_CHAIN`):
|
|
846
|
+
`admin_metrics()["auth"]["lifetime_ceilings"]` reports the server's, and a
|
|
847
|
+
mint over one is 422 `INVALID_BODY` `ttl_too_long` with `ceiling_s`.
|
|
848
|
+
`with_token` derives a client that uses another token over the same
|
|
849
|
+
connections.
|
|
812
850
|
|
|
813
851
|
<!-- example: tokens -->
|
|
814
852
|
```python
|
|
815
853
|
from cortexdb.v1 import lifetime_ceiling
|
|
816
854
|
|
|
817
855
|
erin = Cortex(URL, bearer=operator.mint_token(subject="user:erin", scope=ROOT)["token"])
|
|
818
|
-
print(erin.actor, lifetime_ceiling("user:erin")) # user:erin
|
|
856
|
+
print(erin.actor, lifetime_ceiling("user:erin")) # user:erin 7776000
|
|
819
857
|
|
|
820
858
|
home = f"{ROOT}/user:alice"
|
|
821
859
|
planner = alice.with_token(alice.mint_agent_token(
|
|
@@ -51,6 +51,7 @@ from cortexdb.v1.exceptions import (
|
|
|
51
51
|
V1ConflictError,
|
|
52
52
|
V1ConnectionError,
|
|
53
53
|
V1Error,
|
|
54
|
+
V1EvaluationPendingError,
|
|
54
55
|
V1GoneError,
|
|
55
56
|
V1InvalidRequestError,
|
|
56
57
|
V1MisdirectedRequestError,
|
|
@@ -94,6 +95,8 @@ from cortexdb.v1._transport import StreamEvent
|
|
|
94
95
|
from cortexdb.v1.consistency import ConsistencyTokens
|
|
95
96
|
from cortexdb.v1.ops.access import (
|
|
96
97
|
ACCESS_ROLES,
|
|
98
|
+
CHANGESET_WAIT_SECONDS,
|
|
99
|
+
EvaluationPending,
|
|
97
100
|
authzen_subject,
|
|
98
101
|
changeset_part,
|
|
99
102
|
delete_record,
|
|
@@ -133,6 +136,8 @@ __all__ = [
|
|
|
133
136
|
"StreamEvent",
|
|
134
137
|
"ConsistencyTokens",
|
|
135
138
|
"ACCESS_ROLES",
|
|
139
|
+
"CHANGESET_WAIT_SECONDS",
|
|
140
|
+
"EvaluationPending",
|
|
136
141
|
"authzen_subject",
|
|
137
142
|
"changeset_part",
|
|
138
143
|
"delete_record",
|
|
@@ -165,6 +170,7 @@ __all__ = [
|
|
|
165
170
|
"V1ServerError",
|
|
166
171
|
"V1ServerTimeoutError",
|
|
167
172
|
"V1TimeoutError",
|
|
173
|
+
"V1EvaluationPendingError",
|
|
168
174
|
"V1RateLimitError",
|
|
169
175
|
"V1NotConfiguredError",
|
|
170
176
|
"V1PolicyDeniedError",
|
|
@@ -77,12 +77,26 @@ class Poll:
|
|
|
77
77
|
|
|
78
78
|
The wait between attempts is the response's ``Retry-After`` (seconds),
|
|
79
79
|
else ``interval``; the last attempt starts before ``timeout`` seconds have
|
|
80
|
-
passed
|
|
80
|
+
passed. ``pending`` narrows which answers of ``statuses`` are sent again
|
|
81
|
+
for (default: every one). An answer still pending once ``timeout`` has
|
|
82
|
+
passed is handed to ``expired`` with the seconds waited, when it is set;
|
|
83
|
+
otherwise it is returned as any other answer is.
|
|
81
84
|
"""
|
|
82
85
|
|
|
83
86
|
statuses: frozenset
|
|
84
87
|
timeout: float = 60.0
|
|
85
88
|
interval: float = 1.0
|
|
89
|
+
pending: Optional[Callable[["Response"], bool]] = None
|
|
90
|
+
expired: Optional[Callable[["Response", float], Any]] = None
|
|
91
|
+
|
|
92
|
+
def again(self, response: "Response") -> bool:
|
|
93
|
+
"""Whether ``response`` is one to send the request again for."""
|
|
94
|
+
return response.status in self.statuses and (self.pending is None or self.pending(response))
|
|
95
|
+
|
|
96
|
+
def pause(self, response: "Response") -> float:
|
|
97
|
+
"""Seconds to wait before the next attempt: ``Retry-After``, else ``interval``."""
|
|
98
|
+
seconds = retry_after_seconds(response)
|
|
99
|
+
return self.interval if seconds is None else seconds
|
|
86
100
|
|
|
87
101
|
|
|
88
102
|
#: How a consistency tracker may extend a request (see
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Credentials and operator headers (CortexDB 0.14.0).
|
|
1
|
+
"""Credentials and operator headers (CortexDB 0.14.0 and 0.14.1).
|
|
2
2
|
|
|
3
3
|
* :func:`break_glass_header` builds ``X-Cortex-Break-Glass``
|
|
4
4
|
(``operator_break_glass_v1``): ``reason=<reason>; ticket=<ticket>[;
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
derives ``X-Cortex-Actor`` from a token's ``sub`` when no actor is given.
|
|
12
12
|
* :func:`check_mint` holds a mint request to the rules the server always
|
|
13
13
|
applies to the chain fields (``mint_chain_v1``), and
|
|
14
|
-
:func:`lifetime_ceiling` gives the lifetime ceiling of a
|
|
14
|
+
:func:`lifetime_ceiling` gives the server's default lifetime ceiling of a
|
|
15
|
+
subject's kind (each a server setting since 0.14.1).
|
|
15
16
|
"""
|
|
16
17
|
|
|
17
18
|
from __future__ import annotations
|
|
@@ -34,15 +35,22 @@ _TICKET = re.compile(r"^[A-Za-z0-9._:-]{1,64}$")
|
|
|
34
35
|
_ACTOR = re.compile(r"^(user|agent|service|system):[A-Za-z0-9_.@-]{1,128}$")
|
|
35
36
|
|
|
36
37
|
#: The longest a token minted with a chain field (``act``, ``app``,
|
|
37
|
-
#: ``client``, ``run``, ``run_start``, ``taint``) lives, in
|
|
38
|
+
#: ``client``, ``run``, ``run_start``, ``taint``) lives by default, in
|
|
39
|
+
#: seconds: a day. Since 0.14.1 the server's ``CORTEX_MINT_MAX_LIFETIME_CHAIN``
|
|
40
|
+
#: sets it, whatever ``CORTEX_MINT_LIFETIME_ENFORCE`` says.
|
|
38
41
|
CHAIN_TOKEN_MAX_TTL_SECONDS = 86_400
|
|
39
|
-
#: The lifetime ceiling of a minted token by its subject's kind, in
|
|
40
|
-
#:
|
|
41
|
-
#:
|
|
42
|
-
#:
|
|
43
|
-
#: ``
|
|
42
|
+
#: The default lifetime ceiling of a minted token by its subject's kind, in
|
|
43
|
+
#: seconds: 90 days for a person (``user:``; 7 days on a 0.14.0 server), a
|
|
44
|
+
#: week for an agent, 30 days for a service or the system. Since 0.14.1 each
|
|
45
|
+
#: is a server setting (``CORTEX_MINT_MAX_LIFETIME_PERSON``, ``_AGENT``,
|
|
46
|
+
#: ``_SERVICE``), and ``admin_metrics()["auth"]["lifetime_ceilings"]``
|
|
47
|
+
#: reports the ones a server runs with. The server enforces them unless its
|
|
48
|
+
#: ``CORTEX_MINT_LIFETIME_ENFORCE`` is ``off`` (422 ``INVALID_BODY``
|
|
49
|
+
#: ``ttl_too_long`` at the mint, with ``details.lifetime_s`` and
|
|
50
|
+
#: ``details.ceiling_s``; 401 ``INVALID_TOKEN_CLAIM`` ``lifetime_over_ceiling``
|
|
51
|
+
#: for a token over it).
|
|
44
52
|
LIFETIME_CEILING_SECONDS = {
|
|
45
|
-
"user":
|
|
53
|
+
"user": 7_776_000, "agent": 604_800, "service": 2_592_000, "system": 2_592_000,
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
|
|
@@ -116,9 +124,13 @@ def is_actor_id(value: Any) -> bool:
|
|
|
116
124
|
|
|
117
125
|
|
|
118
126
|
def lifetime_ceiling(subject: str) -> int:
|
|
119
|
-
"""The lifetime ceiling, in seconds, of a token minted
|
|
120
|
-
(:data:`LIFETIME_CEILING_SECONDS`), before any chain
|
|
121
|
-
:data:`CHAIN_TOKEN_MAX_TTL_SECONDS
|
|
127
|
+
"""The server's default lifetime ceiling, in seconds, of a token minted
|
|
128
|
+
for ``subject`` (:data:`LIFETIME_CEILING_SECONDS`), before any chain
|
|
129
|
+
field lowers it to the chain ceiling (:data:`CHAIN_TOKEN_MAX_TTL_SECONDS`
|
|
130
|
+
by default). A server may set each otherwise (0.14.1,
|
|
131
|
+
``CORTEX_MINT_MAX_LIFETIME_*``): ``admin_metrics()["auth"]
|
|
132
|
+
["lifetime_ceilings"]`` says what it runs with, and its refusal names
|
|
133
|
+
the ceiling (``details.ceiling_s``)."""
|
|
122
134
|
kind = subject.split(":", 1)[0]
|
|
123
135
|
if kind not in LIFETIME_CEILING_SECONDS:
|
|
124
136
|
raise ValueError(f"not a principal id (user:, agent:, service:, system:): {subject!r}")
|
|
@@ -143,19 +155,20 @@ def check_mint(
|
|
|
143
155
|
``agent:`` id other than the subject; ``app`` a ``service:`` id;
|
|
144
156
|
``client`` ``"person"`` or ``"agent"``, and ``"person"`` never beside
|
|
145
157
|
``act`` or ``run``; ``run`` 1 to 128 bytes and ``run_start`` only with
|
|
146
|
-
it; each ``taint`` tag 1 to 64 bytes;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
it; each ``taint`` tag 1 to 64 bytes; and an agent chain token (``act``
|
|
159
|
+
or ``run``, or ``app`` without ``client="person"``, or
|
|
160
|
+
``client="agent"``) names its ``caps`` with ``scopes`` that confine them.
|
|
161
|
+
What the server checks against its settings or its state it answers
|
|
162
|
+
itself: the lifetime ceilings, the chain ceiling included (a day by
|
|
163
|
+
default, ``CORTEX_MINT_MAX_LIFETIME_CHAIN`` since 0.14.1: 422
|
|
164
|
+
``INVALID_BODY`` ``ttl_too_long`` with ``details.lifetime_s`` and
|
|
165
|
+
``details.ceiling_s``), an Owner of the application,
|
|
166
|
+
``auth.mint.on_behalf_of``, an AI employee named in ``act``."""
|
|
152
167
|
if not is_actor_id(subject):
|
|
153
168
|
raise ValueError(f"not a principal id (user:, agent:, service:, system:): {subject!r}")
|
|
154
169
|
chain = any(v is not None for v in (act, app, client, run, run_start, taint))
|
|
155
170
|
if not chain:
|
|
156
171
|
return
|
|
157
|
-
if max(int(ttl_seconds), 60) > CHAIN_TOKEN_MAX_TTL_SECONDS:
|
|
158
|
-
raise ValueError("a token that carries a chain field lives at most 86400 s (ttl_too_long)")
|
|
159
172
|
if act is not None:
|
|
160
173
|
if not (is_actor_id(act) and act.startswith("agent:")):
|
|
161
174
|
raise ValueError("act is an agent: id (not_an_agent)")
|
|
@@ -41,7 +41,6 @@ from cortexdb.v1._transport import (
|
|
|
41
41
|
async_stream_op,
|
|
42
42
|
dig,
|
|
43
43
|
page_spec,
|
|
44
|
-
retry_after_seconds,
|
|
45
44
|
sync_op,
|
|
46
45
|
sync_proc,
|
|
47
46
|
sync_stream_op,
|
|
@@ -549,14 +548,18 @@ class _SyncTransport(_ClientCore):
|
|
|
549
548
|
return self._send_polling(req)
|
|
550
549
|
|
|
551
550
|
def _send_polling(self, req: Request) -> Any:
|
|
552
|
-
|
|
551
|
+
poll = req.poll
|
|
552
|
+
start = time.monotonic()
|
|
553
|
+
deadline = start + (poll.timeout if poll else 0.0)
|
|
553
554
|
while True:
|
|
554
555
|
resp = self._send(req)
|
|
555
|
-
if
|
|
556
|
-
wait =
|
|
556
|
+
if poll and poll.again(resp):
|
|
557
|
+
wait = poll.pause(resp)
|
|
557
558
|
if time.monotonic() + wait < deadline:
|
|
558
559
|
time.sleep(wait)
|
|
559
560
|
continue
|
|
561
|
+
if poll.expired is not None:
|
|
562
|
+
return poll.expired(resp, time.monotonic() - start)
|
|
560
563
|
return _finish(req, resp)
|
|
561
564
|
|
|
562
565
|
def _send(self, req: Request, *, stream: bool = False) -> Any:
|
|
@@ -1031,14 +1034,18 @@ class _AsyncTransport(_ClientCore):
|
|
|
1031
1034
|
return await self._send_polling(req)
|
|
1032
1035
|
|
|
1033
1036
|
async def _send_polling(self, req: Request) -> Any:
|
|
1034
|
-
|
|
1037
|
+
poll = req.poll
|
|
1038
|
+
start = time.monotonic()
|
|
1039
|
+
deadline = start + (poll.timeout if poll else 0.0)
|
|
1035
1040
|
while True:
|
|
1036
1041
|
resp = await self._send(req)
|
|
1037
|
-
if
|
|
1038
|
-
wait =
|
|
1042
|
+
if poll and poll.again(resp):
|
|
1043
|
+
wait = poll.pause(resp)
|
|
1039
1044
|
if time.monotonic() + wait < deadline:
|
|
1040
1045
|
await asyncio.sleep(wait)
|
|
1041
1046
|
continue
|
|
1047
|
+
if poll.expired is not None:
|
|
1048
|
+
return poll.expired(resp, time.monotonic() - start)
|
|
1042
1049
|
return _finish(req, resp)
|
|
1043
1050
|
|
|
1044
1051
|
def _httpx_args(self, req: Request) -> Dict[str, Any]:
|
|
@@ -2010,17 +2010,21 @@ class InvalidAccessRecordError(V1ValidationError):
|
|
|
2010
2010
|
change set's record, an application record (``PUT /v1/apps/{id}``), a registry write, or an
|
|
2011
2011
|
edit of an application's reference root, whose shape is fixed (``reason: reference_root``);
|
|
2012
2012
|
a ``when: {purpose}`` id outside a read's ``purpose`` grammar on a roster entry, a set entry
|
|
2013
|
-
or a unit grant is ``reason: when_purpose``;
|
|
2013
|
+
or a unit grant is ``reason: when_purpose``; a change set's put that would make a version-2
|
|
2014
|
+
record a version-1 one, without ``convert``, is ``reason: version_downgrade`` with
|
|
2015
|
+
``details.dropped`` (since 0.14.1); ``details.path``, ``details.reason``.
|
|
2014
2016
|
|
|
2015
|
-
Fix the record; ``details.path`` and ``details.reason`` say what.
|
|
2017
|
+
Fix the record; ``details.path`` and ``details.reason`` say what. For ``version_downgrade``,
|
|
2018
|
+
state the fields ``details.dropped`` names, or say ``convert``.
|
|
2016
2019
|
|
|
2017
|
-
``details``: ``path``, ``reason``.
|
|
2020
|
+
``details``: ``path``, ``reason``, ``dropped``.
|
|
2018
2021
|
"""
|
|
2019
2022
|
|
|
2020
2023
|
CODE = "INVALID_ACCESS_RECORD"
|
|
2021
2024
|
STATUS = 422
|
|
2022
2025
|
RETRIABLE = False
|
|
2023
2026
|
path = _detail("path")
|
|
2027
|
+
dropped = _detail("dropped")
|
|
2024
2028
|
|
|
2025
2029
|
|
|
2026
2030
|
class InvalidAuditError(V1ValidationError):
|
|
@@ -2043,7 +2047,7 @@ class InvalidBodyError(V1ValidationError):
|
|
|
2043
2047
|
``details.reason`` where known.
|
|
2044
2048
|
|
|
2045
2049
|
``details``: ``part``, ``reason``, ``field``, ``unsupported_fields``,
|
|
2046
|
-
``required_capabilities``, ``field_path``, ``entry``.
|
|
2050
|
+
``required_capabilities``, ``field_path``, ``entry``, ``lifetime_s``, ``ceiling_s``.
|
|
2047
2051
|
"""
|
|
2048
2052
|
|
|
2049
2053
|
CODE = "INVALID_BODY"
|
|
@@ -2055,6 +2059,8 @@ class InvalidBodyError(V1ValidationError):
|
|
|
2055
2059
|
required_capabilities = _detail("required_capabilities")
|
|
2056
2060
|
field_path = _detail("field_path")
|
|
2057
2061
|
entry = _detail("entry")
|
|
2062
|
+
lifetime_s = _detail("lifetime_s")
|
|
2063
|
+
ceiling_s = _detail("ceiling_s")
|
|
2058
2064
|
|
|
2059
2065
|
|
|
2060
2066
|
class InvalidBoundaryError(V1ValidationError):
|
|
@@ -2400,15 +2406,19 @@ class InvalidScopeGrammarError(V1ValidationError):
|
|
|
2400
2406
|
class InvalidScopeTreeError(V1ValidationError):
|
|
2401
2407
|
"""422 ``INVALID_SCOPE_TREE`` (not retriable). Org-tree attributes out of their rules (0.13.0):
|
|
2402
2408
|
``details.reason`` names the rule, ``details.field`` the field (``tree.display_name`` is
|
|
2403
|
-
refused under ``CORTEX_DISPLAY_NAME_IN_RECORD_ENFORCE``: put the name in the directory)
|
|
2409
|
+
refused under ``CORTEX_DISPLAY_NAME_IN_RECORD_ENFORCE``: put the name in the directory);
|
|
2410
|
+
since 0.14.1 also a legacy registry write that would make a version-2 record a version-1
|
|
2411
|
+
one, ``reason: version_downgrade``, with ``details.path`` and ``details.dropped``.
|
|
2404
2412
|
|
|
2405
|
-
``details``: ``reason``, ``field``.
|
|
2413
|
+
``details``: ``reason``, ``field``, ``path``, ``dropped``.
|
|
2406
2414
|
"""
|
|
2407
2415
|
|
|
2408
2416
|
CODE = "INVALID_SCOPE_TREE"
|
|
2409
2417
|
STATUS = 422
|
|
2410
2418
|
RETRIABLE = False
|
|
2411
2419
|
field = _detail("field")
|
|
2420
|
+
path = _detail("path")
|
|
2421
|
+
dropped = _detail("dropped")
|
|
2412
2422
|
|
|
2413
2423
|
|
|
2414
2424
|
class InvalidSubtreeError(V1BadRequestError):
|
|
@@ -2469,7 +2479,7 @@ class InvalidTokenClaimError(V1AuthError):
|
|
|
2469
2479
|
|
|
2470
2480
|
Mint a correct token; an AI employee runs as itself, never through ``act``.
|
|
2471
2481
|
|
|
2472
|
-
``details``: ``claim``, ``reason``, ``issuer``.
|
|
2482
|
+
``details``: ``claim``, ``reason``, ``issuer``, ``lifetime_s``, ``ceiling_s``.
|
|
2473
2483
|
"""
|
|
2474
2484
|
|
|
2475
2485
|
CODE = "INVALID_TOKEN_CLAIM"
|
|
@@ -2477,6 +2487,8 @@ class InvalidTokenClaimError(V1AuthError):
|
|
|
2477
2487
|
RETRIABLE = False
|
|
2478
2488
|
claim = _detail("claim")
|
|
2479
2489
|
issuer = _detail("issuer")
|
|
2490
|
+
lifetime_s = _detail("lifetime_s")
|
|
2491
|
+
ceiling_s = _detail("ceiling_s")
|
|
2480
2492
|
|
|
2481
2493
|
|
|
2482
2494
|
class InvalidTokenSignatureError(V1AuthError):
|
|
@@ -2866,10 +2878,10 @@ class NoticeUnavailableError(V1UnavailableError):
|
|
|
2866
2878
|
|
|
2867
2879
|
Retriable: yes, but for ``arming_disabled`` and ``reserved_path_in_use``.
|
|
2868
2880
|
|
|
2869
|
-
Retry after the move; nothing was delivered. ``arming_disabled
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2881
|
+
Retry after the move; nothing was delivered. ``arming_disabled`` and
|
|
2882
|
+
``reserved_path_in_use``: not until the operator raises the ceiling, or migrates the scope's
|
|
2883
|
+
events out and deletes the record; ``members_behind``: once every member is armed.
|
|
2884
|
+
``limit``: retry once the age sweep has dropped older notices.
|
|
2873
2885
|
|
|
2874
2886
|
``details``: ``reason``, ``refusal``.
|
|
2875
2887
|
"""
|
|
@@ -3566,6 +3578,23 @@ class RepoScopeInUseError(V1ConflictError):
|
|
|
3566
3578
|
RETRIABLE = False
|
|
3567
3579
|
|
|
3568
3580
|
|
|
3581
|
+
class RequestAbandonedError(V1UnavailableError):
|
|
3582
|
+
"""503 ``REQUEST_ABANDONED`` (retriable). A change set's evaluation stopped: every caller
|
|
3583
|
+
waiting on it went away (since 0.14.1). The change-set routes (``POST /v1/access/changes``,
|
|
3584
|
+
``…/parts``, ``…/preview``, ``…/activate``) and a SCIM Group write's checks answer it once
|
|
3585
|
+
the request's client has gone, and so has every other caller waiting on that evaluation.
|
|
3586
|
+
Nothing was staged or activated. Only a request whose client has gone meets it, so no client
|
|
3587
|
+
reads it.
|
|
3588
|
+
|
|
3589
|
+
None: only a request whose client has gone is answered with it, so no client reads it;
|
|
3590
|
+
nothing was staged or activated.
|
|
3591
|
+
"""
|
|
3592
|
+
|
|
3593
|
+
CODE = "REQUEST_ABANDONED"
|
|
3594
|
+
STATUS = 503
|
|
3595
|
+
RETRIABLE = True
|
|
3596
|
+
|
|
3597
|
+
|
|
3569
3598
|
class RequestTimeoutError(V1ServerTimeoutError):
|
|
3570
3599
|
"""408 ``REQUEST_TIMEOUT`` (not retriable). Cluster ingress: the body did not arrive within
|
|
3571
3600
|
``body_timeout_s``.
|
|
@@ -4937,6 +4966,7 @@ BY_CODE: Dict[str, Type[V1APIError]] = {
|
|
|
4937
4966
|
"REPO_PURGE_PANICKED": RepoPurgePanickedError,
|
|
4938
4967
|
"REPO_REGISTRY_WRITE_FAILED": RepoRegistryWriteFailedError,
|
|
4939
4968
|
"REPO_SCOPE_IN_USE": RepoScopeInUseError,
|
|
4969
|
+
"REQUEST_ABANDONED": RequestAbandonedError,
|
|
4940
4970
|
"REQUEST_TIMEOUT": RequestTimeoutError,
|
|
4941
4971
|
"RESOLVE_FAILED": ResolveFailedError,
|
|
4942
4972
|
"RESOURCE_DELETED": ResourceDeletedError,
|
|
@@ -5302,6 +5332,7 @@ __all__ = [
|
|
|
5302
5332
|
"RepoPurgePanickedError",
|
|
5303
5333
|
"RepoRegistryWriteFailedError",
|
|
5304
5334
|
"RepoScopeInUseError",
|
|
5335
|
+
"RequestAbandonedError",
|
|
5305
5336
|
"RequestTimeoutError",
|
|
5306
5337
|
"ResolveFailedError",
|
|
5307
5338
|
"ResourceDeletedError",
|
|
@@ -66,6 +66,33 @@ class V1TimeoutError(V1Error):
|
|
|
66
66
|
"""Request exceeded the configured client timeout."""
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
class V1EvaluationPendingError(V1TimeoutError):
|
|
70
|
+
"""A change-set call's evaluation still ran when its ``wait`` ran out.
|
|
71
|
+
|
|
72
|
+
Since 0.14.1 a staging, a preview or an activation whose evaluation runs
|
|
73
|
+
past the server's wait answers 202 with ``Retry-After``, and the client
|
|
74
|
+
sends the same call again until it gets its answer, for at most the
|
|
75
|
+
call's ``wait`` seconds. Nothing failed and the work goes on: send the
|
|
76
|
+
same call again (it joins the evaluation, or is answered by it for 60 s
|
|
77
|
+
after it ended), or give it a longer ``wait``. ``method`` and ``path``
|
|
78
|
+
name the call, ``waited`` the seconds it waited, ``retry_after`` the
|
|
79
|
+
last answer's ``Retry-After`` and ``body`` its body (a preview's
|
|
80
|
+
``{"state": "previewing"}``; a staging's and an activation's are empty).
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
def __init__(self, method: str, path: str, waited: float,
|
|
84
|
+
retry_after: Optional[float] = None, body: Any = None) -> None:
|
|
85
|
+
super().__init__(
|
|
86
|
+
f"{method} {path}: the change set's evaluation still runs after {waited:.0f} s "
|
|
87
|
+
"(202); send the same call again, or give it a longer wait"
|
|
88
|
+
)
|
|
89
|
+
self.method = method
|
|
90
|
+
self.path = path
|
|
91
|
+
self.waited = waited
|
|
92
|
+
self.retry_after = retry_after
|
|
93
|
+
self.body = body if body is not None else {}
|
|
94
|
+
|
|
95
|
+
|
|
69
96
|
class V1APIError(V1Error):
|
|
70
97
|
"""Server returned a non-2xx response with a v1 error envelope.
|
|
71
98
|
|