aidial-sdk 0.44.0.dev4__tar.gz → 0.45.0__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 (62) hide show
  1. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/PKG-INFO +1 -1
  2. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/__init__.py +6 -0
  3. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/application.py +2 -0
  4. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/choice.py +14 -1
  5. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/chunks.py +17 -12
  6. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/request.py +1 -0
  7. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/stage.py +54 -6
  8. aidial_sdk-0.45.0/aidial_sdk/response_headers.py +95 -0
  9. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/telemetry/init.py +18 -0
  10. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/telemetry/types.py +4 -0
  11. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/pyproject.toml +1 -1
  12. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/LICENSE +0 -0
  13. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/README.md +0 -0
  14. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/_errors.py +0 -0
  15. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/_pydantic/__init__.py +0 -0
  16. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/_pydantic/_compat.py +0 -0
  17. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/_pydantic/_model_config.py +0 -0
  18. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/__init__.py +0 -0
  19. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/_cache.py +0 -0
  20. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/_types.py +0 -0
  21. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/base.py +0 -0
  22. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/choice_base.py +0 -0
  23. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/enums.py +0 -0
  24. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/form.py +0 -0
  25. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/function_call.py +0 -0
  26. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/function_tool_call.py +0 -0
  27. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/chat_completion/response.py +0 -0
  28. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/__init__.py +0 -0
  29. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/_headers.py +0 -0
  30. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/configuration.py +0 -0
  31. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/from_request_mixin.py +0 -0
  32. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/rate.py +0 -0
  33. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/tokenize.py +0 -0
  34. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/deployment/truncate_prompt.py +0 -0
  35. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/embeddings/__init__.py +0 -0
  36. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/embeddings/base.py +0 -0
  37. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/embeddings/request.py +0 -0
  38. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/embeddings/response.py +0 -0
  39. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/exceptions.py +0 -0
  40. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/header_propagator.py +0 -0
  41. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/py.typed +0 -0
  42. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/pydantic/v2.py +0 -0
  43. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/pydantic_v1/__init__.py +0 -0
  44. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/telemetry/__init__.py +0 -0
  45. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/telemetry/_context.py +0 -0
  46. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/__init__.py +0 -0
  47. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_attachment.py +0 -0
  48. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_cancel_scope.py +0 -0
  49. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_content_stream.py +0 -0
  50. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_disconnect_middleware.py +0 -0
  51. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_indexed_list.py +0 -0
  52. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_json_log_formatter.py +0 -0
  53. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_logging.py +0 -0
  54. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/_reflection.py +0 -0
  55. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/env.py +0 -0
  56. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/errors.py +0 -0
  57. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/json.py +0 -0
  58. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/log_config.py +0 -0
  59. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/logging.py +0 -0
  60. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/merge_chunks.py +0 -0
  61. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/pydantic.py +0 -0
  62. {aidial_sdk-0.44.0.dev4 → aidial_sdk-0.45.0}/aidial_sdk/utils/streaming.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aidial-sdk
3
- Version: 0.44.0.dev4
3
+ Version: 0.45.0
4
4
  Summary: Framework to create applications and model adapters for AI DIAL
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,5 +1,9 @@
1
1
  from aidial_sdk.application import DIALApp
2
2
  from aidial_sdk.exceptions import HTTPException
3
+ from aidial_sdk.response_headers import (
4
+ NonForwardableHeadersMiddleware,
5
+ strip_stale_content_headers,
6
+ )
3
7
  from aidial_sdk.utils.log_config import LogConfig, configure_root_logger
4
8
  from aidial_sdk.utils.logging import logger
5
9
 
@@ -7,6 +11,8 @@ __all__ = [
7
11
  "DIALApp",
8
12
  "HTTPException",
9
13
  "LogConfig",
14
+ "NonForwardableHeadersMiddleware",
10
15
  "configure_root_logger",
11
16
  "logger",
17
+ "strip_stale_content_headers",
12
18
  ]
@@ -34,6 +34,7 @@ from aidial_sdk.embeddings.request import Request as EmbeddingsRequest
34
34
  from aidial_sdk.exceptions import DeploymentNotFoundError
35
35
  from aidial_sdk.exceptions import HTTPException as DIALException
36
36
  from aidial_sdk.header_propagator import HeaderPropagator
37
+ from aidial_sdk.response_headers import NonForwardableHeadersMiddleware
37
38
  from aidial_sdk.telemetry.types import TelemetryConfig
38
39
  from aidial_sdk.utils._disconnect_middleware import DisconnectMiddleware
39
40
  from aidial_sdk.utils._reflection import get_method_implementation
@@ -136,6 +137,7 @@ class DIALApp(FastAPI):
136
137
  logging.getLogger("uvicorn.access").addFilter(PathFilter(path))
137
138
 
138
139
  self.add_middleware(DisconnectMiddleware)
140
+ self.add_middleware(NonForwardableHeadersMiddleware)
139
141
 
140
142
  self.add_exception_handler(
141
143
  ValidationError, pydantic_validation_exception_handler
@@ -195,12 +195,25 @@ class Choice(ChoiceBase):
195
195
  self.send_chunk(FormSchemaChunk(self._index, form_schema))
196
196
 
197
197
  def create_stage(self, name: str | None = None) -> Stage:
198
+ return self._create_stage(name, parent=None)
199
+
200
+ def _create_stage(
201
+ self,
202
+ name: str | None = None,
203
+ *,
204
+ parent: Stage | None = None,
205
+ ) -> Stage:
198
206
  if not self._opened:
199
207
  raise runtime_error("Trying to create stage to an unopened choice")
200
208
  if self._closed:
201
209
  raise runtime_error("Trying to create stage to a closed choice")
202
210
 
203
- stage = Stage(self._queue, self._index, self._last_stage_index, name)
211
+ stage = Stage(
212
+ self,
213
+ self._last_stage_index,
214
+ name,
215
+ parent,
216
+ )
204
217
  self._last_stage_index += 1
205
218
 
206
219
  return stage
@@ -211,29 +211,34 @@ class StartStageChunk(BaseChunk):
211
211
  choice_index: int
212
212
  stage_index: int
213
213
  name: str | None
214
+ parent_stage_index: int | None
214
215
 
215
- def __init__(self, choice_index: int, stage_index: int, name: str | None):
216
+ def __init__(
217
+ self,
218
+ choice_index: int,
219
+ stage_index: int,
220
+ name: str | None,
221
+ parent_stage_index: int | None = None,
222
+ ):
216
223
  self.choice_index = choice_index
217
224
  self.stage_index = stage_index
218
225
  self.name = name
226
+ self.parent_stage_index = parent_stage_index
219
227
 
220
228
  def to_dict(self):
229
+ stage: dict[str, Any] = {
230
+ "index": self.stage_index,
231
+ "name": self.name,
232
+ "status": None,
233
+ }
234
+ if self.parent_stage_index is not None:
235
+ stage["parent_stage_index"] = self.parent_stage_index
221
236
  return {
222
237
  "choices": [
223
238
  {
224
239
  "index": self.choice_index,
225
240
  "finish_reason": None,
226
- "delta": {
227
- "custom_content": {
228
- "stages": [
229
- {
230
- "index": self.stage_index,
231
- "name": self.name,
232
- "status": None,
233
- }
234
- ]
235
- }
236
- },
241
+ "delta": {"custom_content": {"stages": [stage]}},
237
242
  }
238
243
  ],
239
244
  "usage": None,
@@ -46,6 +46,7 @@ class Stage(ExtraAllowModel, IgnoreIndex):
46
46
  status: Status
47
47
  content: StrictStr | None = None
48
48
  attachments: list[Attachment] | None = None
49
+ parent_stage_index: StrictInt | None = None
49
50
 
50
51
 
51
52
  class CustomContent(ExtraAllowModel):
@@ -1,5 +1,5 @@
1
1
  from types import TracebackType
2
- from typing import overload
2
+ from typing import TYPE_CHECKING, overload
3
3
 
4
4
  from aidial_sdk._pydantic import ValidationError
5
5
  from aidial_sdk.chat_completion._types import ChunkQueue
@@ -15,31 +15,52 @@ from aidial_sdk.chat_completion.request import Attachment
15
15
  from aidial_sdk.utils._attachment import create_attachment
16
16
  from aidial_sdk.utils._content_stream import ContentStream
17
17
  from aidial_sdk.utils.errors import runtime_error
18
+ from aidial_sdk.utils.logging import log_warning
19
+
20
+ if TYPE_CHECKING:
21
+ from aidial_sdk.chat_completion.choice import Choice
18
22
 
19
23
 
20
24
  class Stage:
25
+ _choice: "Choice"
21
26
  _queue: ChunkQueue
22
27
  _choice_index: int
23
28
  _stage_index: int
24
29
  _name: str | None
30
+ _parent: "Stage | None"
31
+ _children: list["Stage"]
25
32
  _last_attachment_index: int
26
33
  _closed: bool
27
34
  _opened: bool
28
35
 
29
36
  def __init__(
30
37
  self,
31
- queue: ChunkQueue,
32
- choice_index: int,
38
+ choice: "Choice",
33
39
  stage_index: int,
34
40
  name: str | None = None,
41
+ parent: "Stage | None" = None,
35
42
  ):
36
- self._queue = queue
37
- self._choice_index = choice_index
43
+ if parent is not None and parent._choice is not choice:
44
+ raise runtime_error(
45
+ "Trying to create a stage whose parent stage belongs to another choice"
46
+ )
47
+
48
+ self._choice = choice
49
+ self._queue = choice._queue
50
+ self._choice_index = choice.index
38
51
  self._stage_index = stage_index
39
52
  self._last_attachment_index = 0
40
53
  self._opened = False
41
54
  self._closed = False
42
55
  self._name = name
56
+ self._parent = parent
57
+ self._children = []
58
+
59
+ if parent is not None:
60
+ parent._children.append(self)
61
+
62
+ def create_stage(self, name: str | None = None) -> "Stage":
63
+ return self._choice._create_stage(name, parent=self)
43
64
 
44
65
  def __enter__(self):
45
66
  self.open()
@@ -119,9 +140,25 @@ class Stage:
119
140
  if self._opened:
120
141
  raise runtime_error("The stage is already open")
121
142
 
143
+ parent = self._parent
144
+ if parent is not None:
145
+ if not parent._opened:
146
+ raise runtime_error(
147
+ "Trying to open a stage whose parent stage is not open"
148
+ )
149
+ if parent._closed:
150
+ raise runtime_error(
151
+ "Trying to open a stage whose parent stage is already closed"
152
+ )
153
+
122
154
  self._opened = True
123
155
  self._queue.put_nowait(
124
- StartStageChunk(self._choice_index, self._stage_index, self._name)
156
+ StartStageChunk(
157
+ self._choice_index,
158
+ self._stage_index,
159
+ self._name,
160
+ parent._stage_index if parent is not None else None,
161
+ )
125
162
  )
126
163
 
127
164
  def close(self, status: Status = Status.COMPLETED):
@@ -130,6 +167,17 @@ class Stage:
130
167
  if self._closed:
131
168
  raise runtime_error("The stage is already closed")
132
169
 
170
+ open_children = [
171
+ child._stage_index
172
+ for child in self._children
173
+ if child._opened and not child._closed
174
+ ]
175
+ if open_children:
176
+ log_warning(
177
+ f"Closing the stage {self._stage_index} which still has "
178
+ f"open child stages: {open_children}"
179
+ )
180
+
133
181
  self._closed = True
134
182
  self._queue.put_nowait(
135
183
  FinishStageChunk(self._choice_index, self._stage_index, status)
@@ -0,0 +1,95 @@
1
+ """Response headers a DIAL component must not relay downstream.
2
+
3
+ A component sitting in front of an upstream API - a model adapter proxying the
4
+ vendor's response, an interceptor rebuilding it - receives the upstream's
5
+ response headers and tends to pass them on. Some of them describe the
6
+ **upstream hop**, not the response the component itself emits:
7
+
8
+ * hop-by-hop headers (RFC 9110 7.6.1). ``transfer-encoding`` is the harmful
9
+ one: the ASGI server computes its own ``content-length`` for the body the
10
+ component emits, and a message carrying both is rejected by a strict HTTP
11
+ parser (RFC 9112 6.2) - DIAL Core being one. A relayed ``connection: close``
12
+ tears down the *downstream* connection once the response is over.
13
+ * ``server`` and ``date``, which the ASGI server supplies itself. Both are
14
+ singleton fields (RFC 9110 5.6.6), so the upstream's copy duplicates them.
15
+
16
+ Which headers these are follows from the HTTP spec alone, never from what the
17
+ component does, so ``NonForwardableHeadersMiddleware`` strips them from every
18
+ response the app emits and takes no configuration:
19
+
20
+ * an app built on ``DIALApp`` has it installed already - nothing to do;
21
+ * an app built on plain ``FastAPI``/``Starlette`` installs it once::
22
+
23
+ app = FastAPI()
24
+ app.add_middleware(NonForwardableHeadersMiddleware)
25
+
26
+ It covers the whole app, including sub-apps mounted into it, so a passthrough
27
+ proxy mounted as one needs no strip of its own.
28
+
29
+ ``content-length`` and ``content-encoding`` are a different matter: they are
30
+ accurate for the upstream body and go stale only once a component reads and
31
+ rebuilds it. The middleware cannot tell a stale one from the correct one the
32
+ ASGI server has just computed, so the rebuilding code drops them itself, on the
33
+ upstream headers it is about to reuse::
34
+
35
+ body = await upstream_response.aread()
36
+ strip_stale_content_headers(upstream_response.headers)
37
+ return Response(content=body, headers=upstream_response.headers)
38
+ """
39
+
40
+ from collections.abc import MutableMapping
41
+
42
+ from starlette.types import ASGIApp, Message, Receive, Scope, Send
43
+
44
+ _HOP_BY_HOP_HEADERS = frozenset(
45
+ {
46
+ b"connection",
47
+ b"keep-alive",
48
+ b"proxy-authenticate",
49
+ b"proxy-authorization",
50
+ b"te",
51
+ b"trailer",
52
+ b"transfer-encoding",
53
+ b"upgrade",
54
+ }
55
+ )
56
+
57
+ _SERVER_MANAGED_HEADERS = frozenset({b"server", b"date"})
58
+
59
+ _NON_FORWARDABLE_HEADERS = _HOP_BY_HOP_HEADERS | _SERVER_MANAGED_HEADERS
60
+
61
+ _STALE_CONTENT_HEADERS = ("content-length", "content-encoding")
62
+
63
+
64
+ class NonForwardableHeadersMiddleware:
65
+ def __init__(self, app: ASGIApp) -> None:
66
+ self.app = app
67
+
68
+ async def __call__(
69
+ self, scope: Scope, receive: Receive, send: Send
70
+ ) -> None:
71
+ if scope["type"] != "http":
72
+ await self.app(scope, receive, send)
73
+ return
74
+
75
+ async def send_wrapper(message: Message) -> None:
76
+ if message["type"] == "http.response.start":
77
+ message["headers"] = [
78
+ (key, value)
79
+ for key, value in message["headers"]
80
+ if key.lower() not in _NON_FORWARDABLE_HEADERS
81
+ ]
82
+ await send(message)
83
+
84
+ await self.app(scope, receive, send_wrapper)
85
+
86
+
87
+ def strip_stale_content_headers(headers: MutableMapping[str, str]) -> None:
88
+ """Drop from `headers` the content headers describing the upstream body.
89
+
90
+ Call it on the upstream response headers once the body they describe has
91
+ been read and rebuilt, so that the framing and the content coding of the
92
+ new body are recomputed rather than inherited.
93
+ """
94
+ for header in _STALE_CONTENT_HEADERS:
95
+ headers.pop(header, None)
@@ -37,6 +37,8 @@ from prometheus_client import start_http_server
37
37
  from aidial_sdk.telemetry.types import TelemetryConfig
38
38
  from aidial_sdk.utils._logging import remove_stream_handlers
39
39
 
40
+ _log = logging.getLogger(__name__)
41
+
40
42
 
41
43
  def init_telemetry(app: FastAPI | None, config: TelemetryConfig):
42
44
  resource = Resource.create(
@@ -142,4 +144,20 @@ def init_telemetry(app: FastAPI | None, config: TelemetryConfig):
142
144
 
143
145
  if app and (config.tracing is not None or config.metrics is not None):
144
146
  # FastAPI instrumentor reports both metrics and traces
147
+ excl = config.tracing.excluded_asgi_spans if config.tracing else []
148
+ _instrument_fastapi_app(app, excl)
149
+
150
+
151
+ def _instrument_fastapi_app(app: FastAPI, exclude_spans: list[str]) -> None:
152
+ if not exclude_spans:
153
+ FastAPIInstrumentor.instrument_app(app)
154
+ return
155
+
156
+ try:
157
+ FastAPIInstrumentor.instrument_app(app, exclude_spans=exclude_spans) # type: ignore
158
+ except TypeError:
159
+ _log.warning(
160
+ "OTEL_PYTHON_FASTAPI_EXCLUDE_SPANS is ignored: it requires "
161
+ "opentelemetry-instrumentation-fastapi>=0.48b0."
162
+ )
145
163
  FastAPIInstrumentor.instrument_app(app)
@@ -16,6 +16,9 @@ OTEL_EXPORTER_PROMETHEUS_PORT = int(
16
16
  OTEL_PYTHON_LOG_CORRELATION = (
17
17
  os.getenv("OTEL_PYTHON_LOG_CORRELATION", "false").lower() == "true"
18
18
  )
19
+ OTEL_PYTHON_FASTAPI_EXCLUDE_SPANS = env_var_list(
20
+ "OTEL_PYTHON_FASTAPI_EXCLUDE_SPANS"
21
+ )
19
22
 
20
23
 
21
24
  class LogsConfig(BaseModel):
@@ -30,6 +33,7 @@ class LogsConfig(BaseModel):
30
33
  class TracingConfig(BaseModel):
31
34
  otlp_export: bool = "otlp" in OTEL_TRACES_EXPORTER
32
35
  logging: bool = OTEL_PYTHON_LOG_CORRELATION
36
+ excluded_asgi_spans: list[str] = OTEL_PYTHON_FASTAPI_EXCLUDE_SPANS
33
37
 
34
38
 
35
39
  class MetricsConfig(BaseModel):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aidial-sdk"
3
- version = "0.44.0.dev4"
3
+ version = "0.45.0"
4
4
  description = "Framework to create applications and model adapters for AI DIAL"
5
5
  authors = [{ name = "EPAM RAIL", email = "SpecialEPM-DIALDevTeam@epam.com" }]
6
6
  license = "Apache-2.0"
File without changes
File without changes