diff --git a/robosystems_client/api/extensions_robo_ledger/promote_obligations.py b/robosystems_client/api/extensions_robo_ledger/promote_obligations.py index 3edea99..f01b4ad 100644 --- a/robosystems_client/api/extensions_robo_ledger/promote_obligations.py +++ b/robosystems_client/api/extensions_robo_ledger/promote_obligations.py @@ -117,10 +117,12 @@ def sync_detailed( Promote matured pending schedule obligations (schedule_entry_due events whose period boundary has passed) to 'classified', and — when dispatch_handlers=true (default) — draft their closing entries - in the same transaction. This is the on-demand form of the background obligation-promotion sweep; - run it before close-period when a schedule was just created or when you can't wait for the Dagster - sensor. Idempotent: re-running skips already-classified obligations and reconciles to existing - drafts. + in the same transaction. Also reaches stranded obligations: events already 'classified' (by an + earlier flip-only sweep) whose closing entry was never drafted are dispatched in the same pass, and + reported via stranded_count. This is the on-demand form of the background obligation-promotion + sweep; run it before close-period when a schedule was just created or when you can't wait for the + Dagster sensor. Idempotent: re-running skips already-classified obligations and reconciles to + existing drafts. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -137,7 +139,9 @@ def sync_detailed( Flips matured ``pending`` ``schedule_entry_due`` events (period boundary passed) to ``classified``; with ``dispatch_handlers`` it also drafts the closing entries in the same transaction (idempotent — reconciles to an - existing draft). + existing draft). The sweep also reaches *stranded* obligations — + already ``classified`` (by an earlier flip-only sweep) but with no + closing entry ever drafted — dispatching them in the same pass. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -171,10 +175,12 @@ def sync( Promote matured pending schedule obligations (schedule_entry_due events whose period boundary has passed) to 'classified', and — when dispatch_handlers=true (default) — draft their closing entries - in the same transaction. This is the on-demand form of the background obligation-promotion sweep; - run it before close-period when a schedule was just created or when you can't wait for the Dagster - sensor. Idempotent: re-running skips already-classified obligations and reconciles to existing - drafts. + in the same transaction. Also reaches stranded obligations: events already 'classified' (by an + earlier flip-only sweep) whose closing entry was never drafted are dispatched in the same pass, and + reported via stranded_count. This is the on-demand form of the background obligation-promotion + sweep; run it before close-period when a schedule was just created or when you can't wait for the + Dagster sensor. Idempotent: re-running skips already-classified obligations and reconciles to + existing drafts. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -191,7 +197,9 @@ def sync( Flips matured ``pending`` ``schedule_entry_due`` events (period boundary passed) to ``classified``; with ``dispatch_handlers`` it also drafts the closing entries in the same transaction (idempotent — reconciles to an - existing draft). + existing draft). The sweep also reaches *stranded* obligations — + already ``classified`` (by an earlier flip-only sweep) but with no + closing entry ever drafted — dispatching them in the same pass. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -220,10 +228,12 @@ async def asyncio_detailed( Promote matured pending schedule obligations (schedule_entry_due events whose period boundary has passed) to 'classified', and — when dispatch_handlers=true (default) — draft their closing entries - in the same transaction. This is the on-demand form of the background obligation-promotion sweep; - run it before close-period when a schedule was just created or when you can't wait for the Dagster - sensor. Idempotent: re-running skips already-classified obligations and reconciles to existing - drafts. + in the same transaction. Also reaches stranded obligations: events already 'classified' (by an + earlier flip-only sweep) whose closing entry was never drafted are dispatched in the same pass, and + reported via stranded_count. This is the on-demand form of the background obligation-promotion + sweep; run it before close-period when a schedule was just created or when you can't wait for the + Dagster sensor. Idempotent: re-running skips already-classified obligations and reconciles to + existing drafts. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -240,7 +250,9 @@ async def asyncio_detailed( Flips matured ``pending`` ``schedule_entry_due`` events (period boundary passed) to ``classified``; with ``dispatch_handlers`` it also drafts the closing entries in the same transaction (idempotent — reconciles to an - existing draft). + existing draft). The sweep also reaches *stranded* obligations — + already ``classified`` (by an earlier flip-only sweep) but with no + closing entry ever drafted — dispatching them in the same pass. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -272,10 +284,12 @@ async def asyncio( Promote matured pending schedule obligations (schedule_entry_due events whose period boundary has passed) to 'classified', and — when dispatch_handlers=true (default) — draft their closing entries - in the same transaction. This is the on-demand form of the background obligation-promotion sweep; - run it before close-period when a schedule was just created or when you can't wait for the Dagster - sensor. Idempotent: re-running skips already-classified obligations and reconciles to existing - drafts. + in the same transaction. Also reaches stranded obligations: events already 'classified' (by an + earlier flip-only sweep) whose closing entry was never drafted are dispatched in the same pass, and + reported via stranded_count. This is the on-demand form of the background obligation-promotion + sweep; run it before close-period when a schedule was just created or when you can't wait for the + Dagster sensor. Idempotent: re-running skips already-classified obligations and reconciles to + existing drafts. **Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict. @@ -292,7 +306,9 @@ async def asyncio( Flips matured ``pending`` ``schedule_entry_due`` events (period boundary passed) to ``classified``; with ``dispatch_handlers`` it also drafts the closing entries in the same transaction (idempotent — reconciles to an - existing draft). + existing draft). The sweep also reaches *stranded* obligations — + already ``classified`` (by an earlier flip-only sweep) but with no + closing entry ever drafted — dispatching them in the same pass. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/operator/batch_process_queries.py b/robosystems_client/api/operator/batch_process_queries.py deleted file mode 100644 index 580e9a4..0000000 --- a/robosystems_client/api/operator/batch_process_queries.py +++ /dev/null @@ -1,229 +0,0 @@ -from http import HTTPStatus -from typing import Any, cast -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.batch_operator_request import BatchOperatorRequest -from ...models.batch_operator_response import BatchOperatorResponse -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...types import Response - - -def _get_kwargs( - graph_id: str, - *, - body: BatchOperatorRequest, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/v1/graphs/{graph_id}/operator/batch".format( - graph_id=quote(str(graph_id), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError | None: - if response.status_code == 200: - response_200 = BatchOperatorResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = ErrorResponse.from_dict(response.json()) - - return response_401 - - if response.status_code == 402: - response_402 = cast(Any, None) - return response_402 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = ErrorResponse.from_dict(response.json()) - - return response_429 - - if response.status_code == 500: - response_500 = ErrorResponse.from_dict(response.json()) - - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: BatchOperatorRequest, -) -> Response[Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError]: - """Batch Process Queries - - Process up to 10 queries sequentially or in parallel. Partial failure is supported — each result has - individual error handling. - - Args: - graph_id (str): - body (BatchOperatorRequest): Request for batch processing multiple queries. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - body: BatchOperatorRequest, -) -> Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError | None: - """Batch Process Queries - - Process up to 10 queries sequentially or in parallel. Partial failure is supported — each result has - individual error handling. - - Args: - graph_id (str): - body (BatchOperatorRequest): Request for batch processing multiple queries. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: BatchOperatorRequest, -) -> Response[Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError]: - """Batch Process Queries - - Process up to 10 queries sequentially or in parallel. Partial failure is supported — each result has - individual error handling. - - Args: - graph_id (str): - body (BatchOperatorRequest): Request for batch processing multiple queries. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - body: BatchOperatorRequest, -) -> Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError | None: - """Batch Process Queries - - Process up to 10 queries sequentially or in parallel. Partial failure is supported — each result has - individual error handling. - - Args: - graph_id (str): - body (BatchOperatorRequest): Request for batch processing multiple queries. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | BatchOperatorResponse | ErrorResponse | HTTPValidationError - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - body=body, - ) - ).parsed diff --git a/robosystems_client/api/operator/recommend_operator.py b/robosystems_client/api/operator/recommend_operator.py deleted file mode 100644 index 396952b..0000000 --- a/robosystems_client/api/operator/recommend_operator.py +++ /dev/null @@ -1,225 +0,0 @@ -from http import HTTPStatus -from typing import Any -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...models.operator_recommendation_request import OperatorRecommendationRequest -from ...models.operator_recommendation_response import OperatorRecommendationResponse -from ...types import Response - - -def _get_kwargs( - graph_id: str, - *, - body: OperatorRecommendationRequest, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/v1/graphs/{graph_id}/operator/recommend".format( - graph_id=quote(str(graph_id), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorResponse | HTTPValidationError | OperatorRecommendationResponse | None: - if response.status_code == 200: - response_200 = OperatorRecommendationResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = ErrorResponse.from_dict(response.json()) - - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = ErrorResponse.from_dict(response.json()) - - return response_429 - - if response.status_code == 500: - response_500 = ErrorResponse.from_dict(response.json()) - - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorResponse | HTTPValidationError | OperatorRecommendationResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: OperatorRecommendationRequest, -) -> Response[ErrorResponse | HTTPValidationError | OperatorRecommendationResponse]: - """Get Operator Recommendations - - Returns operators ranked by confidence score for a query, with explanations. Use before execution - when unsure which operator to pick. - - Args: - graph_id (str): - body (OperatorRecommendationRequest): Request for operator recommendations. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorResponse | HTTPValidationError | OperatorRecommendationResponse] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - body: OperatorRecommendationRequest, -) -> ErrorResponse | HTTPValidationError | OperatorRecommendationResponse | None: - """Get Operator Recommendations - - Returns operators ranked by confidence score for a query, with explanations. Use before execution - when unsure which operator to pick. - - Args: - graph_id (str): - body (OperatorRecommendationRequest): Request for operator recommendations. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorResponse | HTTPValidationError | OperatorRecommendationResponse - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: OperatorRecommendationRequest, -) -> Response[ErrorResponse | HTTPValidationError | OperatorRecommendationResponse]: - """Get Operator Recommendations - - Returns operators ranked by confidence score for a query, with explanations. Use before execution - when unsure which operator to pick. - - Args: - graph_id (str): - body (OperatorRecommendationRequest): Request for operator recommendations. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorResponse | HTTPValidationError | OperatorRecommendationResponse] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - body: OperatorRecommendationRequest, -) -> ErrorResponse | HTTPValidationError | OperatorRecommendationResponse | None: - """Get Operator Recommendations - - Returns operators ranked by confidence score for a query, with explanations. Use before execution - when unsure which operator to pick. - - Args: - graph_id (str): - body (OperatorRecommendationRequest): Request for operator recommendations. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorResponse | HTTPValidationError | OperatorRecommendationResponse - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - body=body, - ) - ).parsed diff --git a/robosystems_client/api/subgraphs/get_subgraph_quota.py b/robosystems_client/api/subgraphs/get_subgraph_quota.py deleted file mode 100644 index 7fb7fc6..0000000 --- a/robosystems_client/api/subgraphs/get_subgraph_quota.py +++ /dev/null @@ -1,204 +0,0 @@ -from http import HTTPStatus -from typing import Any -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...models.subgraph_quota_response import SubgraphQuotaResponse -from ...types import Response - - -def _get_kwargs( - graph_id: str, -) -> dict[str, Any]: - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/v1/graphs/{graph_id}/subgraphs/quota".format( - graph_id=quote(str(graph_id), safe=""), - ), - } - - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorResponse | HTTPValidationError | SubgraphQuotaResponse | None: - if response.status_code == 200: - response_200 = SubgraphQuotaResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = ErrorResponse.from_dict(response.json()) - - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = ErrorResponse.from_dict(response.json()) - - return response_429 - - if response.status_code == 500: - response_500 = ErrorResponse.from_dict(response.json()) - - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorResponse | HTTPValidationError | SubgraphQuotaResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, -) -> Response[ErrorResponse | HTTPValidationError | SubgraphQuotaResponse]: - """Get Subgraph Quota - - Tier capacity: Standard 3, Large 10, XLarge 25 subgraphs. Use the list endpoint for per-subgraph - sizes. - - Args: - graph_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorResponse | HTTPValidationError | SubgraphQuotaResponse] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, -) -> ErrorResponse | HTTPValidationError | SubgraphQuotaResponse | None: - """Get Subgraph Quota - - Tier capacity: Standard 3, Large 10, XLarge 25 subgraphs. Use the list endpoint for per-subgraph - sizes. - - Args: - graph_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorResponse | HTTPValidationError | SubgraphQuotaResponse - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, -) -> Response[ErrorResponse | HTTPValidationError | SubgraphQuotaResponse]: - """Get Subgraph Quota - - Tier capacity: Standard 3, Large 10, XLarge 25 subgraphs. Use the list endpoint for per-subgraph - sizes. - - Args: - graph_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorResponse | HTTPValidationError | SubgraphQuotaResponse] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, -) -> ErrorResponse | HTTPValidationError | SubgraphQuotaResponse | None: - """Get Subgraph Quota - - Tier capacity: Standard 3, Large 10, XLarge 25 subgraphs. Use the list endpoint for per-subgraph - sizes. - - Args: - graph_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorResponse | HTTPValidationError | SubgraphQuotaResponse - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - ) - ).parsed diff --git a/robosystems_client/graphql/schema.graphql b/robosystems_client/graphql/schema.graphql index d6e029e..4cd45de 100644 --- a/robosystems_client/graphql/schema.graphql +++ b/robosystems_client/graphql/schema.graphql @@ -15,7 +15,7 @@ type Query { openReceivablesByAgent: [OpenBalanceByAgent!]! openPayablesByAgent: [OpenBalanceByAgent!]! eventBlock(id: String!): EventBlock - eventBlocks(eventType: String = null, eventCategory: String = null, status: String = null, agentId: String = null, source: String = null, limit: Int = null, offset: Int = null): [EventBlock!]! + eventBlocks(eventType: String = null, eventCategory: String = null, status: String = null, agentId: String = null, source: String = null, payloadDrift: Boolean = null, limit: Int = null, offset: Int = null): [EventBlock!]! summary: LedgerSummary accounts(classification: String = null, isActive: Boolean = null, limit: Int = null, offset: Int = null): AccountList accountTree(includeInactive: Boolean = null): AccountTree @@ -636,6 +636,7 @@ type EventBlock { currency: String! description: String metadata: JSON! + payloadDrift: Boolean! dimensionIds: [String!]! agentId: String resourceType: String @@ -1126,7 +1127,7 @@ type FiscalCalendar { closeableNow: Boolean! """ - Structured blocker codes when closeable_now is False: 'sequence_violation', 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations' + Structured blocker codes when closeable_now is False: 'sequence_violation', 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations', 'stranded_obligations' """ blockers: [String!]! @@ -1149,6 +1150,16 @@ type FiscalCalendar { Days the most recent sync is stale relative to the period to close. Populated only when `sync_stale` is in `blockers` and last_sync_at exists (null when there's a connection but no sync has ever run). """ syncStaleDays: Int + + """ + Matured schedule_entry_due events already at 'classified' with no drafted closing entry for their (schedule, period) — adjusting entries a close would silently omit. Resolve by running promote-obligations with dispatch_handlers=true (which reaches them) or voiding the obligation. + """ + strandedObligationCount: Int! + + """ + Sample of up to 5 stranded obligations (schedule_id, schedule_name, period, event_id) ordered by occurred_at. + """ + strandedObligationSample: [PendingObligationDetail!]! lastCloseAt: DateTime initializedAt: DateTime diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 8df4748..b8d88f5 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -33,8 +33,6 @@ from .backup_response import BackupResponse from .backup_stats_response import BackupStatsResponse from .backup_stats_response_backup_formats import BackupStatsResponseBackupFormats -from .batch_operator_request import BatchOperatorRequest -from .batch_operator_response import BatchOperatorResponse from .billing_customer import BillingCustomer from .bind_text_block_request import BindTextBlockRequest from .bind_text_block_response import BindTextBlockResponse @@ -573,12 +571,6 @@ from .operator_message import OperatorMessage from .operator_metadata_response import OperatorMetadataResponse from .operator_mode import OperatorMode -from .operator_recommendation import OperatorRecommendation -from .operator_recommendation_request import OperatorRecommendationRequest -from .operator_recommendation_request_context_type_0 import ( - OperatorRecommendationRequestContextType0, -) -from .operator_recommendation_response import OperatorRecommendationResponse from .operator_request import OperatorRequest from .operator_request_context_type_0 import OperatorRequestContextType0 from .operator_response import OperatorResponse @@ -720,7 +712,7 @@ StructureUpdatePatchConceptArrangementType0, ) from .structure_update_patch_metadata_type_0 import StructureUpdatePatchMetadataType0 -from .subgraph_quota_response import SubgraphQuotaResponse +from .subgraph_limits import SubgraphLimits from .subgraph_response import SubgraphResponse from .subgraph_response_metadata_type_0 import SubgraphResponseMetadataType0 from .subgraph_summary import SubgraphSummary @@ -882,8 +874,6 @@ "BackupResponse", "BackupStatsResponse", "BackupStatsResponseBackupFormats", - "BatchOperatorRequest", - "BatchOperatorResponse", "BillingCustomer", "BindTextBlockRequest", "BindTextBlockResponse", @@ -1232,10 +1222,6 @@ "OperatorMessage", "OperatorMetadataResponse", "OperatorMode", - "OperatorRecommendation", - "OperatorRecommendationRequest", - "OperatorRecommendationRequestContextType0", - "OperatorRecommendationResponse", "OperatorRequest", "OperatorRequestContextType0", "OperatorResponse", @@ -1361,7 +1347,7 @@ "StructureUpdatePatch", "StructureUpdatePatchConceptArrangementType0", "StructureUpdatePatchMetadataType0", - "SubgraphQuotaResponse", + "SubgraphLimits", "SubgraphResponse", "SubgraphResponseMetadataType0", "SubgraphSummary", diff --git a/robosystems_client/models/backfill_plan_history_operation.py b/robosystems_client/models/backfill_plan_history_operation.py index 917677f..acb2fa5 100644 --- a/robosystems_client/models/backfill_plan_history_operation.py +++ b/robosystems_client/models/backfill_plan_history_operation.py @@ -22,6 +22,9 @@ class BackfillPlanHistoryOperation: cycle; keep chunks modest and loop on `remaining_periods`. Default: 12. allow_stale_sync (bool | Unset): Override the sync-currency gate on each reclose. Historical months predate the last sync in the normal case, so this is rarely needed. Default: False. + allow_stranded_obligations (bool | Unset): Override the stranded-obligation gate on each reclose. Only needed + when a matured classified obligation without a drafted entry exists inside the backfill window and you have + decided not to draft or void it first. Default: False. restamp (bool | Unset): Also re-derive months that ALREADY have canonical statement sets (default: skip them). Use after an engine improvement changes what a stamp produces — each month reruns the full reopen → reclose cycle and replaces its sets. A restamp run is not self-resuming (every month in range stays a candidate); @@ -32,6 +35,7 @@ class BackfillPlanHistoryOperation: start_period: None | str | Unset = UNSET max_periods: int | Unset = 12 allow_stale_sync: bool | Unset = False + allow_stranded_obligations: bool | Unset = False restamp: bool | Unset = False note: None | str | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -47,6 +51,8 @@ def to_dict(self) -> dict[str, Any]: allow_stale_sync = self.allow_stale_sync + allow_stranded_obligations = self.allow_stranded_obligations + restamp = self.restamp note: None | str | Unset @@ -64,6 +70,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["max_periods"] = max_periods if allow_stale_sync is not UNSET: field_dict["allow_stale_sync"] = allow_stale_sync + if allow_stranded_obligations is not UNSET: + field_dict["allow_stranded_obligations"] = allow_stranded_obligations if restamp is not UNSET: field_dict["restamp"] = restamp if note is not UNSET: @@ -88,6 +96,8 @@ def _parse_start_period(data: object) -> None | str | Unset: allow_stale_sync = d.pop("allow_stale_sync", UNSET) + allow_stranded_obligations = d.pop("allow_stranded_obligations", UNSET) + restamp = d.pop("restamp", UNSET) def _parse_note(data: object) -> None | str | Unset: @@ -103,6 +113,7 @@ def _parse_note(data: object) -> None | str | Unset: start_period=start_period, max_periods=max_periods, allow_stale_sync=allow_stale_sync, + allow_stranded_obligations=allow_stranded_obligations, restamp=restamp, note=note, ) diff --git a/robosystems_client/models/batch_operator_request.py b/robosystems_client/models/batch_operator_request.py deleted file mode 100644 index 88b4f42..0000000 --- a/robosystems_client/models/batch_operator_request.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.operator_request import OperatorRequest - - -T = TypeVar("T", bound="BatchOperatorRequest") - - -@_attrs_define -class BatchOperatorRequest: - """Request for batch processing multiple queries. - - Attributes: - queries (list[OperatorRequest]): List of queries to process (max 10) - parallel (bool | Unset): Process queries in parallel Default: False. - """ - - queries: list[OperatorRequest] - parallel: bool | Unset = False - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - queries = [] - for queries_item_data in self.queries: - queries_item = queries_item_data.to_dict() - queries.append(queries_item) - - parallel = self.parallel - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "queries": queries, - } - ) - if parallel is not UNSET: - field_dict["parallel"] = parallel - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.operator_request import OperatorRequest - - d = dict(src_dict) - queries = [] - _queries = d.pop("queries") - for queries_item_data in _queries: - queries_item = OperatorRequest.from_dict(queries_item_data) - - queries.append(queries_item) - - parallel = d.pop("parallel", UNSET) - - batch_operator_request = cls( - queries=queries, - parallel=parallel, - ) - - batch_operator_request.additional_properties = d - return batch_operator_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/batch_operator_response.py b/robosystems_client/models/batch_operator_response.py deleted file mode 100644 index 23d9692..0000000 --- a/robosystems_client/models/batch_operator_response.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -if TYPE_CHECKING: - from ..models.operator_response import OperatorResponse - - -T = TypeVar("T", bound="BatchOperatorResponse") - - -@_attrs_define -class BatchOperatorResponse: - """Response for batch processing. - - Attributes: - results (list[OperatorResponse]): List of operator responses (includes successes and failures) - total_execution_time (float): Total execution time in seconds - parallel_processed (bool): Whether queries were processed in parallel - """ - - results: list[OperatorResponse] - total_execution_time: float - parallel_processed: bool - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - results = [] - for results_item_data in self.results: - results_item = results_item_data.to_dict() - results.append(results_item) - - total_execution_time = self.total_execution_time - - parallel_processed = self.parallel_processed - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "results": results, - "total_execution_time": total_execution_time, - "parallel_processed": parallel_processed, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.operator_response import OperatorResponse - - d = dict(src_dict) - results = [] - _results = d.pop("results") - for results_item_data in _results: - results_item = OperatorResponse.from_dict(results_item_data) - - results.append(results_item) - - total_execution_time = d.pop("total_execution_time") - - parallel_processed = d.pop("parallel_processed") - - batch_operator_response = cls( - results=results, - total_execution_time=total_execution_time, - parallel_processed=parallel_processed, - ) - - batch_operator_response.additional_properties = d - return batch_operator_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/close_period_operation.py b/robosystems_client/models/close_period_operation.py index 494f607..e4d267d 100644 --- a/robosystems_client/models/close_period_operation.py +++ b/robosystems_client/models/close_period_operation.py @@ -22,11 +22,16 @@ class ClosePeriodOperation: note (None | str | Unset): Free-form note attached to the close event allow_stale_sync (bool | Unset): Override the sync-currency gate. Only use when you have manually verified that the source data for the period is complete. Default: False. + allow_stranded_obligations (bool | Unset): Override the stranded-obligation gate — close even though matured + classified obligations have no drafted closing entry, knowingly omitting those adjusting entries from the + period. Prefer running promote-obligations with dispatch_handlers=true (which drafts them) or voiding the + obligations instead. The override is recorded in the close audit note. Default: False. """ period: str note: None | str | Unset = UNSET allow_stale_sync: bool | Unset = False + allow_stranded_obligations: bool | Unset = False additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -40,6 +45,8 @@ def to_dict(self) -> dict[str, Any]: allow_stale_sync = self.allow_stale_sync + allow_stranded_obligations = self.allow_stranded_obligations + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -51,6 +58,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["note"] = note if allow_stale_sync is not UNSET: field_dict["allow_stale_sync"] = allow_stale_sync + if allow_stranded_obligations is not UNSET: + field_dict["allow_stranded_obligations"] = allow_stranded_obligations return field_dict @@ -70,10 +79,13 @@ def _parse_note(data: object) -> None | str | Unset: allow_stale_sync = d.pop("allow_stale_sync", UNSET) + allow_stranded_obligations = d.pop("allow_stranded_obligations", UNSET) + close_period_operation = cls( period=period, note=note, allow_stale_sync=allow_stale_sync, + allow_stranded_obligations=allow_stranded_obligations, ) close_period_operation.additional_properties = d diff --git a/robosystems_client/models/close_period_response.py b/robosystems_client/models/close_period_response.py index faeb3cf..555f6d3 100644 --- a/robosystems_client/models/close_period_response.py +++ b/robosystems_client/models/close_period_response.py @@ -31,7 +31,13 @@ class ClosePeriodResponse: Attributes: fiscal_calendar (FiscalCalendarResponse): Current fiscal calendar state for a graph. period (str): - entries_posted (int | Unset): Number of draft entries transitioned to posted Default: 0. + entries_posted (int | Unset): Total draft entries the close transitioned to posted, across both post paths (QB + pre-publish + local bulk transition). See entries_published_to_qb / entries_posted_locally for the split. + Default: 0. + entries_published_to_qb (int | Unset): Drafts published to QuickBooks by the close's pre-publish step (each is + promoted to posted at publish time). Default: 0. + entries_posted_locally (int | Unset): Drafts posted by the local bulk transition (entries that don't publish to + QuickBooks, e.g. native-only graphs or local-only sources). Default: 0. target_auto_advanced (bool | Unset): Whether close_target was auto-advanced because it was reached Default: False. rule_summary (ClosePeriodResponseRuleSummaryType0 | None | Unset): Aggregated rule-eval outcome across every @@ -53,6 +59,8 @@ class ClosePeriodResponse: fiscal_calendar: FiscalCalendarResponse period: str entries_posted: int | Unset = 0 + entries_published_to_qb: int | Unset = 0 + entries_posted_locally: int | Unset = 0 target_auto_advanced: bool | Unset = False rule_summary: ClosePeriodResponseRuleSummaryType0 | None | Unset = UNSET evaluated_structure_ids: list[str] | Unset = UNSET @@ -78,6 +86,10 @@ def to_dict(self) -> dict[str, Any]: entries_posted = self.entries_posted + entries_published_to_qb = self.entries_published_to_qb + + entries_posted_locally = self.entries_posted_locally + target_auto_advanced = self.target_auto_advanced rule_summary: dict[str, Any] | None | Unset @@ -124,6 +136,10 @@ def to_dict(self) -> dict[str, Any]: ) if entries_posted is not UNSET: field_dict["entries_posted"] = entries_posted + if entries_published_to_qb is not UNSET: + field_dict["entries_published_to_qb"] = entries_published_to_qb + if entries_posted_locally is not UNSET: + field_dict["entries_posted_locally"] = entries_posted_locally if target_auto_advanced is not UNSET: field_dict["target_auto_advanced"] = target_auto_advanced if rule_summary is not UNSET: @@ -161,6 +177,10 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: entries_posted = d.pop("entries_posted", UNSET) + entries_published_to_qb = d.pop("entries_published_to_qb", UNSET) + + entries_posted_locally = d.pop("entries_posted_locally", UNSET) + target_auto_advanced = d.pop("target_auto_advanced", UNSET) def _parse_rule_summary( @@ -233,6 +253,8 @@ def _parse_statement_rule_summary( fiscal_calendar=fiscal_calendar, period=period, entries_posted=entries_posted, + entries_published_to_qb=entries_published_to_qb, + entries_posted_locally=entries_posted_locally, target_auto_advanced=target_auto_advanced, rule_summary=rule_summary, evaluated_structure_ids=evaluated_structure_ids, diff --git a/robosystems_client/models/event_block_envelope.py b/robosystems_client/models/event_block_envelope.py index 72097a3..517aa37 100644 --- a/robosystems_client/models/event_block_envelope.py +++ b/robosystems_client/models/event_block_envelope.py @@ -57,6 +57,10 @@ class EventBlockEnvelope: amount (int | None | Unset): Economic value in **cents** of `currency`, signed (inflows positive, outflows negative). `null` for non-economic events. description (None | str | Unset): Free-text human-readable summary. + payload_drift (bool | Unset): True when a source re-sync surfaced a changed upstream payload for an event whose + GL is already posted (committed/fulfilled are immutable to sync). The live payload and GL are untouched; the + incoming payload is stashed in `metadata.drift_payload` with `metadata.drift_detected_at`. Drifted events need + operator reconciliation — the local books no longer mirror the source. Default: False. event_action (EventBlockEnvelopeEventActionType0 | None | Unset): Canonical action verb refining `event_category`. Null when the source adapter or capture path didn't supply one. agent_id (None | str | Unset): Counterparty agent ID, when the event involves one. @@ -90,6 +94,7 @@ class EventBlockEnvelope: external_url: None | str | Unset = UNSET amount: int | None | Unset = UNSET description: None | str | Unset = UNSET + payload_drift: bool | Unset = False event_action: EventBlockEnvelopeEventActionType0 | None | Unset = UNSET agent_id: None | str | Unset = UNSET resource_type: None | str | Unset = UNSET @@ -157,6 +162,8 @@ def to_dict(self) -> dict[str, Any]: else: description = self.description + payload_drift = self.payload_drift + event_action: None | str | Unset if isinstance(self.event_action, Unset): event_action = UNSET @@ -235,6 +242,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["amount"] = amount if description is not UNSET: field_dict["description"] = description + if payload_drift is not UNSET: + field_dict["payload_drift"] = payload_drift if event_action is not UNSET: field_dict["event_action"] = event_action if agent_id is not UNSET: @@ -336,6 +345,8 @@ def _parse_description(data: object) -> None | str | Unset: description = _parse_description(d.pop("description", UNSET)) + payload_drift = d.pop("payload_drift", UNSET) + def _parse_event_action( data: object, ) -> EventBlockEnvelopeEventActionType0 | None | Unset: @@ -444,6 +455,7 @@ def _parse_discharges_event_id(data: object) -> None | str | Unset: external_url=external_url, amount=amount, description=description, + payload_drift=payload_drift, event_action=event_action, agent_id=agent_id, resource_type=resource_type, diff --git a/robosystems_client/models/fiscal_calendar_response.py b/robosystems_client/models/fiscal_calendar_response.py index 40d84ad..b1dbd9d 100644 --- a/robosystems_client/models/fiscal_calendar_response.py +++ b/robosystems_client/models/fiscal_calendar_response.py @@ -34,7 +34,8 @@ class FiscalCalendarResponse: closeable_now (bool | Unset): Whether the next period in the catch-up sequence passes all closeable gates Default: False. blockers (list[str] | Unset): Structured blocker codes when closeable_now is False: 'sequence_violation', - 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations' + 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations', + 'stranded_obligations' pending_obligation_count (int | Unset): Number of pending schedule_entry_due events blocking close. Non-zero only when `pending_obligations` is in `blockers`. Default: 0. pending_obligation_sample (list[PendingObligationDetailResponse] | Unset): Sample of up to 5 pending obligations @@ -45,6 +46,12 @@ class FiscalCalendarResponse: sync_stale_days (int | None | Unset): Days the most recent sync is stale relative to the period to close. Populated only when `sync_stale` is in `blockers` and last_sync_at exists (null when there's a connection but no sync has ever run). + stranded_obligation_count (int | Unset): Matured schedule_entry_due events already at 'classified' with no + drafted closing entry for their (schedule, period) — adjusting entries a close would silently omit. Resolve by + running promote-obligations with dispatch_handlers=true (which reaches them) or voiding the obligation. Default: + 0. + stranded_obligation_sample (list[PendingObligationDetailResponse] | Unset): Sample of up to 5 stranded + obligations (schedule_id, schedule_name, period, event_id) ordered by occurred_at. last_close_at (datetime.datetime | None | Unset): initialized_at (datetime.datetime | None | Unset): last_sync_at (datetime.datetime | None | Unset): Most recent QB sync timestamp (if connected) @@ -63,6 +70,8 @@ class FiscalCalendarResponse: pending_obligation_sample: list[PendingObligationDetailResponse] | Unset = UNSET earliest_pending_period: None | str | Unset = UNSET sync_stale_days: int | None | Unset = UNSET + stranded_obligation_count: int | Unset = 0 + stranded_obligation_sample: list[PendingObligationDetailResponse] | Unset = UNSET last_close_at: datetime.datetime | None | Unset = UNSET initialized_at: datetime.datetime | None | Unset = UNSET last_sync_at: datetime.datetime | None | Unset = UNSET @@ -119,6 +128,15 @@ def to_dict(self) -> dict[str, Any]: else: sync_stale_days = self.sync_stale_days + stranded_obligation_count = self.stranded_obligation_count + + stranded_obligation_sample: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.stranded_obligation_sample, Unset): + stranded_obligation_sample = [] + for stranded_obligation_sample_item_data in self.stranded_obligation_sample: + stranded_obligation_sample_item = stranded_obligation_sample_item_data.to_dict() + stranded_obligation_sample.append(stranded_obligation_sample_item) + last_close_at: None | str | Unset if isinstance(self.last_close_at, Unset): last_close_at = UNSET @@ -178,6 +196,10 @@ def to_dict(self) -> dict[str, Any]: field_dict["earliest_pending_period"] = earliest_pending_period if sync_stale_days is not UNSET: field_dict["sync_stale_days"] = sync_stale_days + if stranded_obligation_count is not UNSET: + field_dict["stranded_obligation_count"] = stranded_obligation_count + if stranded_obligation_sample is not UNSET: + field_dict["stranded_obligation_sample"] = stranded_obligation_sample if last_close_at is not UNSET: field_dict["last_close_at"] = last_close_at if initialized_at is not UNSET: @@ -260,6 +282,19 @@ def _parse_sync_stale_days(data: object) -> int | None | Unset: sync_stale_days = _parse_sync_stale_days(d.pop("sync_stale_days", UNSET)) + stranded_obligation_count = d.pop("stranded_obligation_count", UNSET) + + _stranded_obligation_sample = d.pop("stranded_obligation_sample", UNSET) + stranded_obligation_sample: list[PendingObligationDetailResponse] | Unset = UNSET + if _stranded_obligation_sample is not UNSET: + stranded_obligation_sample = [] + for stranded_obligation_sample_item_data in _stranded_obligation_sample: + stranded_obligation_sample_item = PendingObligationDetailResponse.from_dict( + stranded_obligation_sample_item_data + ) + + stranded_obligation_sample.append(stranded_obligation_sample_item) + def _parse_last_close_at(data: object) -> datetime.datetime | None | Unset: if data is None: return data @@ -333,6 +368,8 @@ def _parse_last_sync_at(data: object) -> datetime.datetime | None | Unset: pending_obligation_sample=pending_obligation_sample, earliest_pending_period=earliest_pending_period, sync_stale_days=sync_stale_days, + stranded_obligation_count=stranded_obligation_count, + stranded_obligation_sample=stranded_obligation_sample, last_close_at=last_close_at, initialized_at=initialized_at, last_sync_at=last_sync_at, diff --git a/robosystems_client/models/graph_limits_response.py b/robosystems_client/models/graph_limits_response.py index 0734395..76f6b96 100644 --- a/robosystems_client/models/graph_limits_response.py +++ b/robosystems_client/models/graph_limits_response.py @@ -18,6 +18,7 @@ from ..models.query_limits import QueryLimits from ..models.rate_limits import RateLimits from ..models.storage_limits import StorageLimits + from ..models.subgraph_limits import SubgraphLimits T = TypeVar("T", bound="GraphLimitsResponse") @@ -39,6 +40,7 @@ class GraphLimitsResponse: rate_limits (RateLimits): API rate limits. credits_ (CreditLimits | None | Unset): AI credit limits (if applicable) documents (DocumentLimits | None | Unset): Knowledge-base document usage and tier cap (user graphs only) + subgraphs (None | SubgraphLimits | Unset): Subgraph count and tier cap (parent user graphs only) content (ContentLimits | None | Unset): Per-operation materialization limits (if applicable) instance (InstanceUsage | None | Unset): Aggregate instance storage usage (user graphs only) """ @@ -54,6 +56,7 @@ class GraphLimitsResponse: rate_limits: RateLimits credits_: CreditLimits | None | Unset = UNSET documents: DocumentLimits | None | Unset = UNSET + subgraphs: None | SubgraphLimits | Unset = UNSET content: ContentLimits | None | Unset = UNSET instance: InstanceUsage | None | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -63,6 +66,7 @@ def to_dict(self) -> dict[str, Any]: from ..models.credit_limits import CreditLimits from ..models.document_limits import DocumentLimits from ..models.instance_usage import InstanceUsage + from ..models.subgraph_limits import SubgraphLimits graph_id = self.graph_id @@ -98,6 +102,14 @@ def to_dict(self) -> dict[str, Any]: else: documents = self.documents + subgraphs: dict[str, Any] | None | Unset + if isinstance(self.subgraphs, Unset): + subgraphs = UNSET + elif isinstance(self.subgraphs, SubgraphLimits): + subgraphs = self.subgraphs.to_dict() + else: + subgraphs = self.subgraphs + content: dict[str, Any] | None | Unset if isinstance(self.content, Unset): content = UNSET @@ -133,6 +145,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["credits"] = credits_ if documents is not UNSET: field_dict["documents"] = documents + if subgraphs is not UNSET: + field_dict["subgraphs"] = subgraphs if content is not UNSET: field_dict["content"] = content if instance is not UNSET: @@ -151,6 +165,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: from ..models.query_limits import QueryLimits from ..models.rate_limits import RateLimits from ..models.storage_limits import StorageLimits + from ..models.subgraph_limits import SubgraphLimits d = dict(src_dict) graph_id = d.pop("graph_id") @@ -205,6 +220,23 @@ def _parse_documents(data: object) -> DocumentLimits | None | Unset: documents = _parse_documents(d.pop("documents", UNSET)) + def _parse_subgraphs(data: object) -> None | SubgraphLimits | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + subgraphs_type_0 = SubgraphLimits.from_dict(data) + + return subgraphs_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SubgraphLimits | Unset, data) + + subgraphs = _parse_subgraphs(d.pop("subgraphs", UNSET)) + def _parse_content(data: object) -> ContentLimits | None | Unset: if data is None: return data @@ -251,6 +283,7 @@ def _parse_instance(data: object) -> InstanceUsage | None | Unset: rate_limits=rate_limits, credits_=credits_, documents=documents, + subgraphs=subgraphs, content=content, instance=instance, ) diff --git a/robosystems_client/models/operator_recommendation.py b/robosystems_client/models/operator_recommendation.py deleted file mode 100644 index c4bcb96..0000000 --- a/robosystems_client/models/operator_recommendation.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="OperatorRecommendation") - - -@_attrs_define -class OperatorRecommendation: - """Single operator recommendation. - - Attributes: - operator_type (str): Operator type identifier - operator_name (str): Operator display name - confidence (float): Confidence score (0-1) - capabilities (list[str]): Operator capabilities - reason (None | str | Unset): Reason for recommendation - """ - - operator_type: str - operator_name: str - confidence: float - capabilities: list[str] - reason: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - operator_type = self.operator_type - - operator_name = self.operator_name - - confidence = self.confidence - - capabilities = self.capabilities - - reason: None | str | Unset - if isinstance(self.reason, Unset): - reason = UNSET - else: - reason = self.reason - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "operator_type": operator_type, - "operator_name": operator_name, - "confidence": confidence, - "capabilities": capabilities, - } - ) - if reason is not UNSET: - field_dict["reason"] = reason - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - operator_type = d.pop("operator_type") - - operator_name = d.pop("operator_name") - - confidence = d.pop("confidence") - - capabilities = cast(list[str], d.pop("capabilities")) - - def _parse_reason(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - reason = _parse_reason(d.pop("reason", UNSET)) - - operator_recommendation = cls( - operator_type=operator_type, - operator_name=operator_name, - confidence=confidence, - capabilities=capabilities, - reason=reason, - ) - - operator_recommendation.additional_properties = d - return operator_recommendation - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/operator_recommendation_request.py b/robosystems_client/models/operator_recommendation_request.py deleted file mode 100644 index 8199ed1..0000000 --- a/robosystems_client/models/operator_recommendation_request.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.operator_recommendation_request_context_type_0 import ( - OperatorRecommendationRequestContextType0, - ) - - -T = TypeVar("T", bound="OperatorRecommendationRequest") - - -@_attrs_define -class OperatorRecommendationRequest: - """Request for operator recommendations. - - Attributes: - query (str): Query to analyze - context (None | OperatorRecommendationRequestContextType0 | Unset): Additional context - """ - - query: str - context: None | OperatorRecommendationRequestContextType0 | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.operator_recommendation_request_context_type_0 import ( - OperatorRecommendationRequestContextType0, - ) - - query = self.query - - context: dict[str, Any] | None | Unset - if isinstance(self.context, Unset): - context = UNSET - elif isinstance(self.context, OperatorRecommendationRequestContextType0): - context = self.context.to_dict() - else: - context = self.context - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "query": query, - } - ) - if context is not UNSET: - field_dict["context"] = context - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.operator_recommendation_request_context_type_0 import ( - OperatorRecommendationRequestContextType0, - ) - - d = dict(src_dict) - query = d.pop("query") - - def _parse_context( - data: object, - ) -> None | OperatorRecommendationRequestContextType0 | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - context_type_0 = OperatorRecommendationRequestContextType0.from_dict(data) - - return context_type_0 - except (TypeError, ValueError, AttributeError, KeyError): - pass - return cast(None | OperatorRecommendationRequestContextType0 | Unset, data) - - context = _parse_context(d.pop("context", UNSET)) - - operator_recommendation_request = cls( - query=query, - context=context, - ) - - operator_recommendation_request.additional_properties = d - return operator_recommendation_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/operator_recommendation_request_context_type_0.py b/robosystems_client/models/operator_recommendation_request_context_type_0.py deleted file mode 100644 index 5aa2edc..0000000 --- a/robosystems_client/models/operator_recommendation_request_context_type_0.py +++ /dev/null @@ -1,47 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="OperatorRecommendationRequestContextType0") - - -@_attrs_define -class OperatorRecommendationRequestContextType0: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - operator_recommendation_request_context_type_0 = cls() - - operator_recommendation_request_context_type_0.additional_properties = d - return operator_recommendation_request_context_type_0 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/operator_recommendation_response.py b/robosystems_client/models/operator_recommendation_response.py deleted file mode 100644 index 57e21c2..0000000 --- a/robosystems_client/models/operator_recommendation_response.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -if TYPE_CHECKING: - from ..models.operator_recommendation import OperatorRecommendation - - -T = TypeVar("T", bound="OperatorRecommendationResponse") - - -@_attrs_define -class OperatorRecommendationResponse: - """Response for operator recommendations. - - Attributes: - recommendations (list[OperatorRecommendation]): List of operator recommendations sorted by confidence - query (str): The analyzed query - """ - - recommendations: list[OperatorRecommendation] - query: str - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - recommendations = [] - for recommendations_item_data in self.recommendations: - recommendations_item = recommendations_item_data.to_dict() - recommendations.append(recommendations_item) - - query = self.query - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "recommendations": recommendations, - "query": query, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.operator_recommendation import OperatorRecommendation - - d = dict(src_dict) - recommendations = [] - _recommendations = d.pop("recommendations") - for recommendations_item_data in _recommendations: - recommendations_item = OperatorRecommendation.from_dict(recommendations_item_data) - - recommendations.append(recommendations_item) - - query = d.pop("query") - - operator_recommendation_response = cls( - recommendations=recommendations, - query=query, - ) - - operator_recommendation_response.additional_properties = d - return operator_recommendation_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/promote_obligations_request.py b/robosystems_client/models/promote_obligations_request.py index df1634b..4a19465 100644 --- a/robosystems_client/models/promote_obligations_request.py +++ b/robosystems_client/models/promote_obligations_request.py @@ -22,7 +22,9 @@ class PromoteObligationsRequest: Flips matured ``pending`` ``schedule_entry_due`` events (period boundary passed) to ``classified``; with ``dispatch_handlers`` it also drafts the closing entries in the same transaction (idempotent — reconciles to an - existing draft). + existing draft). The sweep also reaches *stranded* obligations — + already ``classified`` (by an earlier flip-only sweep) but with no + closing entry ever drafted — dispatching them in the same pass. Attributes: dispatch_handlers (bool | Unset): When True (default), also fire the schedule_entry_due handler for each diff --git a/robosystems_client/models/promote_obligations_response.py b/robosystems_client/models/promote_obligations_response.py index 96d478e..7f954df 100644 --- a/robosystems_client/models/promote_obligations_response.py +++ b/robosystems_client/models/promote_obligations_response.py @@ -25,7 +25,11 @@ class PromoteObligationsResponse: classified_count (int): Matured obligations flipped pending → classified. dispatched_count (int): Obligations whose closing entry was drafted this run. error_count (int): Per-obligation handler errors (non-fatal). + stranded_count (int | Unset): Matured obligations found already at 'classified' with no drafted closing entry. + With dispatch_handlers=true they were drafted this run (included in dispatched_count); with + dispatch_handlers=false they still have no draft — re-run with dispatch_handlers=true or void them. Default: 0. classified_event_ids (list[str] | Unset): + stranded_event_ids (list[str] | Unset): Event ids of the stranded obligations found this sweep. errors (list[PromoteObligationsResponseErrorsItem] | Unset): Per-obligation errors as {event_id, error}; the sweep continues past them. """ @@ -33,7 +37,9 @@ class PromoteObligationsResponse: classified_count: int dispatched_count: int error_count: int + stranded_count: int | Unset = 0 classified_event_ids: list[str] | Unset = UNSET + stranded_event_ids: list[str] | Unset = UNSET errors: list[PromoteObligationsResponseErrorsItem] | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -44,10 +50,16 @@ def to_dict(self) -> dict[str, Any]: error_count = self.error_count + stranded_count = self.stranded_count + classified_event_ids: list[str] | Unset = UNSET if not isinstance(self.classified_event_ids, Unset): classified_event_ids = self.classified_event_ids + stranded_event_ids: list[str] | Unset = UNSET + if not isinstance(self.stranded_event_ids, Unset): + stranded_event_ids = self.stranded_event_ids + errors: list[dict[str, Any]] | Unset = UNSET if not isinstance(self.errors, Unset): errors = [] @@ -64,8 +76,12 @@ def to_dict(self) -> dict[str, Any]: "error_count": error_count, } ) + if stranded_count is not UNSET: + field_dict["stranded_count"] = stranded_count if classified_event_ids is not UNSET: field_dict["classified_event_ids"] = classified_event_ids + if stranded_event_ids is not UNSET: + field_dict["stranded_event_ids"] = stranded_event_ids if errors is not UNSET: field_dict["errors"] = errors @@ -84,8 +100,12 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: error_count = d.pop("error_count") + stranded_count = d.pop("stranded_count", UNSET) + classified_event_ids = cast(list[str], d.pop("classified_event_ids", UNSET)) + stranded_event_ids = cast(list[str], d.pop("stranded_event_ids", UNSET)) + _errors = d.pop("errors", UNSET) errors: list[PromoteObligationsResponseErrorsItem] | Unset = UNSET if _errors is not UNSET: @@ -99,7 +119,9 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: classified_count=classified_count, dispatched_count=dispatched_count, error_count=error_count, + stranded_count=stranded_count, classified_event_ids=classified_event_ids, + stranded_event_ids=stranded_event_ids, errors=errors, ) diff --git a/robosystems_client/models/subgraph_quota_response.py b/robosystems_client/models/subgraph_limits.py similarity index 52% rename from robosystems_client/models/subgraph_quota_response.py rename to robosystems_client/models/subgraph_limits.py index 1e5c241..1b0f0ab 100644 --- a/robosystems_client/models/subgraph_quota_response.py +++ b/robosystems_client/models/subgraph_limits.py @@ -8,39 +8,35 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="SubgraphQuotaResponse") +T = TypeVar("T", bound="SubgraphLimits") @_attrs_define -class SubgraphQuotaResponse: - """Response model for subgraph quota information. - - Attributes: - parent_graph_id (str): Parent graph identifier - tier (str): Graph tier - current_count (int): Current number of subgraphs - max_allowed (int | None | Unset): Maximum allowed subgraphs (None = unlimited) - remaining (int | None | Unset): Remaining subgraphs that can be created - total_size_mb (float | None | Unset): Total size of all subgraphs - max_size_mb (float | None | Unset): Maximum allowed total size +class SubgraphLimits: + """Subgraph count against the parent graph tier's cap. + + Subgraphs are refused at the tier cap regardless of how small they are, + so this is a count axis independent of the storage one — ``instance`` + already itemizes their footprint. + + Attributes: + current_count (int): Subgraphs currently provisioned under this graph + approaching_limit (bool): Whether approaching subgraph limit (>80%) + max_allowed (int | None | Unset): Maximum subgraphs for this tier (null when uncapped) + remaining (int | None | Unset): Subgraphs that can still be created (null when uncapped) """ - parent_graph_id: str - tier: str current_count: int + approaching_limit: bool max_allowed: int | None | Unset = UNSET remaining: int | None | Unset = UNSET - total_size_mb: float | None | Unset = UNSET - max_size_mb: float | None | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - parent_graph_id = self.parent_graph_id - - tier = self.tier - current_count = self.current_count + approaching_limit = self.approaching_limit + max_allowed: int | None | Unset if isinstance(self.max_allowed, Unset): max_allowed = UNSET @@ -53,47 +49,28 @@ def to_dict(self) -> dict[str, Any]: else: remaining = self.remaining - total_size_mb: float | None | Unset - if isinstance(self.total_size_mb, Unset): - total_size_mb = UNSET - else: - total_size_mb = self.total_size_mb - - max_size_mb: float | None | Unset - if isinstance(self.max_size_mb, Unset): - max_size_mb = UNSET - else: - max_size_mb = self.max_size_mb - field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "parent_graph_id": parent_graph_id, - "tier": tier, "current_count": current_count, + "approaching_limit": approaching_limit, } ) if max_allowed is not UNSET: field_dict["max_allowed"] = max_allowed if remaining is not UNSET: field_dict["remaining"] = remaining - if total_size_mb is not UNSET: - field_dict["total_size_mb"] = total_size_mb - if max_size_mb is not UNSET: - field_dict["max_size_mb"] = max_size_mb return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - parent_graph_id = d.pop("parent_graph_id") - - tier = d.pop("tier") - current_count = d.pop("current_count") + approaching_limit = d.pop("approaching_limit") + def _parse_max_allowed(data: object) -> int | None | Unset: if data is None: return data @@ -112,36 +89,15 @@ def _parse_remaining(data: object) -> int | None | Unset: remaining = _parse_remaining(d.pop("remaining", UNSET)) - def _parse_total_size_mb(data: object) -> float | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(float | None | Unset, data) - - total_size_mb = _parse_total_size_mb(d.pop("total_size_mb", UNSET)) - - def _parse_max_size_mb(data: object) -> float | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(float | None | Unset, data) - - max_size_mb = _parse_max_size_mb(d.pop("max_size_mb", UNSET)) - - subgraph_quota_response = cls( - parent_graph_id=parent_graph_id, - tier=tier, + subgraph_limits = cls( current_count=current_count, + approaching_limit=approaching_limit, max_allowed=max_allowed, remaining=remaining, - total_size_mb=total_size_mb, - max_size_mb=max_size_mb, ) - subgraph_quota_response.additional_properties = d - return subgraph_quota_response + subgraph_limits.additional_properties = d + return subgraph_limits @property def additional_keys(self) -> list[str]: