agenta 0.27.3__py3-none-any.whl → 0.27.4a1__py3-none-any.whl

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.

Potentially problematic release.


This version of agenta might be problematic. Click here for more details.

Files changed (53) hide show
  1. agenta/client/backend/__init__.py +63 -0
  2. agenta/client/backend/client.py +22 -22
  3. agenta/client/backend/core/http_client.py +15 -7
  4. agenta/client/backend/observability/client.py +4 -4
  5. agenta/client/backend/observability_v_1/__init__.py +5 -0
  6. agenta/client/backend/observability_v_1/client.py +560 -0
  7. agenta/client/backend/observability_v_1/types/__init__.py +6 -0
  8. agenta/client/backend/observability_v_1/types/format.py +5 -0
  9. agenta/client/backend/observability_v_1/types/query_traces_response.py +11 -0
  10. agenta/client/backend/types/__init__.py +58 -0
  11. agenta/client/backend/types/agenta_node_dto.py +48 -0
  12. agenta/client/backend/types/agenta_node_dto_nodes_value.py +6 -0
  13. agenta/client/backend/types/agenta_nodes_response.py +30 -0
  14. agenta/client/backend/types/agenta_root_dto.py +30 -0
  15. agenta/client/backend/types/agenta_roots_response.py +30 -0
  16. agenta/client/backend/types/agenta_tree_dto.py +30 -0
  17. agenta/client/backend/types/agenta_trees_response.py +30 -0
  18. agenta/client/backend/types/collect_status_response.py +22 -0
  19. agenta/client/backend/types/exception_dto.py +26 -0
  20. agenta/client/backend/types/link_dto.py +24 -0
  21. agenta/client/backend/types/node_dto.py +24 -0
  22. agenta/client/backend/types/node_type.py +19 -0
  23. agenta/client/backend/types/o_tel_context_dto.py +22 -0
  24. agenta/client/backend/types/o_tel_event_dto.py +23 -0
  25. agenta/client/backend/types/o_tel_extra_dto.py +26 -0
  26. agenta/client/backend/types/o_tel_link_dto.py +23 -0
  27. agenta/client/backend/types/o_tel_span_dto.py +37 -0
  28. agenta/client/backend/types/o_tel_span_kind.py +15 -0
  29. agenta/client/backend/types/o_tel_spans_response.py +24 -0
  30. agenta/client/backend/types/o_tel_status_code.py +8 -0
  31. agenta/client/backend/types/parent_dto.py +21 -0
  32. agenta/client/backend/types/root_dto.py +21 -0
  33. agenta/client/backend/types/span_dto.py +54 -0
  34. agenta/client/backend/types/span_dto_nodes_value.py +9 -0
  35. agenta/client/backend/types/status_code.py +5 -0
  36. agenta/client/backend/types/status_dto.py +23 -0
  37. agenta/client/backend/types/time_dto.py +23 -0
  38. agenta/client/backend/types/tree_dto.py +23 -0
  39. agenta/client/backend/types/tree_type.py +5 -0
  40. agenta/client/backend/variants/client.py +24 -16
  41. agenta/sdk/__init__.py +2 -0
  42. agenta/sdk/decorators/routing.py +28 -4
  43. agenta/sdk/middleware/__init__.py +0 -0
  44. agenta/sdk/middleware/auth.py +136 -0
  45. agenta/sdk/middleware/cache.py +43 -0
  46. agenta/sdk/tracing/exporters.py +1 -1
  47. agenta/sdk/tracing/inline.py +29 -140
  48. agenta/sdk/tracing/processors.py +1 -1
  49. agenta/sdk/types.py +5 -2
  50. {agenta-0.27.3.dist-info → agenta-0.27.4a1.dist-info}/METADATA +1 -1
  51. {agenta-0.27.3.dist-info → agenta-0.27.4a1.dist-info}/RECORD +53 -16
  52. {agenta-0.27.3.dist-info → agenta-0.27.4a1.dist-info}/WHEEL +0 -0
  53. {agenta-0.27.3.dist-info → agenta-0.27.4a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,21 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
5
+ import typing
6
+ import pydantic
7
+
8
+
9
+ class ParentDto(UniversalBaseModel):
10
+ id: str
11
+
12
+ if IS_PYDANTIC_V2:
13
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
14
+ extra="allow", frozen=True
15
+ ) # type: ignore # Pydantic v2
16
+ else:
17
+
18
+ class Config:
19
+ frozen = True
20
+ smart_union = True
21
+ extra = pydantic.Extra.allow
@@ -0,0 +1,21 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
5
+ import typing
6
+ import pydantic
7
+
8
+
9
+ class RootDto(UniversalBaseModel):
10
+ id: str
11
+
12
+ if IS_PYDANTIC_V2:
13
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
14
+ extra="allow", frozen=True
15
+ ) # type: ignore # Pydantic v2
16
+ else:
17
+
18
+ class Config:
19
+ frozen = True
20
+ smart_union = True
21
+ extra = pydantic.Extra.allow
@@ -0,0 +1,54 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from __future__ import annotations
4
+ from ..core.pydantic_utilities import UniversalBaseModel
5
+ import typing
6
+ from .lifecycle_dto import LifecycleDto
7
+ from .root_dto import RootDto
8
+ from .tree_dto import TreeDto
9
+ from .node_dto import NodeDto
10
+ from .parent_dto import ParentDto
11
+ from .time_dto import TimeDto
12
+ from .status_dto import StatusDto
13
+ from .exception_dto import ExceptionDto
14
+ from .link_dto import LinkDto
15
+ from .o_tel_extra_dto import OTelExtraDto
16
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
17
+ import pydantic
18
+ from ..core.pydantic_utilities import update_forward_refs
19
+
20
+
21
+ class SpanDto(UniversalBaseModel):
22
+ lifecycle: typing.Optional[LifecycleDto] = None
23
+ root: RootDto
24
+ tree: TreeDto
25
+ node: NodeDto
26
+ parent: typing.Optional[ParentDto] = None
27
+ time: TimeDto
28
+ status: StatusDto
29
+ exception: typing.Optional[ExceptionDto] = None
30
+ data: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
31
+ metrics: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
32
+ meta: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
33
+ refs: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
34
+ links: typing.Optional[typing.List[LinkDto]] = None
35
+ otel: typing.Optional[OTelExtraDto] = None
36
+ nodes: typing.Optional[
37
+ typing.Dict[str, typing.Optional["SpanDtoNodesValue"]]
38
+ ] = None
39
+
40
+ if IS_PYDANTIC_V2:
41
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
42
+ extra="allow", frozen=True
43
+ ) # type: ignore # Pydantic v2
44
+ else:
45
+
46
+ class Config:
47
+ frozen = True
48
+ smart_union = True
49
+ extra = pydantic.Extra.allow
50
+
51
+
52
+ from .span_dto_nodes_value import SpanDtoNodesValue # noqa: E402
53
+
54
+ update_forward_refs(SpanDto)
@@ -0,0 +1,9 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from __future__ import annotations
4
+ import typing
5
+ import typing
6
+
7
+ if typing.TYPE_CHECKING:
8
+ from .span_dto import SpanDto
9
+ SpanDtoNodesValue = typing.Union["SpanDto", typing.List["SpanDto"]]
@@ -0,0 +1,5 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ StatusCode = typing.Union[typing.Literal["UNSET", "OK", "ERROR"], typing.Any]
@@ -0,0 +1,23 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ from .status_code import StatusCode
5
+ import typing
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+ import pydantic
8
+
9
+
10
+ class StatusDto(UniversalBaseModel):
11
+ code: StatusCode
12
+ message: typing.Optional[str] = None
13
+
14
+ if IS_PYDANTIC_V2:
15
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
16
+ extra="allow", frozen=True
17
+ ) # type: ignore # Pydantic v2
18
+ else:
19
+
20
+ class Config:
21
+ frozen = True
22
+ smart_union = True
23
+ extra = pydantic.Extra.allow
@@ -0,0 +1,23 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import datetime as dt
5
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
6
+ import typing
7
+ import pydantic
8
+
9
+
10
+ class TimeDto(UniversalBaseModel):
11
+ start: dt.datetime
12
+ end: dt.datetime
13
+
14
+ if IS_PYDANTIC_V2:
15
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
16
+ extra="allow", frozen=True
17
+ ) # type: ignore # Pydantic v2
18
+ else:
19
+
20
+ class Config:
21
+ frozen = True
22
+ smart_union = True
23
+ extra = pydantic.Extra.allow
@@ -0,0 +1,23 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from .tree_type import TreeType
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+ import pydantic
8
+
9
+
10
+ class TreeDto(UniversalBaseModel):
11
+ id: str
12
+ type: typing.Optional[TreeType] = None
13
+
14
+ if IS_PYDANTIC_V2:
15
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
16
+ extra="allow", frozen=True
17
+ ) # type: ignore # Pydantic v2
18
+ else:
19
+
20
+ class Config:
21
+ frozen = True
22
+ smart_union = True
23
+ extra = pydantic.Extra.allow
@@ -0,0 +1,5 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ TreeType = typing.Literal["invocation"]
@@ -1104,14 +1104,14 @@ class VariantsClient:
1104
1104
  def configs_delete(
1105
1105
  self,
1106
1106
  *,
1107
- variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1107
+ variant_ref: ReferenceRequestModel,
1108
1108
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1109
1109
  request_options: typing.Optional[RequestOptions] = None,
1110
1110
  ) -> int:
1111
1111
  """
1112
1112
  Parameters
1113
1113
  ----------
1114
- variant_ref : typing.Optional[ReferenceRequestModel]
1114
+ variant_ref : ReferenceRequestModel
1115
1115
 
1116
1116
  application_ref : typing.Optional[ReferenceRequestModel]
1117
1117
 
@@ -1125,13 +1125,15 @@ class VariantsClient:
1125
1125
 
1126
1126
  Examples
1127
1127
  --------
1128
- from agenta import AgentaApi
1128
+ from agenta import AgentaApi, ReferenceRequestModel
1129
1129
 
1130
1130
  client = AgentaApi(
1131
1131
  api_key="YOUR_API_KEY",
1132
1132
  base_url="https://yourhost.com/path/to/api",
1133
1133
  )
1134
- client.variants.configs_delete()
1134
+ client.variants.configs_delete(
1135
+ variant_ref=ReferenceRequestModel(),
1136
+ )
1135
1137
  """
1136
1138
  _response = self._client_wrapper.httpx_client.request(
1137
1139
  "variants/configs/delete",
@@ -1244,14 +1246,14 @@ class VariantsClient:
1244
1246
  def configs_history(
1245
1247
  self,
1246
1248
  *,
1247
- variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1249
+ variant_ref: ReferenceRequestModel,
1248
1250
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
1249
1251
  request_options: typing.Optional[RequestOptions] = None,
1250
1252
  ) -> typing.List[ConfigResponseModel]:
1251
1253
  """
1252
1254
  Parameters
1253
1255
  ----------
1254
- variant_ref : typing.Optional[ReferenceRequestModel]
1256
+ variant_ref : ReferenceRequestModel
1255
1257
 
1256
1258
  application_ref : typing.Optional[ReferenceRequestModel]
1257
1259
 
@@ -1265,13 +1267,15 @@ class VariantsClient:
1265
1267
 
1266
1268
  Examples
1267
1269
  --------
1268
- from agenta import AgentaApi
1270
+ from agenta import AgentaApi, ReferenceRequestModel
1269
1271
 
1270
1272
  client = AgentaApi(
1271
1273
  api_key="YOUR_API_KEY",
1272
1274
  base_url="https://yourhost.com/path/to/api",
1273
1275
  )
1274
- client.variants.configs_history()
1276
+ client.variants.configs_history(
1277
+ variant_ref=ReferenceRequestModel(),
1278
+ )
1275
1279
  """
1276
1280
  _response = self._client_wrapper.httpx_client.request(
1277
1281
  "variants/configs/history",
@@ -2504,14 +2508,14 @@ class AsyncVariantsClient:
2504
2508
  async def configs_delete(
2505
2509
  self,
2506
2510
  *,
2507
- variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2511
+ variant_ref: ReferenceRequestModel,
2508
2512
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2509
2513
  request_options: typing.Optional[RequestOptions] = None,
2510
2514
  ) -> int:
2511
2515
  """
2512
2516
  Parameters
2513
2517
  ----------
2514
- variant_ref : typing.Optional[ReferenceRequestModel]
2518
+ variant_ref : ReferenceRequestModel
2515
2519
 
2516
2520
  application_ref : typing.Optional[ReferenceRequestModel]
2517
2521
 
@@ -2527,7 +2531,7 @@ class AsyncVariantsClient:
2527
2531
  --------
2528
2532
  import asyncio
2529
2533
 
2530
- from agenta import AsyncAgentaApi
2534
+ from agenta import AsyncAgentaApi, ReferenceRequestModel
2531
2535
 
2532
2536
  client = AsyncAgentaApi(
2533
2537
  api_key="YOUR_API_KEY",
@@ -2536,7 +2540,9 @@ class AsyncVariantsClient:
2536
2540
 
2537
2541
 
2538
2542
  async def main() -> None:
2539
- await client.variants.configs_delete()
2543
+ await client.variants.configs_delete(
2544
+ variant_ref=ReferenceRequestModel(),
2545
+ )
2540
2546
 
2541
2547
 
2542
2548
  asyncio.run(main())
@@ -2660,14 +2666,14 @@ class AsyncVariantsClient:
2660
2666
  async def configs_history(
2661
2667
  self,
2662
2668
  *,
2663
- variant_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2669
+ variant_ref: ReferenceRequestModel,
2664
2670
  application_ref: typing.Optional[ReferenceRequestModel] = OMIT,
2665
2671
  request_options: typing.Optional[RequestOptions] = None,
2666
2672
  ) -> typing.List[ConfigResponseModel]:
2667
2673
  """
2668
2674
  Parameters
2669
2675
  ----------
2670
- variant_ref : typing.Optional[ReferenceRequestModel]
2676
+ variant_ref : ReferenceRequestModel
2671
2677
 
2672
2678
  application_ref : typing.Optional[ReferenceRequestModel]
2673
2679
 
@@ -2683,7 +2689,7 @@ class AsyncVariantsClient:
2683
2689
  --------
2684
2690
  import asyncio
2685
2691
 
2686
- from agenta import AsyncAgentaApi
2692
+ from agenta import AsyncAgentaApi, ReferenceRequestModel
2687
2693
 
2688
2694
  client = AsyncAgentaApi(
2689
2695
  api_key="YOUR_API_KEY",
@@ -2692,7 +2698,9 @@ class AsyncVariantsClient:
2692
2698
 
2693
2699
 
2694
2700
  async def main() -> None:
2695
- await client.variants.configs_history()
2701
+ await client.variants.configs_history(
2702
+ variant_ref=ReferenceRequestModel(),
2703
+ )
2696
2704
 
2697
2705
 
2698
2706
  asyncio.run(main())
agenta/sdk/__init__.py CHANGED
@@ -17,6 +17,8 @@ from .types import (
17
17
  FileInputURL,
18
18
  BinaryParam,
19
19
  Prompt,
20
+ AgentaNodeDto,
21
+ AgentaNodesResponse,
20
22
  )
21
23
 
22
24
  from .tracing import Tracing, get_tracer
@@ -14,9 +14,10 @@ from os import environ
14
14
  from fastapi.middleware.cors import CORSMiddleware
15
15
  from fastapi import Body, FastAPI, UploadFile, HTTPException
16
16
 
17
+ from agenta.sdk.middleware.auth import AuthorizationMiddleware
17
18
  from agenta.sdk.context.routing import routing_context_manager, routing_context
18
19
  from agenta.sdk.context.tracing import tracing_context
19
- from agenta.sdk.router import router as router
20
+ from agenta.sdk.router import router
20
21
  from agenta.sdk.utils.exceptions import suppress
21
22
  from agenta.sdk.utils.logging import log
22
23
  from agenta.sdk.types import (
@@ -50,6 +51,9 @@ app.add_middleware(
50
51
  allow_headers=["*"],
51
52
  )
52
53
 
54
+ _MIDDLEWARES = True
55
+
56
+
53
57
  app.include_router(router, prefix="")
54
58
 
55
59
 
@@ -121,6 +125,26 @@ class entrypoint:
121
125
  route_path="",
122
126
  config_schema: Optional[BaseModel] = None,
123
127
  ):
128
+ ### --- Update Middleware --- #
129
+ try:
130
+ global _MIDDLEWARES # pylint: disable=global-statement
131
+
132
+ if _MIDDLEWARES:
133
+ app.add_middleware(
134
+ AuthorizationMiddleware,
135
+ host=ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.host,
136
+ resource_id=ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.app_id,
137
+ resource_type="application",
138
+ )
139
+
140
+ _MIDDLEWARES = False
141
+
142
+ except: # pylint: disable=bare-except
143
+ log.error("------------------------------------")
144
+ log.error("Agenta SDK - failed to secure route: %s", route_path)
145
+ log.error("------------------------------------")
146
+ ### --- Update Middleware --- #
147
+
124
148
  DEFAULT_PATH = "generate"
125
149
  PLAYGROUND_PATH = "/playground"
126
150
  RUN_PATH = "/run"
@@ -330,9 +354,9 @@ class entrypoint:
330
354
  *args,
331
355
  **func_params,
332
356
  ):
333
- log.info(f"---------------------------")
357
+ log.info("---------------------------")
334
358
  log.info(f"Agenta SDK - running route: {repr(self.route_path or '/')}")
335
- log.info(f"---------------------------")
359
+ log.info("---------------------------")
336
360
 
337
361
  tracing_context.set(routing_context.get())
338
362
 
@@ -362,7 +386,7 @@ class entrypoint:
362
386
  log.info(f"Agenta SDK - exiting with success: 200")
363
387
  log.info(f"----------------------------------")
364
388
 
365
- return BaseResponse(data=data, trace=trace)
389
+ return BaseResponse(data=data, tree=trace)
366
390
 
367
391
  def handle_failure(self, error: Exception):
368
392
  log.error("--------------------------------------------------")
File without changes
@@ -0,0 +1,136 @@
1
+ from typing import Callable, Optional
2
+ from os import environ
3
+ from uuid import UUID
4
+ from json import dumps
5
+ from traceback import format_exc
6
+
7
+ import httpx
8
+ from starlette.middleware.base import BaseHTTPMiddleware
9
+ from fastapi import FastAPI, Request, Response
10
+
11
+ from agenta.sdk.utils.logging import log
12
+ from agenta.sdk.middleware.cache import TTLLRUCache
13
+
14
+ AGENTA_SDK_AUTH_CACHE_CAPACITY = environ.get(
15
+ "AGENTA_SDK_AUTH_CACHE_CAPACITY",
16
+ 512,
17
+ )
18
+
19
+ AGENTA_SDK_AUTH_CACHE_TTL = environ.get(
20
+ "AGENTA_SDK_AUTH_CACHE_TTL",
21
+ 15 * 60, # 15 minutes
22
+ )
23
+
24
+ AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED = str(
25
+ environ.get("AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED", False)
26
+ ).lower() in ("true", "1", "t")
27
+
28
+
29
+ class Deny(Response):
30
+ def __init__(self) -> None:
31
+ super().__init__(status_code=401, content="Unauthorized")
32
+
33
+
34
+ cache = TTLLRUCache(
35
+ capacity=AGENTA_SDK_AUTH_CACHE_CAPACITY,
36
+ ttl=AGENTA_SDK_AUTH_CACHE_TTL,
37
+ )
38
+
39
+
40
+ class AuthorizationMiddleware(BaseHTTPMiddleware):
41
+ def __init__(
42
+ self,
43
+ app: FastAPI,
44
+ host: str,
45
+ resource_id: UUID,
46
+ resource_type: str,
47
+ ):
48
+ super().__init__(app)
49
+
50
+ self.host = host
51
+ self.resource_id = resource_id
52
+ self.resource_type = resource_type
53
+
54
+ async def dispatch(
55
+ self,
56
+ request: Request,
57
+ call_next: Callable,
58
+ project_id: Optional[UUID] = None,
59
+ ):
60
+ if AGENTA_UNAUTHORIZED_EXECUTION_ALLOWED:
61
+ return await call_next(request)
62
+
63
+ try:
64
+ authorization = (
65
+ request.headers.get("Authorization")
66
+ or request.headers.get("authorization")
67
+ or None
68
+ )
69
+
70
+ headers = {"Authorization": authorization} if authorization else None
71
+
72
+ cookies = {"sAccessToken": request.cookies.get("sAccessToken")}
73
+
74
+ params = {
75
+ "action": "run_service",
76
+ "resource_type": self.resource_type,
77
+ "resource_id": self.resource_id,
78
+ }
79
+
80
+ if project_id:
81
+ params["project_id"] = project_id
82
+
83
+ _hash = dumps(
84
+ {
85
+ "headers": headers,
86
+ "cookies": cookies,
87
+ "params": params,
88
+ },
89
+ sort_keys=True,
90
+ )
91
+
92
+ cached_policy = cache.get(_hash)
93
+
94
+ if not cached_policy:
95
+ async with httpx.AsyncClient() as client:
96
+ response = await client.get(
97
+ f"{self.host}/api/permissions/verify",
98
+ headers=headers,
99
+ cookies=cookies,
100
+ params=params,
101
+ )
102
+
103
+ if response.status_code != 200:
104
+ cache.put(_hash, {"effect": "deny"})
105
+ return Deny()
106
+
107
+ auth = response.json()
108
+
109
+ if auth.get("effect") != "allow":
110
+ cache.put(_hash, {"effect": "deny"})
111
+ return Deny()
112
+
113
+ cached_policy = {
114
+ "effect": "allow",
115
+ "credentials": auth.get("credentials"),
116
+ }
117
+
118
+ cache.put(_hash, cached_policy)
119
+
120
+ if cached_policy.get("effect") == "deny":
121
+ return Deny()
122
+
123
+ request.state.credentials = cached_policy.get("credentials")
124
+
125
+ print(f"credentials: {request.state.credentials}")
126
+
127
+ return await call_next(request)
128
+
129
+ except: # pylint: disable=bare-except
130
+ log.error("------------------------------------------------------")
131
+ log.error("Agenta SDK - handling auth middleware exception below:")
132
+ log.error("------------------------------------------------------")
133
+ log.error(format_exc().strip("\n"))
134
+ log.error("------------------------------------------------------")
135
+
136
+ return Deny()
@@ -0,0 +1,43 @@
1
+ from time import time
2
+ from collections import OrderedDict
3
+
4
+
5
+ class TTLLRUCache:
6
+ def __init__(self, capacity: int, ttl: int):
7
+ self.cache = OrderedDict()
8
+ self.capacity = capacity
9
+ self.ttl = ttl
10
+
11
+ def get(self, key):
12
+ # CACHE
13
+ if key not in self.cache:
14
+ return None
15
+
16
+ value, expiry = self.cache[key]
17
+ # -----
18
+
19
+ # TTL
20
+ if time() > expiry:
21
+ del self.cache[key]
22
+
23
+ return None
24
+ # ---
25
+
26
+ # LRU
27
+ self.cache.move_to_end(key)
28
+ # ---
29
+
30
+ return value
31
+
32
+ def put(self, key, value):
33
+ # CACHE
34
+ if key in self.cache:
35
+ del self.cache[key]
36
+ # CACHE & LRU
37
+ elif len(self.cache) >= self.capacity:
38
+ self.cache.popitem(last=False)
39
+ # -----------
40
+
41
+ # TTL
42
+ self.cache[key] = (value, time() + self.ttl)
43
+ # ---
@@ -58,7 +58,7 @@ class InlineTraceExporter(SpanExporter):
58
58
  return trace
59
59
 
60
60
 
61
- OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2
61
+ OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2 # pylint: disable=protected-access
62
62
 
63
63
  ConsoleExporter = ConsoleSpanExporter
64
64
  InlineExporter = InlineTraceExporter