codemie-sdk-python 0.1.703__tar.gz → 0.1.705__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.
Files changed (83) hide show
  1. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/PKG-INFO +1 -1
  2. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/pyproject.toml +1 -1
  3. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/__init__.py +2 -2
  4. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/client/client.py +4 -0
  5. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/a2a.py +26 -15
  6. codemie_sdk_python-0.1.705/src/codemie_sdk/models/servicenow_integration.py +103 -0
  7. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/a2a.py +1 -1
  8. codemie_sdk_python-0.1.705/src/codemie_sdk/services/servicenow_integration.py +90 -0
  9. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/README.md +0 -0
  10. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/auth/__init__.py +0 -0
  11. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/auth/credentials.py +0 -0
  12. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/builders/__init__.py +0 -0
  13. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/builders/workflow/__init__.py +0 -0
  14. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/builders/workflow/builder.py +0 -0
  15. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/builders/workflow/definition.py +0 -0
  16. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/builders/workflow/publish.py +0 -0
  17. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/client/__init__.py +0 -0
  18. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/exceptions.py +0 -0
  19. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/__init__.py +0 -0
  20. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/activity_event.py +0 -0
  21. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/admin.py +0 -0
  22. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/analytics.py +0 -0
  23. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/assistant.py +0 -0
  24. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/categories.py +0 -0
  25. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/common.py +0 -0
  26. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/conversation.py +0 -0
  27. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/cost_center.py +0 -0
  28. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/datasource.py +0 -0
  29. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/errors.py +0 -0
  30. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/file_operation.py +0 -0
  31. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/guardrails.py +0 -0
  32. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/integration.py +0 -0
  33. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/llm.py +0 -0
  34. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/mcp_config.py +0 -0
  35. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/mermaid.py +0 -0
  36. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/project.py +0 -0
  37. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/skill.py +0 -0
  38. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/task.py +0 -0
  39. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/user.py +0 -0
  40. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/vendor_assistant.py +0 -0
  41. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/vendor_guardrail.py +0 -0
  42. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/vendor_knowledgebase.py +0 -0
  43. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/vendor_runtime.py +0 -0
  44. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/vendor_workflow.py +0 -0
  45. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/workflow.py +0 -0
  46. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/workflow_execution_payload.py +0 -0
  47. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/workflow_state.py +0 -0
  48. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/workflow_thoughts.py +0 -0
  49. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/workflow_transition.py +0 -0
  50. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/models/workspace.py +0 -0
  51. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/activity_event.py +0 -0
  52. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/admin.py +0 -0
  53. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/analytics.py +0 -0
  54. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/assistant.py +0 -0
  55. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/categories.py +0 -0
  56. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/codemie_guardrails.py +0 -0
  57. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/conversation.py +0 -0
  58. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/cost_center.py +0 -0
  59. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/customer_config_service.py +0 -0
  60. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/datasource.py +0 -0
  61. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/dynamic_config.py +0 -0
  62. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/files.py +0 -0
  63. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/integration.py +0 -0
  64. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/llm.py +0 -0
  65. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/mcp_configs.py +0 -0
  66. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/mermaid.py +0 -0
  67. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/project.py +0 -0
  68. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/project_budget_groups.py +0 -0
  69. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/skill.py +0 -0
  70. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/task.py +0 -0
  71. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/user.py +0 -0
  72. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/vendor_assistant.py +0 -0
  73. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/vendor_guardrail.py +0 -0
  74. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/vendor_knowledgebase.py +0 -0
  75. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/vendor_runtime.py +0 -0
  76. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/vendor_workflow.py +0 -0
  77. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/webhook.py +0 -0
  78. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/workflow.py +0 -0
  79. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/workflow_execution.py +0 -0
  80. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/workflow_execution_state.py +0 -0
  81. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/services/workspace.py +0 -0
  82. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/utils/__init__.py +0 -0
  83. {codemie_sdk_python-0.1.703 → codemie_sdk_python-0.1.705}/src/codemie_sdk/utils/http.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codemie-sdk-python
3
- Version: 0.1.703
3
+ Version: 0.1.705
4
4
  Summary: CodeMie SDK for Python
5
5
  License: Apache-2.0
6
6
  Author: CodeMie
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "codemie-sdk-python"
3
- version = "0.1.703"
3
+ version = "0.1.705"
4
4
  description = "CodeMie SDK for Python"
5
5
  authors = ["CodeMie"]
6
6
  license = "Apache-2.0"
@@ -170,8 +170,8 @@ from .models.integration import (
170
170
  from .models.a2a import (
171
171
  AgentCard,
172
172
  AgentProvider,
173
+ AgentInterface,
173
174
  AgentCapabilities,
174
- AgentAuthentication,
175
175
  AgentSkill,
176
176
  )
177
177
  from .services.a2a import A2AService
@@ -307,8 +307,8 @@ __all__ = [
307
307
  "TypeOfIntegration",
308
308
  "AgentCard",
309
309
  "AgentProvider",
310
+ "AgentInterface",
310
311
  "AgentCapabilities",
311
- "AgentAuthentication",
312
312
  "AgentSkill",
313
313
  "A2AService",
314
314
  ]
@@ -33,6 +33,7 @@ from ..services.mcp_configs import MCPConfigsService
33
33
  from ..services.cost_center import CostCenterService
34
34
  from ..services.customer_config_service import CustomerConfigService
35
35
  from ..services.project_budget_groups import ProjectBudgetGroupsService
36
+ from ..services.servicenow_integration import ServiceNowIntegrationService
36
37
 
37
38
 
38
39
  class CodeMieClient:
@@ -183,6 +184,9 @@ class CodeMieClient:
183
184
  self.project_budget_groups = ProjectBudgetGroupsService(
184
185
  self._api_domain, _token_source, verify_ssl=self._verify_ssl
185
186
  )
187
+ self.servicenow_integration = ServiceNowIntegrationService(
188
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
189
+ )
186
190
  self.a2a = A2AService(
187
191
  self._api_domain, _token_source, verify_ssl=self._verify_ssl
188
192
  )
@@ -1,4 +1,6 @@
1
- """A2A (agent-to-agent) models."""
1
+ """A2A (agent-to-agent) models (protocol v1.0)."""
2
+
3
+ from typing import Any
2
4
 
3
5
  from pydantic import BaseModel, ConfigDict
4
6
 
@@ -8,27 +10,28 @@ class AgentProvider(BaseModel):
8
10
 
9
11
  model_config = ConfigDict(extra="ignore")
10
12
 
11
- organization: str
13
+ organization: str | None = None
12
14
  url: str | None = None
13
15
 
14
16
 
15
- class AgentCapabilities(BaseModel):
16
- """Capabilities advertised by an A2A agent card."""
17
+ class AgentInterface(BaseModel):
18
+ """A transport interface the agent exposes."""
17
19
 
18
20
  model_config = ConfigDict(extra="ignore")
19
21
 
20
- streaming: bool = False
21
- pushNotifications: bool = False
22
- stateTransitionHistory: bool = False
22
+ url: str
23
+ protocolBinding: str | None = None
24
+ protocolVersion: str | None = None
23
25
 
24
26
 
25
- class AgentAuthentication(BaseModel):
26
- """Authentication schemes advertised by an A2A agent card."""
27
+ class AgentCapabilities(BaseModel):
28
+ """Capabilities advertised by an A2A agent card."""
27
29
 
28
30
  model_config = ConfigDict(extra="ignore")
29
31
 
30
- schemes: list[str]
31
- credentials: str | None = None
32
+ streaming: bool = False
33
+ pushNotifications: bool = False
34
+ extendedAgentCard: bool = False
32
35
 
33
36
 
34
37
  class AgentSkill(BaseModel):
@@ -52,12 +55,20 @@ class AgentCard(BaseModel):
52
55
 
53
56
  name: str
54
57
  description: str | None = None
55
- url: str
58
+ supportedInterfaces: list[AgentInterface]
56
59
  provider: AgentProvider | None = None
57
60
  version: str
58
61
  documentationUrl: str | None = None
59
62
  capabilities: AgentCapabilities
60
- authentication: AgentAuthentication | None = None
61
- defaultInputModes: list[str] = ["text"]
62
- defaultOutputModes: list[str] = ["text"]
63
+ securitySchemes: dict[str, dict[str, Any]] | None = None
64
+ securityRequirements: list[dict[str, Any]] | None = None
65
+ defaultInputModes: list[str] = []
66
+ defaultOutputModes: list[str] = []
63
67
  skills: list[AgentSkill]
68
+
69
+ @property
70
+ def protocol_version(self) -> str | None:
71
+ """Protocol version of the first advertised interface."""
72
+ if self.supportedInterfaces:
73
+ return self.supportedInterfaces[0].protocolVersion
74
+ return None
@@ -0,0 +1,103 @@
1
+ # Copyright 2026 EPAM Systems, Inc. ("EPAM")
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """ServiceNow integration models for the CodeMie SDK.
16
+
17
+ The integration endpoints are callable only by the ServiceNow integration service account.
18
+ The request model is deliberately permissive: the server owns the validation rules, so the
19
+ SDK sends what the caller gives it and surfaces the server's verdict as an HTTP error.
20
+ """
21
+
22
+ from enum import Enum
23
+
24
+ from pydantic import BaseModel, ConfigDict, Field
25
+
26
+
27
+ class ServiceNowBudgetAction(str, Enum):
28
+ """Budget action requested by ServiceNow."""
29
+
30
+ SET = "set"
31
+ ADJUST = "adjust"
32
+ CANCEL = "cancel"
33
+
34
+
35
+ class ServiceNowProject(BaseModel):
36
+ """A shared project returned by the project lookup."""
37
+
38
+ model_config = ConfigDict(extra="ignore")
39
+
40
+ project_name: str
41
+ display_name: str | None = None
42
+
43
+
44
+ class ServiceNowBudgetRequest(BaseModel):
45
+ """Request body for applying a ServiceNow budget request to a project.
46
+
47
+ Attributes:
48
+ action: ``set`` replaces the budget, ``adjust`` merges into it, ``cancel`` deletes it.
49
+ request_id: ServiceNow request number, used for audit logs and new budget names.
50
+ epam_project_code: EPAM project code; names the cost center when it differs from
51
+ the CodeMie project name.
52
+ codemie_project_name: CodeMie project to manage; the server defaults it to
53
+ ``epam_project_code`` when omitted.
54
+ admin_emails: People to make project admins (ignored by ``cancel``).
55
+ amounts: Monthly budget in USD per category (``platform``, ``cli``,
56
+ ``premium_models``); required for ``set`` and ``adjust``.
57
+ """
58
+
59
+ # Non-finite amounts are sent as the JSON constants NaN / Infinity instead of null,
60
+ # so the server, not the client, rejects them.
61
+ model_config = ConfigDict(ser_json_inf_nan="constants")
62
+
63
+ action: ServiceNowBudgetAction
64
+ request_id: str
65
+ epam_project_code: str
66
+ codemie_project_name: str | None = None
67
+ admin_emails: list[str] = Field(default_factory=list)
68
+ amounts: dict[str, float] | None = None
69
+
70
+
71
+ class ServiceNowBudgetCategory(BaseModel):
72
+ """Budget of one spend category in a budget response."""
73
+
74
+ model_config = ConfigDict(extra="ignore")
75
+
76
+ category: str
77
+ max_budget: float
78
+ soft_budget: float
79
+ budget_reset_at: str | None = None
80
+
81
+
82
+ class ServiceNowBudgetGroup(BaseModel):
83
+ """Budget of a project after the request, with its categories in a fixed order."""
84
+
85
+ model_config = ConfigDict(extra="ignore")
86
+
87
+ total_amount: float
88
+ budget_duration: str
89
+ categories: list[ServiceNowBudgetCategory]
90
+
91
+
92
+ class ServiceNowBudgetResponse(BaseModel):
93
+ """Outcome of a budget request."""
94
+
95
+ model_config = ConfigDict(extra="ignore")
96
+
97
+ project_name: str
98
+ cost_center: str | None = None
99
+ created_project: bool
100
+ created_cost_center: bool
101
+ budget: ServiceNowBudgetGroup | None = None
102
+ admins_assigned: list[str] = Field(default_factory=list)
103
+ admins_pending: list[str] = Field(default_factory=list)
@@ -27,7 +27,7 @@ class A2AService:
27
27
  AgentCard: agent discovery metadata for the assistant
28
28
  """
29
29
  return self._api.get(
30
- f"/v1/a2a/assistants/{assistant_id}/.well-known/agent.json",
30
+ f"/v1/a2a/assistants/{assistant_id}/.well-known/agent-card.json",
31
31
  AgentCard,
32
32
  wrap_response=False,
33
33
  )
@@ -0,0 +1,90 @@
1
+ # Copyright 2026 EPAM Systems, Inc. ("EPAM")
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """ServiceNow integration service for the CodeMie SDK."""
16
+
17
+ from ..models.servicenow_integration import (
18
+ ServiceNowBudgetRequest,
19
+ ServiceNowBudgetResponse,
20
+ ServiceNowProject,
21
+ )
22
+ from ..utils.http import ApiRequestHandler, TokenSource
23
+
24
+
25
+ class ServiceNowIntegrationService:
26
+ """Service for the ServiceNow integration endpoints.
27
+
28
+ Only the ServiceNow integration service account may call these endpoints; any other
29
+ caller is rejected with HTTP 403.
30
+ """
31
+
32
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
33
+ """Initialize the ServiceNowIntegrationService.
34
+
35
+ Args:
36
+ api_domain: Base URL for the CodeMie API
37
+ token: Authentication token
38
+ verify_ssl: Whether to verify SSL certificates
39
+ """
40
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
41
+
42
+ def list_projects(self, emails: list[str]) -> list[ServiceNowProject]:
43
+ """List the shared projects that any of the given users belong to.
44
+
45
+ The result is the distinct union across all emails, ordered by project name.
46
+ Emails with no active CodeMie user are skipped, and an empty list is returned
47
+ when none match. The emails are sent as given; the server rejects an empty
48
+ list or an invalid email with HTTP 422.
49
+
50
+ Args:
51
+ emails: Requester and approver emails
52
+
53
+ Returns:
54
+ List of ServiceNowProject with the project name and display name
55
+
56
+ Raises:
57
+ HTTPError: If the request fails
58
+ """
59
+ return self._api.get(
60
+ "/v1/integrations/servicenow/projects",
61
+ response_model=list[ServiceNowProject],
62
+ params={"emails": emails},
63
+ wrap_response=False,
64
+ )
65
+
66
+ def submit_budget_request(
67
+ self, request: ServiceNowBudgetRequest
68
+ ) -> ServiceNowBudgetResponse:
69
+ """Apply a ServiceNow budget request to a project.
70
+
71
+ ``set`` replaces the project budget, ``adjust`` merges into it and ``cancel``
72
+ deletes it. The project (and its cost center) is created when it does not exist,
73
+ and every resolvable ``admin_emails`` user becomes a project admin.
74
+
75
+ Args:
76
+ request: The budget request
77
+
78
+ Returns:
79
+ ServiceNowBudgetResponse with the resolved project, cost center, the budget
80
+ after the request (None after cancel) and the admin assignment outcome
81
+
82
+ Raises:
83
+ HTTPError: If the request is rejected (400, 403, 404, 409 or 422)
84
+ """
85
+ return self._api.post(
86
+ "/v1/integrations/servicenow/budgets",
87
+ response_model=ServiceNowBudgetResponse,
88
+ data=request.model_dump_json(exclude_none=True),
89
+ wrap_response=False,
90
+ )