Repository: maihemlabs/maihem (language: python)

Issue:
WIP added support for documents



Discussion / hints:

Fix patch:
diff --git a/design_maihem_agent.py b/design_maihem_agent.py
new file mode 100644
index 0000000..bd2ae83
--- /dev/null
+++ b/design_maihem_agent.py
@@ -0,0 +1,33 @@
+from maihem.agents import MaihemAgent
+
+
+maihem_agent = MaihemAgent(
+    identifier="test-agent",
+    workflow_prompt="", # Guide the behavior of the Maihem Agent with a prompt describing the workflow of the user
+    workflow_dict="", # Optional, provide a dictionary of the workflow to guide the behavior of the Maihem Agent, use our tool to help you generate this
+    metric_to_test="helpfulness",
+    static_responses=True, # Optional, return the same static responses every time
+    turns_static=5, # Optional, to set the first number of turns to be static (repeat the same messages)
+    turns_max=10, # Optional, to set maximum number of turns
+    add_personality=True, # Optional, add personality to the agent
+    target_agent_identifier="target_agent_unique_identifier",
+    target_agent_role="mental health assistant",
+    target_agent_description="A chatbot for emotional support",
+)
+
+# For RAG evaluations
+# Load documents that the agent can use to generate responses
+maihem_agent.add_documents(paths=["./data/journaling.txt", "./data/habit-building.txt", "./data/emotional-support.txt"])
+
+maihem_agent_message = maihem_agent.chat(
+    target_agent_message="Hi, how can I help you today?", # Message from the Target Agent
+    contexts=["<Context 1>", "<Context 2>"], # Optional, to provide context for the agent for RAG
+)
+
+# Get message content and evals
+maihem_agent_message.content
+maihem_agent_message.eval
+
+# Get conversation and evals
+maihem_agent.conversation
+maihem_agent.evals
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index e585207..882c7cf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,7 +17,7 @@ classifiers = [
     "Programming Language :: Python :: 3",
 ]
 keywords = ["genAI", "LLM", "evaluation", "data", "generation", "synthetic"]
-dependencies = ["requests", "pandas", "pydantic", "pycountry", "pydantic_extra_types", "httpx", "attrs", "loguru", "tqdm", "anyio"]
+dependencies = ["requests", "pandas", "pydantic", "pycountry", "pydantic_extra_types", "httpx", "attrs", "loguru", "tqdm", "anyio", "pymupdf", "docx2txt"]
 requires-python = ">=3.9"
 
 [project.urls]
diff --git a/src/maihem.egg-info/dependency_links.txt b/src/maihem.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/src/maihem.egg-info/dependency_links.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-
diff --git a/src/maihem.egg-info/requires.txt b/src/maihem.egg-info/requires.txt
deleted file mode 100644
index 1bb1327..0000000
--- a/src/maihem.egg-info/requires.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-requests
-pandas
-pydantic
-pycountry
-pydantic_extra_types
-httpx
-attrs
-loguru
-tqdm
-anyio
diff --git a/src/maihem/api.py b/src/maihem/api.py
index 8afaff7..512ea97 100644
--- a/src/maihem/api.py
+++ b/src/maihem/api.py
@@ -5,8 +5,8 @@
 from maihem.api_client.maihem_client.models.api_schema_agent_target_create_request import (
     APISchemaAgentTargetCreateRequest,
 )
-from maihem.api_client.maihem_client.models.api_schema_agent_target_create_response import (
-    APISchemaAgentTargetCreateResponse,
+from maihem.api_client.maihem_client.models.api_schema_agent_target import (
+    APISchemaAgentTarget,
 )
 from maihem.api_client.maihem_client.models.api_schema_test_create_request import (
     APISchemaTestCreateRequest,
@@ -29,9 +29,6 @@
 from maihem.api_client.maihem_client.models.api_schema_test_run_conversations import (
     APISchemaTestRunConversations,
 )
-from maihem.api_client.maihem_client.models.api_schema_agent_target_get_response import (
-    APISchemaAgentTargetGetResponse,
-)
 from maihem.api_client.maihem_client.api.tests import tests_create_test
 from maihem.api_client.maihem_client.api.tests import (
     tests_create_test_run,
@@ -43,6 +40,9 @@
 from maihem.api_client.maihem_client.models.api_schema_conversation_turn_create_request import (
     APISchemaConversationTurnCreateRequest,
 )
+from maihem.api_client.maihem_client.models.api_schema_conversation_turn_create_request_document_type_0 import (
+    APISchemaConversationTurnCreateRequestDocumentType0,
+)
 from maihem.api_client.maihem_client.models.api_schema_conversation_turn_create_response import (
     APISchemaConversationTurnCreateResponse,
 )
@@ -84,9 +84,9 @@ def whoami(self) -> Dict[str, str]:
 
     def create_agent_target(
         self, req: APISchemaAgentTargetCreateRequest
-    ) -> APISchemaAgentTargetCreateResponse:
+    ) -> APISchemaAgentTarget:
         with MaihemHTTPClient(base_url=self.base_url) as client:
-            response: Response[APISchemaAgentTargetCreateResponse] = (
+            response: Response[APISchemaAgentTarget] = (
                 agents_create_agent_target.sync_detailed(
                     client=client,
                     x_api_key=self.token,
@@ -101,10 +101,10 @@ def create_agent_target(
 
     def get_agent_target_by_identifier(
         self, identifier: str
-    ) -> APISchemaAgentTargetGetResponse:
+    ) -> APISchemaAgentTarget:
 
         with MaihemHTTPClient(base_url=self.base_url) as client:
-            response: Response[List[APISchemaAgentTargetGetResponse]] = (
+            response: Response[List[APISchemaAgentTarget]] = (
                 agents_get_agent_targets.sync_detailed(
                     client=client,
                     x_api_key=self.token,
@@ -166,11 +166,23 @@ def create_conversation_turn(
         conversation_id: str,
         target_agent_message: Optional[str] = None,
         contexts: Optional[List[str]] = None,
+        document: Optional[Dict[str, str]] = None,
     ) -> APISchemaConversationTurnCreateResponse:
         with MaihemHTTPClient(base_url=self.base_url) as client:
+            document_req = None
+
+            if document:
+                document_req = (
+                    APISchemaConversationTurnCreateRequestDocumentType0.from_dict(
+                        document
+                    )
+                )
+
             req: APISchemaConversationTurnCreateRequest = (
                 APISchemaConversationTurnCreateRequest(
-                    message=target_agent_message, contexts=contexts
+                    message=target_agent_message,
+                    contexts=contexts,
+                    document=document_req if document_req else None,
                 )
             )
 
diff --git a/src/maihem/api_client/maihem_client/api/agents/agents_create_agent_target.py b/src/maihem/api_client/maihem_client/api/agents/agents_create_agent_target.py
index f39f58c..5edad60 100644
--- a/src/maihem/api_client/maihem_client/api/agents/agents_create_agent_target.py
+++ b/src/maihem/api_client/maihem_client/api/agents/agents_create_agent_target.py
@@ -5,8 +5,8 @@
 
 from ... import errors
 from ...client import AuthenticatedClient, Client
+from ...models.api_schema_agent_target import APISchemaAgentTarget
 from ...models.api_schema_agent_target_create_request import APISchemaAgentTargetCreateRequest
-from ...models.api_schema_agent_target_create_response import APISchemaAgentTargetCreateResponse
 from ...models.error_response import ErrorResponse
 from ...types import UNSET, Response, Unset
 
@@ -36,9 +36,9 @@ def _get_kwargs(
 
 def _parse_response(
     *, client: Union[AuthenticatedClient, Client], response: httpx.Response
-) -> Optional[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]:
+) -> Optional[Union[APISchemaAgentTarget, ErrorResponse]]:
     if response.status_code == HTTPStatus.CREATED:
-        response_201 = APISchemaAgentTargetCreateResponse.from_dict(response.json())
+        response_201 = APISchemaAgentTarget.from_dict(response.json())
 
         return response_201
     if response.status_code == HTTPStatus.BAD_REQUEST:
@@ -57,6 +57,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
@@ -65,7 +69,7 @@ def _parse_response(
 
 def _build_response(
     *, client: Union[AuthenticatedClient, Client], response: httpx.Response
-) -> Response[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]:
+) -> Response[Union[APISchemaAgentTarget, ErrorResponse]]:
     return Response(
         status_code=HTTPStatus(response.status_code),
         content=response.content,
@@ -79,7 +83,7 @@ def sync_detailed(
     client: AuthenticatedClient,
     body: APISchemaAgentTargetCreateRequest,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Response[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]:
+) -> Response[Union[APISchemaAgentTarget, ErrorResponse]]:
     """Connect target agent
 
      Add a new target agent for Maihem to test
@@ -93,7 +97,7 @@ def sync_detailed(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Response[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]
+        Response[Union[APISchemaAgentTarget, ErrorResponse]]
     """
 
     kwargs = _get_kwargs(
@@ -113,7 +117,7 @@ def sync(
     client: AuthenticatedClient,
     body: APISchemaAgentTargetCreateRequest,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Optional[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]:
+) -> Optional[Union[APISchemaAgentTarget, ErrorResponse]]:
     """Connect target agent
 
      Add a new target agent for Maihem to test
@@ -127,7 +131,7 @@ def sync(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Union[APISchemaAgentTargetCreateResponse, ErrorResponse]
+        Union[APISchemaAgentTarget, ErrorResponse]
     """
 
     return sync_detailed(
@@ -142,7 +146,7 @@ async def asyncio_detailed(
     client: AuthenticatedClient,
     body: APISchemaAgentTargetCreateRequest,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Response[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]:
+) -> Response[Union[APISchemaAgentTarget, ErrorResponse]]:
     """Connect target agent
 
      Add a new target agent for Maihem to test
@@ -156,7 +160,7 @@ async def asyncio_detailed(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Response[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]
+        Response[Union[APISchemaAgentTarget, ErrorResponse]]
     """
 
     kwargs = _get_kwargs(
@@ -174,7 +178,7 @@ async def asyncio(
     client: AuthenticatedClient,
     body: APISchemaAgentTargetCreateRequest,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Optional[Union[APISchemaAgentTargetCreateResponse, ErrorResponse]]:
+) -> Optional[Union[APISchemaAgentTarget, ErrorResponse]]:
     """Connect target agent
 
      Add a new target agent for Maihem to test
@@ -188,7 +192,7 @@ async def asyncio(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Union[APISchemaAgentTargetCreateResponse, ErrorResponse]
+        Union[APISchemaAgentTarget, ErrorResponse]
     """
 
     return (
diff --git a/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_target.py b/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_target.py
new file mode 100644
index 0000000..5168931
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_target.py
@@ -0,0 +1,198 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.api_schema_agent_target import APISchemaAgentTarget
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Response, Unset
+
+
+def _get_kwargs(
+    agent_target_id: str,
+    *,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+    if not isinstance(x_api_key, Unset):
+        headers["x-api-key"] = x_api_key
+
+    _kwargs: Dict[str, Any] = {
+        "method": "get",
+        "url": f"/agents/target/{agent_target_id}",
+    }
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[APISchemaAgentTarget, ErrorResponse]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = APISchemaAgentTarget.from_dict(response.json())
+
+        return response_200
+    if response.status_code == HTTPStatus.BAD_REQUEST:
+        response_400 = ErrorResponse.from_dict(response.json())
+
+        return response_400
+    if response.status_code == HTTPStatus.CONFLICT:
+        response_409 = ErrorResponse.from_dict(response.json())
+
+        return response_409
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = ErrorResponse.from_dict(response.json())
+
+        return response_422
+    if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
+        response_500 = ErrorResponse.from_dict(response.json())
+
+        return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[APISchemaAgentTarget, ErrorResponse]]:
+    return Response(
+        status_code=HTTPStatus(response.status_code),
+        content=response.content,
+        headers=response.headers,
+        parsed=_parse_response(client=client, response=response),
+    )
+
+
+def sync_detailed(
+    agent_target_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaAgentTarget, ErrorResponse]]:
+    """Get a target agent
+
+     Gets a specified target agent
+
+    Args:
+        agent_target_id (str):
+        x_api_key (Union[None, Unset, 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[Union[APISchemaAgentTarget, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        agent_target_id=agent_target_id,
+        x_api_key=x_api_key,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    agent_target_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaAgentTarget, ErrorResponse]]:
+    """Get a target agent
+
+     Gets a specified target agent
+
+    Args:
+        agent_target_id (str):
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaAgentTarget, ErrorResponse]
+    """
+
+    return sync_detailed(
+        agent_target_id=agent_target_id,
+        client=client,
+        x_api_key=x_api_key,
+    ).parsed
+
+
+async def asyncio_detailed(
+    agent_target_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaAgentTarget, ErrorResponse]]:
+    """Get a target agent
+
+     Gets a specified target agent
+
+    Args:
+        agent_target_id (str):
+        x_api_key (Union[None, Unset, 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[Union[APISchemaAgentTarget, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        agent_target_id=agent_target_id,
+        x_api_key=x_api_key,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    agent_target_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaAgentTarget, ErrorResponse]]:
+    """Get a target agent
+
+     Gets a specified target agent
+
+    Args:
+        agent_target_id (str):
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaAgentTarget, ErrorResponse]
+    """
+
+    return (
+        await asyncio_detailed(
+            agent_target_id=agent_target_id,
+            client=client,
+            x_api_key=x_api_key,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_targets.py b/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_targets.py
index 4902e98..7cdcdb2 100644
--- a/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_targets.py
+++ b/src/maihem/api_client/maihem_client/api/agents/agents_get_agent_targets.py
@@ -5,7 +5,7 @@
 
 from ... import errors
 from ...client import AuthenticatedClient, Client
-from ...models.api_schema_agent_target_get_response import APISchemaAgentTargetGetResponse
+from ...models.api_schema_agent_target import APISchemaAgentTarget
 from ...models.error_response import ErrorResponse
 from ...types import UNSET, Response, Unset
 
@@ -37,12 +37,12 @@ def _get_kwargs(
 
 def _parse_response(
     *, client: Union[AuthenticatedClient, Client], response: httpx.Response
-) -> Optional[Union[ErrorResponse, List["APISchemaAgentTargetGetResponse"]]]:
+) -> Optional[Union[ErrorResponse, List["APISchemaAgentTarget"]]]:
     if response.status_code == HTTPStatus.OK:
         response_200 = []
         _response_200 = response.json()
         for response_200_item_data in _response_200:
-            response_200_item = APISchemaAgentTargetGetResponse.from_dict(response_200_item_data)
+            response_200_item = APISchemaAgentTarget.from_dict(response_200_item_data)
 
             response_200.append(response_200_item)
 
@@ -63,6 +63,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
@@ -71,7 +75,7 @@ def _parse_response(
 
 def _build_response(
     *, client: Union[AuthenticatedClient, Client], response: httpx.Response
-) -> Response[Union[ErrorResponse, List["APISchemaAgentTargetGetResponse"]]]:
+) -> Response[Union[ErrorResponse, List["APISchemaAgentTarget"]]]:
     return Response(
         status_code=HTTPStatus(response.status_code),
         content=response.content,
@@ -85,7 +89,7 @@ def sync_detailed(
     client: AuthenticatedClient,
     identifier: Union[Unset, str] = UNSET,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Response[Union[ErrorResponse, List["APISchemaAgentTargetGetResponse"]]]:
+) -> Response[Union[ErrorResponse, List["APISchemaAgentTarget"]]]:
     """Get all target agents
 
      Gets a list of all configured target agents
@@ -99,7 +103,7 @@ def sync_detailed(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Response[Union[ErrorResponse, List['APISchemaAgentTargetGetResponse']]]
+        Response[Union[ErrorResponse, List['APISchemaAgentTarget']]]
     """
 
     kwargs = _get_kwargs(
@@ -119,7 +123,7 @@ def sync(
     client: AuthenticatedClient,
     identifier: Union[Unset, str] = UNSET,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Optional[Union[ErrorResponse, List["APISchemaAgentTargetGetResponse"]]]:
+) -> Optional[Union[ErrorResponse, List["APISchemaAgentTarget"]]]:
     """Get all target agents
 
      Gets a list of all configured target agents
@@ -133,7 +137,7 @@ def sync(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Union[ErrorResponse, List['APISchemaAgentTargetGetResponse']]
+        Union[ErrorResponse, List['APISchemaAgentTarget']]
     """
 
     return sync_detailed(
@@ -148,7 +152,7 @@ async def asyncio_detailed(
     client: AuthenticatedClient,
     identifier: Union[Unset, str] = UNSET,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Response[Union[ErrorResponse, List["APISchemaAgentTargetGetResponse"]]]:
+) -> Response[Union[ErrorResponse, List["APISchemaAgentTarget"]]]:
     """Get all target agents
 
      Gets a list of all configured target agents
@@ -162,7 +166,7 @@ async def asyncio_detailed(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Response[Union[ErrorResponse, List['APISchemaAgentTargetGetResponse']]]
+        Response[Union[ErrorResponse, List['APISchemaAgentTarget']]]
     """
 
     kwargs = _get_kwargs(
@@ -180,7 +184,7 @@ async def asyncio(
     client: AuthenticatedClient,
     identifier: Union[Unset, str] = UNSET,
     x_api_key: Union[None, Unset, str] = UNSET,
-) -> Optional[Union[ErrorResponse, List["APISchemaAgentTargetGetResponse"]]]:
+) -> Optional[Union[ErrorResponse, List["APISchemaAgentTarget"]]]:
     """Get all target agents
 
      Gets a list of all configured target agents
@@ -194,7 +198,7 @@ async def asyncio(
         httpx.TimeoutException: If the request takes longer than Client.timeout.
 
     Returns:
-        Union[ErrorResponse, List['APISchemaAgentTargetGetResponse']]
+        Union[ErrorResponse, List['APISchemaAgentTarget']]
     """
 
     return (
diff --git a/src/maihem/api_client/maihem_client/api/conversations/conversations_get_conversation.py b/src/maihem/api_client/maihem_client/api/conversations/conversations_get_conversation.py
index 0e7304f..e09ba7f 100644
--- a/src/maihem/api_client/maihem_client/api/conversations/conversations_get_conversation.py
+++ b/src/maihem/api_client/maihem_client/api/conversations/conversations_get_conversation.py
@@ -51,6 +51,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/metrics/__init__.py b/src/maihem/api_client/maihem_client/api/metrics/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/maihem/api_client/maihem_client/api/metrics/metrics_get_metrics.py b/src/maihem/api_client/maihem_client/api/metrics/metrics_get_metrics.py
new file mode 100644
index 0000000..b4744e0
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/metrics/metrics_get_metrics.py
@@ -0,0 +1,190 @@
+from http import HTTPStatus
+from typing import Any, Dict, List, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.api_schema_metric import APISchemaMetric
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Response, Unset
+
+
+def _get_kwargs(
+    *,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+    if not isinstance(x_api_key, Unset):
+        headers["x-api-key"] = x_api_key
+
+    _kwargs: Dict[str, Any] = {
+        "method": "get",
+        "url": "/metrics",
+    }
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[ErrorResponse, List["APISchemaMetric"]]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = []
+        _response_200 = response.json()
+        for response_200_item_data in _response_200:
+            response_200_item = APISchemaMetric.from_dict(response_200_item_data)
+
+            response_200.append(response_200_item)
+
+        return response_200
+    if response.status_code == HTTPStatus.BAD_REQUEST:
+        response_400 = ErrorResponse.from_dict(response.json())
+
+        return response_400
+    if response.status_code == HTTPStatus.CONFLICT:
+        response_409 = ErrorResponse.from_dict(response.json())
+
+        return response_409
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = ErrorResponse.from_dict(response.json())
+
+        return response_422
+    if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
+        response_500 = ErrorResponse.from_dict(response.json())
+
+        return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[ErrorResponse, List["APISchemaMetric"]]]:
+    return Response(
+        status_code=HTTPStatus(response.status_code),
+        content=response.content,
+        headers=response.headers,
+        parsed=_parse_response(client=client, response=response),
+    )
+
+
+def sync_detailed(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[ErrorResponse, List["APISchemaMetric"]]]:
+    """Get metrics
+
+     Get all supported metrics
+
+    Args:
+        x_api_key (Union[None, Unset, 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[Union[ErrorResponse, List['APISchemaMetric']]]
+    """
+
+    kwargs = _get_kwargs(
+        x_api_key=x_api_key,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[ErrorResponse, List["APISchemaMetric"]]]:
+    """Get metrics
+
+     Get all supported metrics
+
+    Args:
+        x_api_key (Union[None, Unset, 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:
+        Union[ErrorResponse, List['APISchemaMetric']]
+    """
+
+    return sync_detailed(
+        client=client,
+        x_api_key=x_api_key,
+    ).parsed
+
+
+async def asyncio_detailed(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[ErrorResponse, List["APISchemaMetric"]]]:
+    """Get metrics
+
+     Get all supported metrics
+
+    Args:
+        x_api_key (Union[None, Unset, 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[Union[ErrorResponse, List['APISchemaMetric']]]
+    """
+
+    kwargs = _get_kwargs(
+        x_api_key=x_api_key,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[ErrorResponse, List["APISchemaMetric"]]]:
+    """Get metrics
+
+     Get all supported metrics
+
+    Args:
+        x_api_key (Union[None, Unset, 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:
+        Union[ErrorResponse, List['APISchemaMetric']]
+    """
+
+    return (
+        await asyncio_detailed(
+            client=client,
+            x_api_key=x_api_key,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/orgs/orgs_create_org.py b/src/maihem/api_client/maihem_client/api/orgs/orgs_create_org.py
index 3ed5773..7187a8e 100644
--- a/src/maihem/api_client/maihem_client/api/orgs/orgs_create_org.py
+++ b/src/maihem/api_client/maihem_client/api/orgs/orgs_create_org.py
@@ -54,6 +54,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/users/__init__.py b/src/maihem/api_client/maihem_client/api/users/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/maihem/api_client/maihem_client/api/users/users_get_user_profile.py b/src/maihem/api_client/maihem_client/api/users/users_get_user_profile.py
new file mode 100644
index 0000000..f19007b
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/users/users_get_user_profile.py
@@ -0,0 +1,185 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.api_schema_user_profile import APISchemaUserProfile
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Response, Unset
+
+
+def _get_kwargs(
+    *,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+    if not isinstance(x_api_key, Unset):
+        headers["x-api-key"] = x_api_key
+
+    _kwargs: Dict[str, Any] = {
+        "method": "get",
+        "url": "/users/profile",
+    }
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[APISchemaUserProfile, ErrorResponse]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = APISchemaUserProfile.from_dict(response.json())
+
+        return response_200
+    if response.status_code == HTTPStatus.BAD_REQUEST:
+        response_400 = ErrorResponse.from_dict(response.json())
+
+        return response_400
+    if response.status_code == HTTPStatus.CONFLICT:
+        response_409 = ErrorResponse.from_dict(response.json())
+
+        return response_409
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = ErrorResponse.from_dict(response.json())
+
+        return response_422
+    if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
+        response_500 = ErrorResponse.from_dict(response.json())
+
+        return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[APISchemaUserProfile, ErrorResponse]]:
+    return Response(
+        status_code=HTTPStatus(response.status_code),
+        content=response.content,
+        headers=response.headers,
+        parsed=_parse_response(client=client, response=response),
+    )
+
+
+def sync_detailed(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaUserProfile, ErrorResponse]]:
+    """Get user profile
+
+     Get a users profile
+
+    Args:
+        x_api_key (Union[None, Unset, 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[Union[APISchemaUserProfile, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        x_api_key=x_api_key,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaUserProfile, ErrorResponse]]:
+    """Get user profile
+
+     Get a users profile
+
+    Args:
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaUserProfile, ErrorResponse]
+    """
+
+    return sync_detailed(
+        client=client,
+        x_api_key=x_api_key,
+    ).parsed
+
+
+async def asyncio_detailed(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaUserProfile, ErrorResponse]]:
+    """Get user profile
+
+     Get a users profile
+
+    Args:
+        x_api_key (Union[None, Unset, 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[Union[APISchemaUserProfile, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        x_api_key=x_api_key,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaUserProfile, ErrorResponse]]:
+    """Get user profile
+
+     Get a users profile
+
+    Args:
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaUserProfile, ErrorResponse]
+    """
+
+    return (
+        await asyncio_detailed(
+            client=client,
+            x_api_key=x_api_key,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_org_create.py b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_org_create.py
new file mode 100644
index 0000000..ac4bc53
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_org_create.py
@@ -0,0 +1,171 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.http_validation_error import HTTPValidationError
+from ...models.idp_org_create_request import IDPOrgCreateRequest
+from ...types import Response
+
+
+def _get_kwargs(
+    *,
+    body: IDPOrgCreateRequest,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+
+    _kwargs: Dict[str, Any] = {
+        "method": "post",
+        "url": "/webhooks/idp/orgs/create",
+    }
+
+    _body = body.to_dict()
+
+    _kwargs["json"] = _body
+    headers["Content-Type"] = "application/json"
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[Any, HTTPValidationError]]:
+    if response.status_code == HTTPStatus.CREATED:
+        response_201 = response.json()
+        return response_201
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = HTTPValidationError.from_dict(response.json())
+
+        return response_422
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[Any, 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(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgCreateRequest,
+) -> Response[Union[Any, HTTPValidationError]]:
+    """Webhook IDP Org Create
+
+     Create an org from the IDP org created event
+
+    Args:
+        body (IDPOrgCreateRequest):
+
+    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[Union[Any, HTTPValidationError]]
+    """
+
+    kwargs = _get_kwargs(
+        body=body,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgCreateRequest,
+) -> Optional[Union[Any, HTTPValidationError]]:
+    """Webhook IDP Org Create
+
+     Create an org from the IDP org created event
+
+    Args:
+        body (IDPOrgCreateRequest):
+
+    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:
+        Union[Any, HTTPValidationError]
+    """
+
+    return sync_detailed(
+        client=client,
+        body=body,
+    ).parsed
+
+
+async def asyncio_detailed(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgCreateRequest,
+) -> Response[Union[Any, HTTPValidationError]]:
+    """Webhook IDP Org Create
+
+     Create an org from the IDP org created event
+
+    Args:
+        body (IDPOrgCreateRequest):
+
+    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[Union[Any, HTTPValidationError]]
+    """
+
+    kwargs = _get_kwargs(
+        body=body,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgCreateRequest,
+) -> Optional[Union[Any, HTTPValidationError]]:
+    """Webhook IDP Org Create
+
+     Create an org from the IDP org created event
+
+    Args:
+        body (IDPOrgCreateRequest):
+
+    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:
+        Union[Any, HTTPValidationError]
+    """
+
+    return (
+        await asyncio_detailed(
+            client=client,
+            body=body,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_org_user_add.py b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_org_user_add.py
new file mode 100644
index 0000000..defea4f
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_org_user_add.py
@@ -0,0 +1,171 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.http_validation_error import HTTPValidationError
+from ...models.idp_org_user_add_request import IDPOrgUserAddRequest
+from ...types import Response
+
+
+def _get_kwargs(
+    *,
+    body: IDPOrgUserAddRequest,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+
+    _kwargs: Dict[str, Any] = {
+        "method": "post",
+        "url": "/webhooks/idp/orgs/users/add",
+    }
+
+    _body = body.to_dict()
+
+    _kwargs["json"] = _body
+    headers["Content-Type"] = "application/json"
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[Any, HTTPValidationError]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = response.json()
+        return response_200
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = HTTPValidationError.from_dict(response.json())
+
+        return response_422
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[Any, 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(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgUserAddRequest,
+) -> Response[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User added to Org
+
+     Add a user to an Org from the IDP event
+
+    Args:
+        body (IDPOrgUserAddRequest):
+
+    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[Union[Any, HTTPValidationError]]
+    """
+
+    kwargs = _get_kwargs(
+        body=body,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgUserAddRequest,
+) -> Optional[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User added to Org
+
+     Add a user to an Org from the IDP event
+
+    Args:
+        body (IDPOrgUserAddRequest):
+
+    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:
+        Union[Any, HTTPValidationError]
+    """
+
+    return sync_detailed(
+        client=client,
+        body=body,
+    ).parsed
+
+
+async def asyncio_detailed(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgUserAddRequest,
+) -> Response[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User added to Org
+
+     Add a user to an Org from the IDP event
+
+    Args:
+        body (IDPOrgUserAddRequest):
+
+    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[Union[Any, HTTPValidationError]]
+    """
+
+    kwargs = _get_kwargs(
+        body=body,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPOrgUserAddRequest,
+) -> Optional[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User added to Org
+
+     Add a user to an Org from the IDP event
+
+    Args:
+        body (IDPOrgUserAddRequest):
+
+    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:
+        Union[Any, HTTPValidationError]
+    """
+
+    return (
+        await asyncio_detailed(
+            client=client,
+            body=body,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/webhooks/webhooks_create_user.py b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_user_create.py
similarity index 86%
rename from src/maihem/api_client/maihem_client/api/webhooks/webhooks_create_user.py
rename to src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_user_create.py
index 5c319ff..e9e646f 100644
--- a/src/maihem/api_client/maihem_client/api/webhooks/webhooks_create_user.py
+++ b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_user_create.py
@@ -6,19 +6,19 @@
 from ... import errors
 from ...client import AuthenticatedClient, Client
 from ...models.http_validation_error import HTTPValidationError
-from ...models.idp_user import IDPUser
+from ...models.idp_user_create_request import IDPUserCreateRequest
 from ...types import Response
 
 
 def _get_kwargs(
     *,
-    body: IDPUser,
+    body: IDPUserCreateRequest,
 ) -> Dict[str, Any]:
     headers: Dict[str, Any] = {}
 
     _kwargs: Dict[str, Any] = {
         "method": "post",
-        "url": "/webhooks/idp/users",
+        "url": "/webhooks/idp/users/create",
     }
 
     _body = body.to_dict()
@@ -60,14 +60,14 @@ def _build_response(
 def sync_detailed(
     *,
     client: Union[AuthenticatedClient, Client],
-    body: IDPUser,
+    body: IDPUserCreateRequest,
 ) -> Response[Union[Any, HTTPValidationError]]:
     """Webhook IDP User Create
 
-     Receive a new user from the IDP
+     Create a user from the IDP user create event
 
     Args:
-        body (IDPUser):
+        body (IDPUserCreateRequest):
 
     Raises:
         errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -91,14 +91,14 @@ def sync_detailed(
 def sync(
     *,
     client: Union[AuthenticatedClient, Client],
-    body: IDPUser,
+    body: IDPUserCreateRequest,
 ) -> Optional[Union[Any, HTTPValidationError]]:
     """Webhook IDP User Create
 
-     Receive a new user from the IDP
+     Create a user from the IDP user create event
 
     Args:
-        body (IDPUser):
+        body (IDPUserCreateRequest):
 
     Raises:
         errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -117,14 +117,14 @@ def sync(
 async def asyncio_detailed(
     *,
     client: Union[AuthenticatedClient, Client],
-    body: IDPUser,
+    body: IDPUserCreateRequest,
 ) -> Response[Union[Any, HTTPValidationError]]:
     """Webhook IDP User Create
 
-     Receive a new user from the IDP
+     Create a user from the IDP user create event
 
     Args:
-        body (IDPUser):
+        body (IDPUserCreateRequest):
 
     Raises:
         errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -146,14 +146,14 @@ async def asyncio_detailed(
 async def asyncio(
     *,
     client: Union[AuthenticatedClient, Client],
-    body: IDPUser,
+    body: IDPUserCreateRequest,
 ) -> Optional[Union[Any, HTTPValidationError]]:
     """Webhook IDP User Create
 
-     Receive a new user from the IDP
+     Create a user from the IDP user create event
 
     Args:
-        body (IDPUser):
+        body (IDPUserCreateRequest):
 
     Raises:
         errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
diff --git a/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_user_update.py b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_user_update.py
new file mode 100644
index 0000000..49dbdf3
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/webhooks/webhooks_process_idp_user_update.py
@@ -0,0 +1,171 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.http_validation_error import HTTPValidationError
+from ...models.idp_user_update_request import IDPUserUpdateRequest
+from ...types import Response
+
+
+def _get_kwargs(
+    *,
+    body: IDPUserUpdateRequest,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+
+    _kwargs: Dict[str, Any] = {
+        "method": "post",
+        "url": "/webhooks/idp/users/update",
+    }
+
+    _body = body.to_dict()
+
+    _kwargs["json"] = _body
+    headers["Content-Type"] = "application/json"
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[Any, HTTPValidationError]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = response.json()
+        return response_200
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = HTTPValidationError.from_dict(response.json())
+
+        return response_422
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[Any, 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(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPUserUpdateRequest,
+) -> Response[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User Update
+
+     Update a user from the IDP user create event
+
+    Args:
+        body (IDPUserUpdateRequest):
+
+    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[Union[Any, HTTPValidationError]]
+    """
+
+    kwargs = _get_kwargs(
+        body=body,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPUserUpdateRequest,
+) -> Optional[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User Update
+
+     Update a user from the IDP user create event
+
+    Args:
+        body (IDPUserUpdateRequest):
+
+    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:
+        Union[Any, HTTPValidationError]
+    """
+
+    return sync_detailed(
+        client=client,
+        body=body,
+    ).parsed
+
+
+async def asyncio_detailed(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPUserUpdateRequest,
+) -> Response[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User Update
+
+     Update a user from the IDP user create event
+
+    Args:
+        body (IDPUserUpdateRequest):
+
+    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[Union[Any, HTTPValidationError]]
+    """
+
+    kwargs = _get_kwargs(
+        body=body,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    *,
+    client: Union[AuthenticatedClient, Client],
+    body: IDPUserUpdateRequest,
+) -> Optional[Union[Any, HTTPValidationError]]:
+    """Webhook IDP User Update
+
+     Update a user from the IDP user create event
+
+    Args:
+        body (IDPUserUpdateRequest):
+
+    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:
+        Union[Any, HTTPValidationError]
+    """
+
+    return (
+        await asyncio_detailed(
+            client=client,
+            body=body,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/models/__init__.py b/src/maihem/api_client/maihem_client/models/__init__.py
index 2df0d3a..0bf0d53 100644
--- a/src/maihem/api_client/maihem_client/models/__init__.py
+++ b/src/maihem/api_client/maihem_client/models/__init__.py
@@ -1,36 +1,54 @@
 """Contains all the data models used in inputs/outputs"""
 
+from .agent_maihem_role import AgentMaihemRole
 from .agent_type import AgentType
+from .api_schema_agent_target import APISchemaAgentTarget
 from .api_schema_agent_target_create_request import APISchemaAgentTargetCreateRequest
-from .api_schema_agent_target_create_response import APISchemaAgentTargetCreateResponse
-from .api_schema_agent_target_get_response import APISchemaAgentTargetGetResponse
 from .api_schema_conversation_turn_create_request import APISchemaConversationTurnCreateRequest
+from .api_schema_conversation_turn_create_request_document_type_0 import (
+    APISchemaConversationTurnCreateRequestDocumentType0,
+)
 from .api_schema_conversation_turn_create_response import APISchemaConversationTurnCreateResponse
 from .api_schema_links import APISchemaLinks
+from .api_schema_metric import APISchemaMetric
+from .api_schema_org import APISchemaOrg
 from .api_schema_test import APISchemaTest
 from .api_schema_test_create_request import APISchemaTestCreateRequest
 from .api_schema_test_create_request_metrics_config import APISchemaTestCreateRequestMetricsConfig
 from .api_schema_test_metrics_config import APISchemaTestMetricsConfig
+from .api_schema_test_result_metric_feedback import APISchemaTestResultMetricFeedback
+from .api_schema_test_result_metric_feedback_create_request import APISchemaTestResultMetricFeedbackCreateRequest
+from .api_schema_test_result_metric_feedback_create_request_feedback import (
+    APISchemaTestResultMetricFeedbackCreateRequestFeedback,
+)
+from .api_schema_test_result_metric_feedback_feedback import APISchemaTestResultMetricFeedbackFeedback
 from .api_schema_test_run import APISchemaTestRun
+from .api_schema_test_run_conversation_counts import APISchemaTestRunConversationCounts
 from .api_schema_test_run_conversations import APISchemaTestRunConversations
 from .api_schema_test_run_create_request import APISchemaTestRunCreateRequest
 from .api_schema_test_run_result_conversations import APISchemaTestRunResultConversations
+from .api_schema_test_run_result_conversations_metric_scores_type_0 import (
+    APISchemaTestRunResultConversationsMetricScoresType0,
+)
 from .api_schema_test_run_result_metric_scores import APISchemaTestRunResultMetricScores
 from .api_schema_test_run_result_metrics import APISchemaTestRunResultMetrics
-from .api_schema_test_run_result_metrics_metric_scores import APISchemaTestRunResultMetricsMetricScores
+from .api_schema_test_run_result_metrics_metric_scores_type_0 import APISchemaTestRunResultMetricsMetricScoresType0
+from .api_schema_user import APISchemaUser
+from .api_schema_user_profile import APISchemaUserProfile
 from .conversation_nested import ConversationNested
 from .conversation_nested_evaluation import ConversationNestedEvaluation
-from .conversation_nested_evaluation_base import ConversationNestedEvaluationBase
 from .conversation_nested_message import ConversationNestedMessage
 from .conversation_nested_sentence import ConversationNestedSentence
 from .conversation_nested_token_cost import ConversationNestedTokenCost
-from .conversation_nested_token_cost_base import ConversationNestedTokenCostBase
 from .conversation_nested_turn import ConversationNestedTurn
 from .error_codes import ErrorCodes
 from .error_response import ErrorResponse
 from .error_response_error import ErrorResponseError
 from .http_validation_error import HTTPValidationError
-from .idp_user import IDPUser
+from .idp_org_create_request import IDPOrgCreateRequest
+from .idp_org_user_add_request import IDPOrgUserAddRequest
+from .idp_user_create_request import IDPUserCreateRequest
+from .idp_user_update_request import IDPUserUpdateRequest
 from .org import Org
 from .org_base import OrgBase
 from .test_result_enum import TestResultEnum
@@ -38,37 +56,49 @@
 from .validation_error import ValidationError
 
 __all__ = (
+    "AgentMaihemRole",
     "AgentType",
+    "APISchemaAgentTarget",
     "APISchemaAgentTargetCreateRequest",
-    "APISchemaAgentTargetCreateResponse",
-    "APISchemaAgentTargetGetResponse",
     "APISchemaConversationTurnCreateRequest",
+    "APISchemaConversationTurnCreateRequestDocumentType0",
     "APISchemaConversationTurnCreateResponse",
     "APISchemaLinks",
+    "APISchemaMetric",
+    "APISchemaOrg",
     "APISchemaTest",
     "APISchemaTestCreateRequest",
     "APISchemaTestCreateRequestMetricsConfig",
     "APISchemaTestMetricsConfig",
+    "APISchemaTestResultMetricFeedback",
+    "APISchemaTestResultMetricFeedbackCreateRequest",
+    "APISchemaTestResultMetricFeedbackCreateRequestFeedback",
+    "APISchemaTestResultMetricFeedbackFeedback",
     "APISchemaTestRun",
+    "APISchemaTestRunConversationCounts",
     "APISchemaTestRunConversations",
     "APISchemaTestRunCreateRequest",
     "APISchemaTestRunResultConversations",
+    "APISchemaTestRunResultConversationsMetricScoresType0",
     "APISchemaTestRunResultMetrics",
     "APISchemaTestRunResultMetricScores",
-    "APISchemaTestRunResultMetricsMetricScores",
+    "APISchemaTestRunResultMetricsMetricScoresType0",
+    "APISchemaUser",
+    "APISchemaUserProfile",
     "ConversationNested",
     "ConversationNestedEvaluation",
-    "ConversationNestedEvaluationBase",
     "ConversationNestedMessage",
     "ConversationNestedSentence",
     "ConversationNestedTokenCost",
-    "ConversationNestedTokenCostBase",
     "ConversationNestedTurn",
     "ErrorCodes",
     "ErrorResponse",
     "ErrorResponseError",
     "HTTPValidationError",
-    "IDPUser",
+    "IDPOrgCreateRequest",
+    "IDPOrgUserAddRequest",
+    "IDPUserCreateRequest",
+    "IDPUserUpdateRequest",
     "Org",
     "OrgBase",
     "TestResultEnum",
diff --git a/src/maihem/api_client/maihem_client/models/agent_maihem_role.py b/src/maihem/api_client/maihem_client/models/agent_maihem_role.py
new file mode 100644
index 0000000..83df6a9
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/agent_maihem_role.py
@@ -0,0 +1,9 @@
+from enum import Enum
+
+
+class AgentMaihemRole(str, Enum):
+    QA = "qa"
+    SEC = "sec"
+
+    def __str__(self) -> str:
+        return str(self.value)
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_agent_target_get_response.py b/src/maihem/api_client/maihem_client/models/api_schema_agent_target.py
similarity index 50%
rename from src/maihem/api_client/maihem_client/models/api_schema_agent_target_get_response.py
rename to src/maihem/api_client/maihem_client/models/api_schema_agent_target.py
index d0e845b..e55962c 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_agent_target_get_response.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_agent_target.py
@@ -5,13 +5,15 @@
 from attrs import field as _attrs_field
 from dateutil.parser import isoparse
 
+from ..models.test_result_enum import TestResultEnum
+from ..models.test_status_enum import TestStatusEnum
 from ..types import UNSET, Unset
 
-T = TypeVar("T", bound="APISchemaAgentTargetGetResponse")
+T = TypeVar("T", bound="APISchemaAgentTarget")
 
 
 @_attrs_define
-class APISchemaAgentTargetGetResponse:
+class APISchemaAgentTarget:
     """
     Attributes:
         id (str):
@@ -19,11 +21,15 @@ class APISchemaAgentTargetGetResponse:
         updated_at (datetime.datetime):
         identifier (str):
         role (str):
+        language (str):
         name (Union[None, Unset, str]):
         description (Union[None, Unset, str]):
         industry (Union[None, Unset, str]):
-        language (Union[None, Unset, str]):  Default: 'en'.
         url (Union[None, Unset, str]):
+        last_test_run_id (Union[None, Unset, str]):
+        last_test_run_at (Union[None, Unset, datetime.datetime]):
+        last_test_run_status (Union[None, TestStatusEnum, Unset]):
+        last_test_run_result (Union[None, TestResultEnum, Unset]):
     """
 
     id: str
@@ -31,11 +37,15 @@ class APISchemaAgentTargetGetResponse:
     updated_at: datetime.datetime
     identifier: str
     role: str
+    language: str
     name: Union[None, Unset, str] = UNSET
     description: Union[None, Unset, str] = UNSET
     industry: Union[None, Unset, str] = UNSET
-    language: Union[None, Unset, str] = "en"
     url: Union[None, Unset, str] = UNSET
+    last_test_run_id: Union[None, Unset, str] = UNSET
+    last_test_run_at: Union[None, Unset, datetime.datetime] = UNSET
+    last_test_run_status: Union[None, TestStatusEnum, Unset] = UNSET
+    last_test_run_result: Union[None, TestResultEnum, Unset] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
     def to_dict(self) -> Dict[str, Any]:
@@ -49,6 +59,8 @@ def to_dict(self) -> Dict[str, Any]:
 
         role = self.role
 
+        language = self.language
+
         name: Union[None, Unset, str]
         if isinstance(self.name, Unset):
             name = UNSET
@@ -67,18 +79,42 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             industry = self.industry
 
-        language: Union[None, Unset, str]
-        if isinstance(self.language, Unset):
-            language = UNSET
-        else:
-            language = self.language
-
         url: Union[None, Unset, str]
         if isinstance(self.url, Unset):
             url = UNSET
         else:
             url = self.url
 
+        last_test_run_id: Union[None, Unset, str]
+        if isinstance(self.last_test_run_id, Unset):
+            last_test_run_id = UNSET
+        else:
+            last_test_run_id = self.last_test_run_id
+
+        last_test_run_at: Union[None, Unset, str]
+        if isinstance(self.last_test_run_at, Unset):
+            last_test_run_at = UNSET
+        elif isinstance(self.last_test_run_at, datetime.datetime):
+            last_test_run_at = self.last_test_run_at.isoformat()
+        else:
+            last_test_run_at = self.last_test_run_at
+
+        last_test_run_status: Union[None, Unset, str]
+        if isinstance(self.last_test_run_status, Unset):
+            last_test_run_status = UNSET
+        elif isinstance(self.last_test_run_status, TestStatusEnum):
+            last_test_run_status = self.last_test_run_status.value
+        else:
+            last_test_run_status = self.last_test_run_status
+
+        last_test_run_result: Union[None, Unset, str]
+        if isinstance(self.last_test_run_result, Unset):
+            last_test_run_result = UNSET
+        elif isinstance(self.last_test_run_result, TestResultEnum):
+            last_test_run_result = self.last_test_run_result.value
+        else:
+            last_test_run_result = self.last_test_run_result
+
         field_dict: Dict[str, Any] = {}
         field_dict.update(self.additional_properties)
         field_dict.update(
@@ -88,6 +124,7 @@ def to_dict(self) -> Dict[str, Any]:
                 "updated_at": updated_at,
                 "identifier": identifier,
                 "role": role,
+                "language": language,
             }
         )
         if name is not UNSET:
@@ -96,10 +133,16 @@ def to_dict(self) -> Dict[str, Any]:
             field_dict["description"] = description
         if industry is not UNSET:
             field_dict["industry"] = industry
-        if language is not UNSET:
-            field_dict["language"] = language
         if url is not UNSET:
             field_dict["url"] = url
+        if last_test_run_id is not UNSET:
+            field_dict["last_test_run_id"] = last_test_run_id
+        if last_test_run_at is not UNSET:
+            field_dict["last_test_run_at"] = last_test_run_at
+        if last_test_run_status is not UNSET:
+            field_dict["last_test_run_status"] = last_test_run_status
+        if last_test_run_result is not UNSET:
+            field_dict["last_test_run_result"] = last_test_run_result
 
         return field_dict
 
@@ -116,6 +159,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
 
         role = d.pop("role")
 
+        language = d.pop("language")
+
         def _parse_name(data: object) -> Union[None, Unset, str]:
             if data is None:
                 return data
@@ -143,39 +188,94 @@ def _parse_industry(data: object) -> Union[None, Unset, str]:
 
         industry = _parse_industry(d.pop("industry", UNSET))
 
-        def _parse_language(data: object) -> Union[None, Unset, str]:
+        def _parse_url(data: object) -> Union[None, Unset, str]:
             if data is None:
                 return data
             if isinstance(data, Unset):
                 return data
             return cast(Union[None, Unset, str], data)
 
-        language = _parse_language(d.pop("language", UNSET))
+        url = _parse_url(d.pop("url", UNSET))
 
-        def _parse_url(data: object) -> Union[None, Unset, str]:
+        def _parse_last_test_run_id(data: object) -> Union[None, Unset, str]:
             if data is None:
                 return data
             if isinstance(data, Unset):
                 return data
             return cast(Union[None, Unset, str], data)
 
-        url = _parse_url(d.pop("url", UNSET))
+        last_test_run_id = _parse_last_test_run_id(d.pop("last_test_run_id", UNSET))
 
-        api_schema_agent_target_get_response = cls(
+        def _parse_last_test_run_at(data: object) -> Union[None, Unset, datetime.datetime]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, str):
+                    raise TypeError()
+                last_test_run_at_type_0 = isoparse(data)
+
+                return last_test_run_at_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union[None, Unset, datetime.datetime], data)
+
+        last_test_run_at = _parse_last_test_run_at(d.pop("last_test_run_at", UNSET))
+
+        def _parse_last_test_run_status(data: object) -> Union[None, TestStatusEnum, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, str):
+                    raise TypeError()
+                last_test_run_status_type_0 = TestStatusEnum(data)
+
+                return last_test_run_status_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union[None, TestStatusEnum, Unset], data)
+
+        last_test_run_status = _parse_last_test_run_status(d.pop("last_test_run_status", UNSET))
+
+        def _parse_last_test_run_result(data: object) -> Union[None, TestResultEnum, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, str):
+                    raise TypeError()
+                last_test_run_result_type_0 = TestResultEnum(data)
+
+                return last_test_run_result_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union[None, TestResultEnum, Unset], data)
+
+        last_test_run_result = _parse_last_test_run_result(d.pop("last_test_run_result", UNSET))
+
+        api_schema_agent_target = cls(
             id=id,
             created_at=created_at,
             updated_at=updated_at,
             identifier=identifier,
             role=role,
+            language=language,
             name=name,
             description=description,
             industry=industry,
-            language=language,
             url=url,
+            last_test_run_id=last_test_run_id,
+            last_test_run_at=last_test_run_at,
+            last_test_run_status=last_test_run_status,
+            last_test_run_result=last_test_run_result,
         )
 
-        api_schema_agent_target_get_response.additional_properties = d
-        return api_schema_agent_target_get_response
+        api_schema_agent_target.additional_properties = d
+        return api_schema_agent_target
 
     @property
     def additional_keys(self) -> List[str]:
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_agent_target_create_response.py b/src/maihem/api_client/maihem_client/models/api_schema_agent_target_create_response.py
deleted file mode 100644
index b32455d..0000000
--- a/src/maihem/api_client/maihem_client/models/api_schema_agent_target_create_response.py
+++ /dev/null
@@ -1,194 +0,0 @@
-import datetime
-from typing import Any, Dict, List, Type, TypeVar, Union, cast
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-from dateutil.parser import isoparse
-
-from ..types import UNSET, Unset
-
-T = TypeVar("T", bound="APISchemaAgentTargetCreateResponse")
-
-
-@_attrs_define
-class APISchemaAgentTargetCreateResponse:
-    """
-    Attributes:
-        id (str):
-        created_at (datetime.datetime):
-        updated_at (datetime.datetime):
-        identifier (str):
-        role (str):
-        name (Union[None, Unset, str]):
-        description (Union[None, Unset, str]):
-        industry (Union[None, Unset, str]):
-        language (Union[None, Unset, str]):  Default: 'en'.
-        url (Union[None, Unset, str]):
-    """
-
-    id: str
-    created_at: datetime.datetime
-    updated_at: datetime.datetime
-    identifier: str
-    role: str
-    name: Union[None, Unset, str] = UNSET
-    description: Union[None, Unset, str] = UNSET
-    industry: Union[None, Unset, str] = UNSET
-    language: Union[None, Unset, str] = "en"
-    url: Union[None, Unset, str] = UNSET
-    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
-
-    def to_dict(self) -> Dict[str, Any]:
-        id = self.id
-
-        created_at = self.created_at.isoformat()
-
-        updated_at = self.updated_at.isoformat()
-
-        identifier = self.identifier
-
-        role = self.role
-
-        name: Union[None, Unset, str]
-        if isinstance(self.name, Unset):
-            name = UNSET
-        else:
-            name = self.name
-
-        description: Union[None, Unset, str]
-        if isinstance(self.description, Unset):
-            description = UNSET
-        else:
-            description = self.description
-
-        industry: Union[None, Unset, str]
-        if isinstance(self.industry, Unset):
-            industry = UNSET
-        else:
-            industry = self.industry
-
-        language: Union[None, Unset, str]
-        if isinstance(self.language, Unset):
-            language = UNSET
-        else:
-            language = self.language
-
-        url: Union[None, Unset, str]
-        if isinstance(self.url, Unset):
-            url = UNSET
-        else:
-            url = self.url
-
-        field_dict: Dict[str, Any] = {}
-        field_dict.update(self.additional_properties)
-        field_dict.update(
-            {
-                "id": id,
-                "created_at": created_at,
-                "updated_at": updated_at,
-                "identifier": identifier,
-                "role": role,
-            }
-        )
-        if name is not UNSET:
-            field_dict["name"] = name
-        if description is not UNSET:
-            field_dict["description"] = description
-        if industry is not UNSET:
-            field_dict["industry"] = industry
-        if language is not UNSET:
-            field_dict["language"] = language
-        if url is not UNSET:
-            field_dict["url"] = url
-
-        return field_dict
-
-    @classmethod
-    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
-        d = src_dict.copy()
-        id = d.pop("id")
-
-        created_at = isoparse(d.pop("created_at"))
-
-        updated_at = isoparse(d.pop("updated_at"))
-
-        identifier = d.pop("identifier")
-
-        role = d.pop("role")
-
-        def _parse_name(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        name = _parse_name(d.pop("name", UNSET))
-
-        def _parse_description(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        description = _parse_description(d.pop("description", UNSET))
-
-        def _parse_industry(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        industry = _parse_industry(d.pop("industry", UNSET))
-
-        def _parse_language(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        language = _parse_language(d.pop("language", UNSET))
-
-        def _parse_url(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        url = _parse_url(d.pop("url", UNSET))
-
-        api_schema_agent_target_create_response = cls(
-            id=id,
-            created_at=created_at,
-            updated_at=updated_at,
-            identifier=identifier,
-            role=role,
-            name=name,
-            description=description,
-            industry=industry,
-            language=language,
-            url=url,
-        )
-
-        api_schema_agent_target_create_response.additional_properties = d
-        return api_schema_agent_target_create_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/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request.py b/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request.py
index 9db8813..e930ec6 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request.py
@@ -1,10 +1,16 @@
-from typing import Any, Dict, List, Type, TypeVar, Union, cast
+from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union, 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.api_schema_conversation_turn_create_request_document_type_0 import (
+        APISchemaConversationTurnCreateRequestDocumentType0,
+    )
+
+
 T = TypeVar("T", bound="APISchemaConversationTurnCreateRequest")
 
 
@@ -14,13 +20,19 @@ class APISchemaConversationTurnCreateRequest:
     Attributes:
         message (Union[None, Unset, str]):
         contexts (Union[List[str], None, Unset]):
+        document (Union['APISchemaConversationTurnCreateRequestDocumentType0', None, Unset]):
     """
 
     message: Union[None, Unset, str] = UNSET
     contexts: Union[List[str], None, Unset] = UNSET
+    document: Union["APISchemaConversationTurnCreateRequestDocumentType0", None, Unset] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
     def to_dict(self) -> Dict[str, Any]:
+        from ..models.api_schema_conversation_turn_create_request_document_type_0 import (
+            APISchemaConversationTurnCreateRequestDocumentType0,
+        )
+
         message: Union[None, Unset, str]
         if isinstance(self.message, Unset):
             message = UNSET
@@ -36,6 +48,14 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             contexts = self.contexts
 
+        document: Union[Dict[str, Any], None, Unset]
+        if isinstance(self.document, Unset):
+            document = UNSET
+        elif isinstance(self.document, APISchemaConversationTurnCreateRequestDocumentType0):
+            document = self.document.to_dict()
+        else:
+            document = self.document
+
         field_dict: Dict[str, Any] = {}
         field_dict.update(self.additional_properties)
         field_dict.update({})
@@ -43,11 +63,17 @@ def to_dict(self) -> Dict[str, Any]:
             field_dict["message"] = message
         if contexts is not UNSET:
             field_dict["contexts"] = contexts
+        if document is not UNSET:
+            field_dict["document"] = document
 
         return field_dict
 
     @classmethod
     def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        from ..models.api_schema_conversation_turn_create_request_document_type_0 import (
+            APISchemaConversationTurnCreateRequestDocumentType0,
+        )
+
         d = src_dict.copy()
 
         def _parse_message(data: object) -> Union[None, Unset, str]:
@@ -76,9 +102,27 @@ def _parse_contexts(data: object) -> Union[List[str], None, Unset]:
 
         contexts = _parse_contexts(d.pop("contexts", UNSET))
 
+        def _parse_document(data: object) -> Union["APISchemaConversationTurnCreateRequestDocumentType0", None, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, dict):
+                    raise TypeError()
+                document_type_0 = APISchemaConversationTurnCreateRequestDocumentType0.from_dict(data)
+
+                return document_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union["APISchemaConversationTurnCreateRequestDocumentType0", None, Unset], data)
+
+        document = _parse_document(d.pop("document", UNSET))
+
         api_schema_conversation_turn_create_request = cls(
             message=message,
             contexts=contexts,
+            document=document,
         )
 
         api_schema_conversation_turn_create_request.additional_properties = d
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request_document_type_0.py b/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request_document_type_0.py
new file mode 100644
index 0000000..11cfe3b
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_conversation_turn_create_request_document_type_0.py
@@ -0,0 +1,43 @@
+from typing import Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+T = TypeVar("T", bound="APISchemaConversationTurnCreateRequestDocumentType0")
+
+
+@_attrs_define
+class APISchemaConversationTurnCreateRequestDocumentType0:
+    """ """
+
+    additional_properties: Dict[str, str] = _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: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        api_schema_conversation_turn_create_request_document_type_0 = cls()
+
+        api_schema_conversation_turn_create_request_document_type_0.additional_properties = d
+        return api_schema_conversation_turn_create_request_document_type_0
+
+    @property
+    def additional_keys(self) -> List[str]:
+        return list(self.additional_properties.keys())
+
+    def __getitem__(self, key: str) -> str:
+        return self.additional_properties[key]
+
+    def __setitem__(self, key: str, value: str) -> 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/src/maihem/api_client/maihem_client/models/api_schema_metric.py b/src/maihem/api_client/maihem_client/models/api_schema_metric.py
new file mode 100644
index 0000000..7e16618
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_metric.py
@@ -0,0 +1,106 @@
+from typing import Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+T = TypeVar("T", bound="APISchemaMetric")
+
+
+@_attrs_define
+class APISchemaMetric:
+    """
+    Attributes:
+        id (str):
+        metric_group (str):
+        metric_group_label (str):
+        metric_sub_group (str):
+        metric_sub_group_label (str):
+        metric (str):
+        metric_label (str):
+    """
+
+    id: str
+    metric_group: str
+    metric_group_label: str
+    metric_sub_group: str
+    metric_sub_group_label: str
+    metric: str
+    metric_label: str
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        id = self.id
+
+        metric_group = self.metric_group
+
+        metric_group_label = self.metric_group_label
+
+        metric_sub_group = self.metric_sub_group
+
+        metric_sub_group_label = self.metric_sub_group_label
+
+        metric = self.metric
+
+        metric_label = self.metric_label
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "id": id,
+                "metric_group": metric_group,
+                "metric_group_label": metric_group_label,
+                "metric_sub_group": metric_sub_group,
+                "metric_sub_group_label": metric_sub_group_label,
+                "metric": metric,
+                "metric_label": metric_label,
+            }
+        )
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        id = d.pop("id")
+
+        metric_group = d.pop("metric_group")
+
+        metric_group_label = d.pop("metric_group_label")
+
+        metric_sub_group = d.pop("metric_sub_group")
+
+        metric_sub_group_label = d.pop("metric_sub_group_label")
+
+        metric = d.pop("metric")
+
+        metric_label = d.pop("metric_label")
+
+        api_schema_metric = cls(
+            id=id,
+            metric_group=metric_group,
+            metric_group_label=metric_group_label,
+            metric_sub_group=metric_sub_group,
+            metric_sub_group_label=metric_sub_group_label,
+            metric=metric,
+            metric_label=metric_label,
+        )
+
+        api_schema_metric.additional_properties = d
+        return api_schema_metric
+
+    @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/src/maihem/api_client/maihem_client/models/api_schema_org.py b/src/maihem/api_client/maihem_client/models/api_schema_org.py
new file mode 100644
index 0000000..b17bcab
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_org.py
@@ -0,0 +1,106 @@
+import datetime
+from typing import Any, Dict, List, Type, TypeVar, Union, cast
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+from dateutil.parser import isoparse
+
+from ..types import UNSET, Unset
+
+T = TypeVar("T", bound="APISchemaOrg")
+
+
+@_attrs_define
+class APISchemaOrg:
+    """
+    Attributes:
+        id (str):
+        created_at (datetime.datetime):
+        updated_at (datetime.datetime):
+        name (str):
+        idp_org_id (Union[None, Unset, str]):
+    """
+
+    id: str
+    created_at: datetime.datetime
+    updated_at: datetime.datetime
+    name: str
+    idp_org_id: Union[None, Unset, str] = UNSET
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        id = self.id
+
+        created_at = self.created_at.isoformat()
+
+        updated_at = self.updated_at.isoformat()
+
+        name = self.name
+
+        idp_org_id: Union[None, Unset, str]
+        if isinstance(self.idp_org_id, Unset):
+            idp_org_id = UNSET
+        else:
+            idp_org_id = self.idp_org_id
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "id": id,
+                "created_at": created_at,
+                "updated_at": updated_at,
+                "name": name,
+            }
+        )
+        if idp_org_id is not UNSET:
+            field_dict["idp_org_id"] = idp_org_id
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        id = d.pop("id")
+
+        created_at = isoparse(d.pop("created_at"))
+
+        updated_at = isoparse(d.pop("updated_at"))
+
+        name = d.pop("name")
+
+        def _parse_idp_org_id(data: object) -> Union[None, Unset, str]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, str], data)
+
+        idp_org_id = _parse_idp_org_id(d.pop("idp_org_id", UNSET))
+
+        api_schema_org = cls(
+            id=id,
+            created_at=created_at,
+            updated_at=updated_at,
+            name=name,
+            idp_org_id=idp_org_id,
+        )
+
+        api_schema_org.additional_properties = d
+        return api_schema_org
+
+    @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/src/maihem/api_client/maihem_client/models/api_schema_user.py b/src/maihem/api_client/maihem_client/models/api_schema_user.py
new file mode 100644
index 0000000..fe6bf11
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_user.py
@@ -0,0 +1,130 @@
+import datetime
+from typing import Any, Dict, List, Type, TypeVar, Union, cast
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+from dateutil.parser import isoparse
+
+from ..types import UNSET, Unset
+
+T = TypeVar("T", bound="APISchemaUser")
+
+
+@_attrs_define
+class APISchemaUser:
+    """
+    Attributes:
+        id (str):
+        created_at (datetime.datetime):
+        updated_at (datetime.datetime):
+        idp_user_id (str):
+        first_name (str):
+        last_name (str):
+        email (str):
+        image_url (Union[None, Unset, str]):
+    """
+
+    id: str
+    created_at: datetime.datetime
+    updated_at: datetime.datetime
+    idp_user_id: str
+    first_name: str
+    last_name: str
+    email: str
+    image_url: Union[None, Unset, str] = UNSET
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        id = self.id
+
+        created_at = self.created_at.isoformat()
+
+        updated_at = self.updated_at.isoformat()
+
+        idp_user_id = self.idp_user_id
+
+        first_name = self.first_name
+
+        last_name = self.last_name
+
+        email = self.email
+
+        image_url: Union[None, Unset, str]
+        if isinstance(self.image_url, Unset):
+            image_url = UNSET
+        else:
+            image_url = self.image_url
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "id": id,
+                "created_at": created_at,
+                "updated_at": updated_at,
+                "idp_user_id": idp_user_id,
+                "first_name": first_name,
+                "last_name": last_name,
+                "email": email,
+            }
+        )
+        if image_url is not UNSET:
+            field_dict["image_url"] = image_url
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        id = d.pop("id")
+
+        created_at = isoparse(d.pop("created_at"))
+
+        updated_at = isoparse(d.pop("updated_at"))
+
+        idp_user_id = d.pop("idp_user_id")
+
+        first_name = d.pop("first_name")
+
+        last_name = d.pop("last_name")
+
+        email = d.pop("email")
+
+        def _parse_image_url(data: object) -> Union[None, Unset, str]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, str], data)
+
+        image_url = _parse_image_url(d.pop("image_url", UNSET))
+
+        api_schema_user = cls(
+            id=id,
+            created_at=created_at,
+            updated_at=updated_at,
+            idp_user_id=idp_user_id,
+            first_name=first_name,
+            last_name=last_name,
+            email=email,
+            image_url=image_url,
+        )
+
+        api_schema_user.additional_properties = d
+        return api_schema_user
+
+    @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/src/maihem/api_client/maihem_client/models/api_schema_user_profile.py b/src/maihem/api_client/maihem_client/models/api_schema_user_profile.py
new file mode 100644
index 0000000..1591182
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_user_profile.py
@@ -0,0 +1,74 @@
+from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+if TYPE_CHECKING:
+    from ..models.api_schema_org import APISchemaOrg
+    from ..models.api_schema_user import APISchemaUser
+
+
+T = TypeVar("T", bound="APISchemaUserProfile")
+
+
+@_attrs_define
+class APISchemaUserProfile:
+    """
+    Attributes:
+        user (APISchemaUser):
+        org (APISchemaOrg):
+    """
+
+    user: "APISchemaUser"
+    org: "APISchemaOrg"
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        user = self.user.to_dict()
+
+        org = self.org.to_dict()
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "user": user,
+                "org": org,
+            }
+        )
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        from ..models.api_schema_org import APISchemaOrg
+        from ..models.api_schema_user import APISchemaUser
+
+        d = src_dict.copy()
+        user = APISchemaUser.from_dict(d.pop("user"))
+
+        org = APISchemaOrg.from_dict(d.pop("org"))
+
+        api_schema_user_profile = cls(
+            user=user,
+            org=org,
+        )
+
+        api_schema_user_profile.additional_properties = d
+        return api_schema_user_profile
+
+    @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/src/maihem/api_client/maihem_client/models/conversation_nested.py b/src/maihem/api_client/maihem_client/models/conversation_nested.py
index 9c1685d..bdf5b7f 100644
--- a/src/maihem/api_client/maihem_client/models/conversation_nested.py
+++ b/src/maihem/api_client/maihem_client/models/conversation_nested.py
@@ -10,7 +10,7 @@
 from ..types import UNSET, Unset
 
 if TYPE_CHECKING:
-    from ..models.conversation_nested_evaluation_base import ConversationNestedEvaluationBase
+    from ..models.conversation_nested_evaluation import ConversationNestedEvaluation
     from ..models.conversation_nested_turn import ConversationNestedTurn
 
 
@@ -28,7 +28,7 @@ class ConversationNested:
         result (TestResultEnum):
         started_at (Union[None, Unset, datetime.datetime]):
         completed_at (Union[None, Unset, datetime.datetime]):
-        evaluations (Union[Unset, List['ConversationNestedEvaluationBase']]):
+        evaluations (Union[Unset, List['ConversationNestedEvaluation']]):
         conversation_turns (Union[Unset, List['ConversationNestedTurn']]):
     """
 
@@ -39,7 +39,7 @@ class ConversationNested:
     result: TestResultEnum
     started_at: Union[None, Unset, datetime.datetime] = UNSET
     completed_at: Union[None, Unset, datetime.datetime] = UNSET
-    evaluations: Union[Unset, List["ConversationNestedEvaluationBase"]] = UNSET
+    evaluations: Union[Unset, List["ConversationNestedEvaluation"]] = UNSET
     conversation_turns: Union[Unset, List["ConversationNestedTurn"]] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
@@ -108,7 +108,7 @@ def to_dict(self) -> Dict[str, Any]:
 
     @classmethod
     def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
-        from ..models.conversation_nested_evaluation_base import ConversationNestedEvaluationBase
+        from ..models.conversation_nested_evaluation import ConversationNestedEvaluation
         from ..models.conversation_nested_turn import ConversationNestedTurn
 
         d = src_dict.copy()
@@ -159,7 +159,7 @@ def _parse_completed_at(data: object) -> Union[None, Unset, datetime.datetime]:
         evaluations = []
         _evaluations = d.pop("evaluations", UNSET)
         for evaluations_item_data in _evaluations or []:
-            evaluations_item = ConversationNestedEvaluationBase.from_dict(evaluations_item_data)
+            evaluations_item = ConversationNestedEvaluation.from_dict(evaluations_item_data)
 
             evaluations.append(evaluations_item)
 
diff --git a/src/maihem/api_client/maihem_client/models/conversation_nested_evaluation_base.py b/src/maihem/api_client/maihem_client/models/conversation_nested_evaluation_base.py
deleted file mode 100644
index a16fb63..0000000
--- a/src/maihem/api_client/maihem_client/models/conversation_nested_evaluation_base.py
+++ /dev/null
@@ -1,207 +0,0 @@
-from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union, cast
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..models.test_result_enum import TestResultEnum
-from ..types import UNSET, Unset
-
-if TYPE_CHECKING:
-    from ..models.conversation_nested_token_cost_base import ConversationNestedTokenCostBase
-
-
-T = TypeVar("T", bound="ConversationNestedEvaluationBase")
-
-
-@_attrs_define
-class ConversationNestedEvaluationBase:
-    """
-    Attributes:
-        result (TestResultEnum):
-        metric_slug (str):
-        id (Union[None, Unset, str]):
-        score (Union[None, Unset, float]):
-        confidence (Union[None, Unset, float]):
-        explanation (Union[None, Unset, str]):
-        classification (Union[None, Unset, str]):
-        token_cost (Union['ConversationNestedTokenCostBase', None, Unset]):
-    """
-
-    result: TestResultEnum
-    metric_slug: str
-    id: Union[None, Unset, str] = UNSET
-    score: Union[None, Unset, float] = UNSET
-    confidence: Union[None, Unset, float] = UNSET
-    explanation: Union[None, Unset, str] = UNSET
-    classification: Union[None, Unset, str] = UNSET
-    token_cost: Union["ConversationNestedTokenCostBase", None, Unset] = UNSET
-    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
-
-    def to_dict(self) -> Dict[str, Any]:
-        from ..models.conversation_nested_token_cost_base import ConversationNestedTokenCostBase
-
-        result = self.result.value
-
-        metric_slug = self.metric_slug
-
-        id: Union[None, Unset, str]
-        if isinstance(self.id, Unset):
-            id = UNSET
-        else:
-            id = self.id
-
-        score: Union[None, Unset, float]
-        if isinstance(self.score, Unset):
-            score = UNSET
-        else:
-            score = self.score
-
-        confidence: Union[None, Unset, float]
-        if isinstance(self.confidence, Unset):
-            confidence = UNSET
-        else:
-            confidence = self.confidence
-
-        explanation: Union[None, Unset, str]
-        if isinstance(self.explanation, Unset):
-            explanation = UNSET
-        else:
-            explanation = self.explanation
-
-        classification: Union[None, Unset, str]
-        if isinstance(self.classification, Unset):
-            classification = UNSET
-        else:
-            classification = self.classification
-
-        token_cost: Union[Dict[str, Any], None, Unset]
-        if isinstance(self.token_cost, Unset):
-            token_cost = UNSET
-        elif isinstance(self.token_cost, ConversationNestedTokenCostBase):
-            token_cost = self.token_cost.to_dict()
-        else:
-            token_cost = self.token_cost
-
-        field_dict: Dict[str, Any] = {}
-        field_dict.update(self.additional_properties)
-        field_dict.update(
-            {
-                "result": result,
-                "metric_slug": metric_slug,
-            }
-        )
-        if id is not UNSET:
-            field_dict["id"] = id
-        if score is not UNSET:
-            field_dict["score"] = score
-        if confidence is not UNSET:
-            field_dict["confidence"] = confidence
-        if explanation is not UNSET:
-            field_dict["explanation"] = explanation
-        if classification is not UNSET:
-            field_dict["classification"] = classification
-        if token_cost is not UNSET:
-            field_dict["token_cost"] = token_cost
-
-        return field_dict
-
-    @classmethod
-    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
-        from ..models.conversation_nested_token_cost_base import ConversationNestedTokenCostBase
-
-        d = src_dict.copy()
-        result = TestResultEnum(d.pop("result"))
-
-        metric_slug = d.pop("metric_slug")
-
-        def _parse_id(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        id = _parse_id(d.pop("id", UNSET))
-
-        def _parse_score(data: object) -> Union[None, Unset, float]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, float], data)
-
-        score = _parse_score(d.pop("score", UNSET))
-
-        def _parse_confidence(data: object) -> Union[None, Unset, float]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, float], data)
-
-        confidence = _parse_confidence(d.pop("confidence", UNSET))
-
-        def _parse_explanation(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        explanation = _parse_explanation(d.pop("explanation", UNSET))
-
-        def _parse_classification(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        classification = _parse_classification(d.pop("classification", UNSET))
-
-        def _parse_token_cost(data: object) -> Union["ConversationNestedTokenCostBase", None, Unset]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            try:
-                if not isinstance(data, dict):
-                    raise TypeError()
-                token_cost_type_0 = ConversationNestedTokenCostBase.from_dict(data)
-
-                return token_cost_type_0
-            except:  # noqa: E722
-                pass
-            return cast(Union["ConversationNestedTokenCostBase", None, Unset], data)
-
-        token_cost = _parse_token_cost(d.pop("token_cost", UNSET))
-
-        conversation_nested_evaluation_base = cls(
-            result=result,
-            metric_slug=metric_slug,
-            id=id,
-            score=score,
-            confidence=confidence,
-            explanation=explanation,
-            classification=classification,
-            token_cost=token_cost,
-        )
-
-        conversation_nested_evaluation_base.additional_properties = d
-        return conversation_nested_evaluation_base
-
-    @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/src/maihem/api_client/maihem_client/models/conversation_nested_token_cost_base.py b/src/maihem/api_client/maihem_client/models/conversation_nested_token_cost_base.py
deleted file mode 100644
index 03202e5..0000000
--- a/src/maihem/api_client/maihem_client/models/conversation_nested_token_cost_base.py
+++ /dev/null
@@ -1,104 +0,0 @@
-from typing import Any, Dict, List, Type, TypeVar, Union, cast
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-T = TypeVar("T", bound="ConversationNestedTokenCostBase")
-
-
-@_attrs_define
-class ConversationNestedTokenCostBase:
-    """
-    Attributes:
-        input_tokens (int):
-        output_tokens (int):
-        cost_amount (int):
-        cost_currency (str):
-        id (Union[None, Unset, str]):
-    """
-
-    input_tokens: int
-    output_tokens: int
-    cost_amount: int
-    cost_currency: str
-    id: Union[None, Unset, str] = UNSET
-    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
-
-    def to_dict(self) -> Dict[str, Any]:
-        input_tokens = self.input_tokens
-
-        output_tokens = self.output_tokens
-
-        cost_amount = self.cost_amount
-
-        cost_currency = self.cost_currency
-
-        id: Union[None, Unset, str]
-        if isinstance(self.id, Unset):
-            id = UNSET
-        else:
-            id = self.id
-
-        field_dict: Dict[str, Any] = {}
-        field_dict.update(self.additional_properties)
-        field_dict.update(
-            {
-                "input_tokens": input_tokens,
-                "output_tokens": output_tokens,
-                "cost_amount": cost_amount,
-                "cost_currency": cost_currency,
-            }
-        )
-        if id is not UNSET:
-            field_dict["id"] = id
-
-        return field_dict
-
-    @classmethod
-    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
-        d = src_dict.copy()
-        input_tokens = d.pop("input_tokens")
-
-        output_tokens = d.pop("output_tokens")
-
-        cost_amount = d.pop("cost_amount")
-
-        cost_currency = d.pop("cost_currency")
-
-        def _parse_id(data: object) -> Union[None, Unset, str]:
-            if data is None:
-                return data
-            if isinstance(data, Unset):
-                return data
-            return cast(Union[None, Unset, str], data)
-
-        id = _parse_id(d.pop("id", UNSET))
-
-        conversation_nested_token_cost_base = cls(
-            input_tokens=input_tokens,
-            output_tokens=output_tokens,
-            cost_amount=cost_amount,
-            cost_currency=cost_currency,
-            id=id,
-        )
-
-        conversation_nested_token_cost_base.additional_properties = d
-        return conversation_nested_token_cost_base
-
-    @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/src/maihem/api_client/maihem_client/models/error_codes.py b/src/maihem/api_client/maihem_client/models/error_codes.py
index a2d7d6a..31fcdeb 100644
--- a/src/maihem/api_client/maihem_client/models/error_codes.py
+++ b/src/maihem/api_client/maihem_client/models/error_codes.py
@@ -6,6 +6,7 @@ class ErrorCodes(str, Enum):
     ERR_DATA_INTEGRITY = "err_data_integrity"
     ERR_INTERNAL_SERVER = "err_internal_server"
     ERR_NOT_FOUND = "err_not_found"
+    ERR_REQUEST_TIMEOUT = "err_request_timeout"
     ERR_REQUEST_VALIDATION = "err_request_validation"
     ERR_SCHEMA_VALIDATION = "err_schema_validation"
 
diff --git a/src/maihem/api_client/maihem_client/models/idp_org_create_request.py b/src/maihem/api_client/maihem_client/models/idp_org_create_request.py
new file mode 100644
index 0000000..9ce3090
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/idp_org_create_request.py
@@ -0,0 +1,74 @@
+from typing import Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+T = TypeVar("T", bound="IDPOrgCreateRequest")
+
+
+@_attrs_define
+class IDPOrgCreateRequest:
+    """
+    Attributes:
+        event_type (str):
+        org_id (str):
+        name (str):
+    """
+
+    event_type: str
+    org_id: str
+    name: str
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        event_type = self.event_type
+
+        org_id = self.org_id
+
+        name = self.name
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "event_type": event_type,
+                "org_id": org_id,
+                "name": name,
+            }
+        )
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        event_type = d.pop("event_type")
+
+        org_id = d.pop("org_id")
+
+        name = d.pop("name")
+
+        idp_org_create_request = cls(
+            event_type=event_type,
+            org_id=org_id,
+            name=name,
+        )
+
+        idp_org_create_request.additional_properties = d
+        return idp_org_create_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/src/maihem/api_client/maihem_client/models/idp_org_user_add_request.py b/src/maihem/api_client/maihem_client/models/idp_org_user_add_request.py
new file mode 100644
index 0000000..edaf612
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/idp_org_user_add_request.py
@@ -0,0 +1,82 @@
+from typing import Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+T = TypeVar("T", bound="IDPOrgUserAddRequest")
+
+
+@_attrs_define
+class IDPOrgUserAddRequest:
+    """
+    Attributes:
+        event_type (str):
+        org_id (str):
+        role (str):
+        user_id (str):
+    """
+
+    event_type: str
+    org_id: str
+    role: str
+    user_id: str
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        event_type = self.event_type
+
+        org_id = self.org_id
+
+        role = self.role
+
+        user_id = self.user_id
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "event_type": event_type,
+                "org_id": org_id,
+                "role": role,
+                "user_id": user_id,
+            }
+        )
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        event_type = d.pop("event_type")
+
+        org_id = d.pop("org_id")
+
+        role = d.pop("role")
+
+        user_id = d.pop("user_id")
+
+        idp_org_user_add_request = cls(
+            event_type=event_type,
+            org_id=org_id,
+            role=role,
+            user_id=user_id,
+        )
+
+        idp_org_user_add_request.additional_properties = d
+        return idp_org_user_add_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/src/maihem/api_client/maihem_client/models/idp_user.py b/src/maihem/api_client/maihem_client/models/idp_user_create_request.py
similarity index 94%
rename from src/maihem/api_client/maihem_client/models/idp_user.py
rename to src/maihem/api_client/maihem_client/models/idp_user_create_request.py
index 9b787f1..523b8c4 100644
--- a/src/maihem/api_client/maihem_client/models/idp_user.py
+++ b/src/maihem/api_client/maihem_client/models/idp_user_create_request.py
@@ -5,11 +5,11 @@
 
 from ..types import UNSET, Unset
 
-T = TypeVar("T", bound="IDPUser")
+T = TypeVar("T", bound="IDPUserCreateRequest")
 
 
 @_attrs_define
-class IDPUser:
+class IDPUserCreateRequest:
     """
     Attributes:
         email (str):
@@ -109,7 +109,7 @@ def _parse_username(data: object) -> Union[None, Unset, str]:
 
         username = _parse_username(d.pop("username", UNSET))
 
-        idp_user = cls(
+        idp_user_create_request = cls(
             email=email,
             email_confirmed=email_confirmed,
             event_type=event_type,
@@ -120,8 +120,8 @@ def _parse_username(data: object) -> Union[None, Unset, str]:
             username=username,
         )
 
-        idp_user.additional_properties = d
-        return idp_user
+        idp_user_create_request.additional_properties = d
+        return idp_user_create_request
 
     @property
     def additional_keys(self) -> List[str]:
diff --git a/src/maihem/api_client/maihem_client/models/idp_user_update_request.py b/src/maihem/api_client/maihem_client/models/idp_user_update_request.py
new file mode 100644
index 0000000..60545ae
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/idp_user_update_request.py
@@ -0,0 +1,66 @@
+from typing import Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+T = TypeVar("T", bound="IDPUserUpdateRequest")
+
+
+@_attrs_define
+class IDPUserUpdateRequest:
+    """
+    Attributes:
+        event_type (str):
+        user_id (str):
+    """
+
+    event_type: str
+    user_id: str
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        event_type = self.event_type
+
+        user_id = self.user_id
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "event_type": event_type,
+                "user_id": user_id,
+            }
+        )
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        event_type = d.pop("event_type")
+
+        user_id = d.pop("user_id")
+
+        idp_user_update_request = cls(
+            event_type=event_type,
+            user_id=user_id,
+        )
+
+        idp_user_update_request.additional_properties = d
+        return idp_user_update_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/src/maihem/clients.py b/src/maihem/clients.py
index 50df4a1..ca87344 100644
--- a/src/maihem/clients.py
+++ b/src/maihem/clients.py
@@ -1,8 +1,13 @@
+from concurrent.futures import ThreadPoolExecutor, as_completed
 import os
 from typing import Dict, Literal, Optional, List, Tuple
 from pydantic import ValidationError
+import random
+from tqdm import tqdm
+from yaspin import yaspin
+from yaspin.spinners import Spinners
 
-from maihem.schemas.agents import AgentTarget, AgentType
+from maihem.schemas.agents import TargetAgent, AgentType
 from maihem.schemas.tests import (
     Test,
     TestRun,
@@ -31,12 +36,11 @@
 from maihem.api import MaihemHTTPClientSync
 from maihem.schemas.tests import TestStatusEnum
 from maihem.logger import get_logger
-from tqdm import tqdm
-from concurrent.futures import ThreadPoolExecutor, as_completed
 
 
 class Client:
     _base_url: str = "https://api.maihem.ai"
+    _base_url_ui: str = "https://cause.maihem.ai"
     _api_key: str = None
 
     def create_target_agent(
@@ -45,10 +49,10 @@ def create_target_agent(
         role: str,
         industry: str,
         description: str,
-    ) -> AgentTarget:
+    ) -> TargetAgent:
         pass
 
-    def get_target_agent(self, identifier: str) -> AgentTarget:
+    def get_target_agent(self, identifier: str) -> TargetAgent:
         # Add implementation here
         raise NotImplementedError("Method not implemented")
 
@@ -65,7 +69,7 @@ def create_test(
     def create_test_run(
         self,
         test_identifier: str,
-        agent_target: AgentTarget,
+        agent_target: TargetAgent,
         concurrent_conversations: int,
     ) -> TestRun:
         raise NotImplementedError("Method not implemented")
@@ -92,6 +96,9 @@ def _override_base_url(self, base_url: str) -> None:
         self._base_url = base_url
         self._maihem_api_client = MaihemHTTPClientSync(self._base_url, self._api_key)
 
+    def _override_base_url_ui(self, base_url_ui: str) -> None:
+        self._base_url_ui = base_url_ui
+
     def create_target_agent(
         self,
         identifier: str,
@@ -100,7 +107,7 @@ def create_target_agent(
         description: str,
         name: Optional[str] = None,
         language: Optional[str] = "en",
-    ) -> AgentTarget:
+    ) -> TargetAgent:
         logger = get_logger()
         logger.info(f"Creating target agent {identifier}...")
         resp = None
@@ -121,14 +128,14 @@ def create_target_agent(
         agent_target = None
 
         try:
-            agent_target = AgentTarget.model_validate(resp.to_dict())
+            agent_target = TargetAgent.model_validate(resp.to_dict())
         except ValidationError as e:
             errors.handle_schema_validation_error(e)
 
         logger.info(f"Successfully created target agent {identifier}!")
         return agent_target
 
-    def get_target_agent(self, identifier: str) -> AgentTarget:
+    def get_target_agent(self, identifier: str) -> TargetAgent:
         resp = None
         try:
             resp = self._maihem_api_client.get_agent_target_by_identifier(
@@ -140,7 +147,7 @@ def get_target_agent(self, identifier: str) -> AgentTarget:
         agent_target = None
 
         try:
-            agent_target = AgentTarget.model_validate(resp.to_dict())
+            agent_target = TargetAgent.model_validate(resp.to_dict())
         except ValidationError as e:
             errors.handle_schema_validation_error(e)
 
@@ -213,7 +220,7 @@ def get_test(self, identifier: str) -> Test:
     def create_test_run(
         self,
         test_identifier: str,
-        target_agent: AgentTarget,
+        target_agent: TargetAgent,
         concurrent_conversations: int = 1,
     ) -> TestRun:
         if not target_agent._chat_function:
@@ -229,10 +236,11 @@ def create_test_run(
         logger.info(f"Spawning test run for test {test.identifier}...")
 
         try:
-            resp = self._maihem_api_client.create_test_run(
-                test_id=test.id,
-                agent_target_id=target_agent.id,
-            )
+            with yaspin(Spinners.arc, text="Creating Maihem Agents, this might take a minute...") as sp:
+                resp = self._maihem_api_client.create_test_run(
+                    test_id=test.id,
+                    agent_target_id=target_agent.id,
+                )
         except errors.ErrorBase as e:
             errors.handle_base_error(e)
 
@@ -252,8 +260,9 @@ def create_test_run(
             f"Running test run with {len(conversation_ids)} conversations (up to {concurrent_conversations} concurrently)..."
         )
         logger.info(f"Test run ID: {test_run.id}")
-        logger.info(f"Test run results (API): {test_run.links.test_result}")
-        logger.info("Test run results (UI): coming soon!")
+        logger.info(
+            f"Test run results (UI): {self._base_url_ui}/evaluations/{test_run.id}"
+        )
 
         print("\n" + "-" * 50 + "\n")
 
@@ -382,7 +391,7 @@ def _run_conversation(
         test_run_id: str,
         conversation_id: str,
         test: Test,
-        target_agent: AgentTarget,
+        target_agent: TargetAgent,
         progress_bar_position: int,
     ) -> str:
         is_conversation_active = True
@@ -427,35 +436,44 @@ def _run_conversation_turn(
         test_run_id: str,
         conversation_id: str,
         test: Test,
-        target_agent: AgentTarget,
+        target_agent: TargetAgent,
         previous_turn_id: Optional[str] = None,
     ) -> ConversationTurnCreateResponse:
-        agent_maithem_message = None
+        agent_maihem_message = None
 
         conversation = self.get_conversation(conversation_id)
 
+        document_key = None
+        document_text = None
+
+        if target_agent._documents:
+            document_key = random.choice(list(target_agent._documents.keys()))
+            document_text = target_agent._documents[document_key]
+
         if (
             test.initiating_agent == AgentType.MAIHEM
             and len(conversation.conversation_turns) == 0
         ):
+
             turn_resp = self._generate_conversation_turn(
                 test_run_id=test_run_id,
                 conversation_id=conversation_id,
                 target_agent_message=None,
                 contexts=[],
+                document={document_key: document_text} if document_key else None,
             )
 
-            agent_maithem_message = self._get_conversation_message_from_conversation(
+            agent_maihem_message = self._get_conversation_message_from_conversation(
                 turn_id=turn_resp.turn_id,
                 agent_type=AgentType.MAIHEM,
                 conversation=turn_resp.conversation,
             )
-        elif previous_turn_id is None:
+        elif previous_turn_id is None and len(conversation.conversation_turns) > 0:
             return ConversationTurnCreateResponse(
                 turn_id=None, conversation=conversation
             )
-        else:
-            agent_maithem_message = self._get_conversation_message_from_conversation(
+        elif previous_turn_id is not None and len(conversation.conversation_turns) > 0:
+            agent_maihem_message = self._get_conversation_message_from_conversation(
                 turn_id=previous_turn_id,
                 agent_type=AgentType.MAIHEM,
                 conversation=conversation,
@@ -466,7 +484,7 @@ def _run_conversation_turn(
                 target_agent,
                 conversation_id,
                 agent_maihem_message=(
-                    agent_maithem_message.content if agent_maithem_message else None
+                    agent_maihem_message.content if agent_maihem_message else None
                 ),
             )
         except Exception as e:
@@ -479,6 +497,7 @@ def _run_conversation_turn(
             conversation_id=conversation_id,
             target_agent_message=target_agent_message,
             contexts=contexts,
+            document={document_key: document_text} if document_key else None,
         )
 
         return turn_resp
@@ -489,6 +508,7 @@ def _generate_conversation_turn(
         conversation_id: str,
         target_agent_message: Optional[str] = None,
         contexts: Optional[List[str]] = None,
+        document: Optional[Dict] = None,
     ) -> ConversationTurnCreateResponse:
         try:
             resp = self._maihem_api_client.create_conversation_turn(
@@ -496,6 +516,7 @@ def _generate_conversation_turn(
                 conversation_id=conversation_id,
                 target_agent_message=target_agent_message,
                 contexts=contexts,
+                document=document,
             )
 
             return ConversationTurnCreateResponse(
@@ -524,9 +545,9 @@ def _get_conversation_message_from_conversation(
 
     def _send_target_agent_message(
         self,
-        target_agent: AgentTarget,
+        target_agent: TargetAgent,
         conversation_id: str,
-        agent_maihem_message: str,
+        agent_maihem_message: Optional[str] = None,
     ) -> Tuple[str, List[str]]:
         target_agent_message, contexts = target_agent._send_message(
             conversation_id, agent_maihem_message
@@ -547,17 +568,17 @@ def create_target_agent(
         company: str,
         industry: str,
         description: str,
-    ) -> AgentTarget:
+    ) -> TargetAgent:
         raise NotImplementedError("Method not implemented")
 
-    def get_target_agent(self, identifier: str) -> AgentTarget:
+    def get_target_agent(self, identifier: str) -> TargetAgent:
         raise NotImplementedError("Method not implemented")
 
     def create_test(
         self,
         test_identifier: str,
         initiating_agent: Literal["maihem", "target"],
-        agent_maihem_behavior_prompt: str = None,
+        maihem_agent_behavior_prompt: str = None,
         conversation_turns_max: int = 10,
         metrics_config: Dict = None,
     ) -> Test:
@@ -567,7 +588,7 @@ def create_test_run(
         self,
         identifier: str,
         test_identifier: str,
-        agent_target: AgentTarget,
+        target_agent: TargetAgent,
         dynamic_mode: Literal["static", "dynamic"],
         concurrent_conversations: int,
     ) -> TestRun:
diff --git a/src/maihem/schemas/agents.py b/src/maihem/schemas/agents.py
index 71c8aac..e39ef0c 100644
--- a/src/maihem/schemas/agents.py
+++ b/src/maihem/schemas/agents.py
@@ -1,15 +1,15 @@
 from datetime import datetime
 from pydantic import BaseModel
-from typing import Callable, Optional, Tuple, List
+from typing import Callable, Optional, Tuple, List, Dict
 import maihem.errors as errors
-
 from enum import Enum
 from maihem.logger import get_logger
-
 from pydantic_extra_types.language_code import LanguageAlpha2
+import os
+from maihem.utils import extract_text
 
 
-class AgentTarget(BaseModel):
+class TargetAgent(BaseModel):
     id: str
     created_at: datetime
     updated_at: datetime
@@ -21,6 +21,7 @@ class AgentTarget(BaseModel):
     language: Optional[LanguageAlpha2] = "en"
 
     _chat_function: Optional[Callable] = None
+    _documents: Dict[str, str] = {}
 
     def set_chat_function(self, chat_function: Callable) -> None:
         logger = get_logger()
@@ -53,8 +54,39 @@ def test_chat_function(self, chat_function: Callable) -> bool:
                 f"Error testing target agent chat function: {e}"
             )
 
+    def add_documents(self, documents: List[str]) -> None:
+        logger = get_logger()
+        for doc_path in documents:
+            if not os.path.exists(doc_path):
+                logger.warning(f"Document not found: {doc_path}")
+                continue
+
+            if not os.path.isfile(doc_path):
+                logger.warning(f"Path is not a file: {doc_path}")
+                continue
+
+            file_size = os.path.getsize(doc_path)
+            if file_size == 0:
+                logger.warning(f"File is empty: {doc_path}")
+                continue
+
+            if file_size > 10 * 1024 * 1024:  # 10 MB limit
+                logger.warning(f"File is too large (>10MB): {doc_path}")
+                continue
+
+            try:
+                text = extract_text(doc_path)
+                if not text.strip():
+                    logger.warning(f"Extracted text is empty: {doc_path}")
+                    continue
+                filename = os.path.basename(doc_path)
+                self._documents[filename] = text
+                logger.info(f"Added document: {filename}")
+            except Exception as e:
+                logger.error(f"Error processing document {doc_path}: {str(e)}")
+
     def _send_message(
-        self, conversation_id: str, message: str
+        self, conversation_id: str, message: Optional[str] = ""
     ) -> Tuple[str, List[str]]:
         if not self._chat_function:
             errors.raise_chat_function_error("Target agent chat function not set")
diff --git a/src/maihem/utils.py b/src/maihem/utils.py
new file mode 100644
index 0000000..c982b22
--- /dev/null
+++ b/src/maihem/utils.py
@@ -0,0 +1,37 @@
+import os
+import pymupdf
+import docx2txt
+
+
+def extract_text(file_path):
+    file_extension = os.path.splitext(file_path)[1].lower()
+
+    if file_extension == ".pdf":
+        return extract_pdf_text(file_path)
+    elif file_extension == ".docx":
+        return extract_docx_text(file_path)
+    elif file_extension in [".txt", ".md"]:
+        return extract_text_file(file_path)
+    else:
+        raise ValueError(f"Unsupported file type: {file_extension}")
+
+
+def extract_pdf_text(file_path):
+    doc = pymupdf.open(file_path)
+    text = ""
+    for page in doc:
+        text += page.get_text()
+    return text
+
+
+def extract_docx_text(file_path):
+    text = docx2txt.process(file_path)
+    return text
+
+
+def extract_text_file(file_path):
+    doc = pymupdf.open(file_path, filetype="txt")
+    text = ""
+    for page in doc:
+        text += page.get_text()
+    return text


Test patch:
diff --git a/src/design_maihem_test.py b/src/design_maihem_test.py
new file mode 100644
index 0000000..b7c77c3
--- /dev/null
+++ b/src/design_maihem_test.py
@@ -0,0 +1,87 @@
+from typing import Tuple, List
+import os
+import random
+
+from maihem.clients import Maihem
+from maihem.utils import extract_text
+
+
+# Create a Maihem client by providing your API key. 
+# Add API key to MAIHEM_API_KEY environment variable.
+# os.environ["MAIHEM_API_KEY"] = api_key
+maihem_client = Maihem()
+
+# Create (and describe) the target agent you want to test
+try:
+    target_agent = maihem_client.create_target_agent(
+        identifier="tg_agent_pg_essays",
+        role="question answering",
+        industry="entrepreneurship",
+        description="A chatbot that answers questions about entrepreneurship and startups, based in the essays of Paul Graham, the co-founder of Y Combinator.",
+    )
+except Exception as e:
+    # or get target agent if it exists
+    target_agent = maihem_client.get_target_agent(identifier="tg_agent_pg_essays")
+
+# Example of chat function
+def chat_function(conversation_id: str, agent_maihem_message: str) -> Tuple[str, List[str]]:
+    """
+    Callable chat function to wrap your target agent to be tested.
+
+    params:
+    - conversation_id: unique conversation ID generated by Maihem, use it to keep track of different conversations
+    - agent_maihem_msg: message from the Maihem Agent
+
+    return:
+    - agent_target_message [str] - message from your Target Agent in response to the Maihem Agent message
+    - contexts [List[str]] - list of contexts (required for RAG evaluations), pass empty list if not needed
+    """
+    
+    # The message from your Target Agent. 
+    # Connect your agent here to respond to agent_maihem_message. 
+    # Keep track of same or new conversations with conversation_id
+    agent_target_message = "Hi, how can I help you today?"
+    
+    # List of contexts for RAG evaluations, pass empty list if not needed
+    contexts = ["<Context 1>", "<Context 2>"] 
+    
+    return agent_target_message, contexts
+    
+# Set the chat function to the Target Agent, so we can automatically chat with your Target Agent
+target_agent.set_chat_function(chat_function)
+
+# For RAG testing, add a list of documents so Maihem can generate questions from them to evaluate your Target Agent
+target_agent.add_documents(documents=["./test_data/RAG_PG_essays.pdf"])
+
+# Select the Metrics you want to evaluate your agent on, 
+# and how many conversations you want to run for each metric.
+# You can find the list of supported metrics here: https://docs.maihem.ai/metrics/collection
+metrics_config = {
+    "qa_cx_helpfulness": 2, # Number of conversations to run for this metric
+    "qa_cx_goal_completion": 2, # Number of conversations to run for this metric
+    # "qa_rag_hallucination": 5, # Number of conversations to run for this metric
+    # "qa_rag_answer_relevance": 5, # Number of conversations to run for this metric
+}
+
+# Create a Test
+test = maihem_client.create_test(
+    identifier="test_pg_essays_9999",
+    metrics_config=metrics_config,
+    maihem_agent_behavior_prompt="Ask questions about entrepreneurship and startups based on the essays of Paul Graham. Image you are a young entrepreneur looking for advice, deciding wheter to drop out of college to start a company.",
+    conversation_turns_max=5
+)
+
+# # Create a Test Run from a Test and a Target Agent
+test_run = maihem_client.create_test_run(
+    test_identifier="test_pg_essays_9999", # The identifier of the Test you want to run
+    target_agent=target_agent, # The Target Agent you want to test
+    concurrent_conversations=10, # How many conversations to run concurrently
+)
+
+# Get the results of the Test Run (status and how many conversations passed or failed)
+results = maihem_client.get_test_run_result(test_run_id=test_run.id)
+print(results)
+
+# Get the conversations generated in the Test Run
+conversations = maihem_client.get_test_run_result_conversations(test_run_id=test_run.id)
+print(conversations)
diff --git a/src/maihem/api_client/maihem_client/api/test_result_metrics/__init__.py b/src/maihem/api_client/maihem_client/api/test_result_metrics/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/maihem/api_client/maihem_client/api/test_result_metrics/test_result_metrics_add_test_result_metric_feedback.py b/src/maihem/api_client/maihem_client/api/test_result_metrics/test_result_metrics_add_test_result_metric_feedback.py
new file mode 100644
index 0000000..ab7abc0
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/test_result_metrics/test_result_metrics_add_test_result_metric_feedback.py
@@ -0,0 +1,219 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.api_schema_test_result_metric_feedback import APISchemaTestResultMetricFeedback
+from ...models.api_schema_test_result_metric_feedback_create_request import (
+    APISchemaTestResultMetricFeedbackCreateRequest,
+)
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Response, Unset
+
+
+def _get_kwargs(
+    trm_id: str,
+    *,
+    body: APISchemaTestResultMetricFeedbackCreateRequest,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+    if not isinstance(x_api_key, Unset):
+        headers["x-api-key"] = x_api_key
+
+    _kwargs: Dict[str, Any] = {
+        "method": "post",
+        "url": f"/test-result-metrics/{trm_id}/feedback",
+    }
+
+    _body = body.to_dict()
+
+    _kwargs["json"] = _body
+    headers["Content-Type"] = "application/json"
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]:
+    if response.status_code == HTTPStatus.CREATED:
+        response_201 = APISchemaTestResultMetricFeedback.from_dict(response.json())
+
+        return response_201
+    if response.status_code == HTTPStatus.BAD_REQUEST:
+        response_400 = ErrorResponse.from_dict(response.json())
+
+        return response_400
+    if response.status_code == HTTPStatus.CONFLICT:
+        response_409 = ErrorResponse.from_dict(response.json())
+
+        return response_409
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = ErrorResponse.from_dict(response.json())
+
+        return response_422
+    if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
+        response_500 = ErrorResponse.from_dict(response.json())
+
+        return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]:
+    return Response(
+        status_code=HTTPStatus(response.status_code),
+        content=response.content,
+        headers=response.headers,
+        parsed=_parse_response(client=client, response=response),
+    )
+
+
+def sync_detailed(
+    trm_id: str,
+    *,
+    client: AuthenticatedClient,
+    body: APISchemaTestResultMetricFeedbackCreateRequest,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]:
+    """Add test result metric feedback
+
+     Add feedback to a test result metric
+
+    Args:
+        trm_id (str):
+        x_api_key (Union[None, Unset, str]):
+        body (APISchemaTestResultMetricFeedbackCreateRequest):
+
+    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[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        trm_id=trm_id,
+        body=body,
+        x_api_key=x_api_key,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    trm_id: str,
+    *,
+    client: AuthenticatedClient,
+    body: APISchemaTestResultMetricFeedbackCreateRequest,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]:
+    """Add test result metric feedback
+
+     Add feedback to a test result metric
+
+    Args:
+        trm_id (str):
+        x_api_key (Union[None, Unset, str]):
+        body (APISchemaTestResultMetricFeedbackCreateRequest):
+
+    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:
+        Union[APISchemaTestResultMetricFeedback, ErrorResponse]
+    """
+
+    return sync_detailed(
+        trm_id=trm_id,
+        client=client,
+        body=body,
+        x_api_key=x_api_key,
+    ).parsed
+
+
+async def asyncio_detailed(
+    trm_id: str,
+    *,
+    client: AuthenticatedClient,
+    body: APISchemaTestResultMetricFeedbackCreateRequest,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]:
+    """Add test result metric feedback
+
+     Add feedback to a test result metric
+
+    Args:
+        trm_id (str):
+        x_api_key (Union[None, Unset, str]):
+        body (APISchemaTestResultMetricFeedbackCreateRequest):
+
+    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[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        trm_id=trm_id,
+        body=body,
+        x_api_key=x_api_key,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    trm_id: str,
+    *,
+    client: AuthenticatedClient,
+    body: APISchemaTestResultMetricFeedbackCreateRequest,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaTestResultMetricFeedback, ErrorResponse]]:
+    """Add test result metric feedback
+
+     Add feedback to a test result metric
+
+    Args:
+        trm_id (str):
+        x_api_key (Union[None, Unset, str]):
+        body (APISchemaTestResultMetricFeedbackCreateRequest):
+
+    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:
+        Union[APISchemaTestResultMetricFeedback, ErrorResponse]
+    """
+
+    return (
+        await asyncio_detailed(
+            trm_id=trm_id,
+            client=client,
+            body=body,
+            x_api_key=x_api_key,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_create_conversation_turn.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_create_conversation_turn.py
index a485cc7..7efadb9 100644
--- a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_create_conversation_turn.py
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_create_conversation_turn.py
@@ -59,6 +59,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run.py
index ab3e1c4..1048315 100644
--- a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run.py
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run.py
@@ -51,6 +51,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_conversations.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_conversations.py
index d155138..63348be 100644
--- a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_conversations.py
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_conversations.py
@@ -51,6 +51,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result.py
index 8ed0120..b94abbc 100644
--- a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result.py
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result.py
@@ -51,6 +51,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_conversations.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_conversations.py
index 0bb480d..7de337e 100644
--- a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_conversations.py
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_conversations.py
@@ -51,6 +51,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_metric_conversations.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_metric_conversations.py
new file mode 100644
index 0000000..dbad144
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_run_result_with_metric_conversations.py
@@ -0,0 +1,211 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.api_schema_test_run_result_conversations import APISchemaTestRunResultConversations
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Response, Unset
+
+
+def _get_kwargs(
+    test_run_id: str,
+    metric_id: str,
+    *,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+    if not isinstance(x_api_key, Unset):
+        headers["x-api-key"] = x_api_key
+
+    _kwargs: Dict[str, Any] = {
+        "method": "get",
+        "url": f"/test-runs/{test_run_id}/results/metrics/{metric_id}/conversations",
+    }
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[APISchemaTestRunResultConversations, ErrorResponse]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = APISchemaTestRunResultConversations.from_dict(response.json())
+
+        return response_200
+    if response.status_code == HTTPStatus.BAD_REQUEST:
+        response_400 = ErrorResponse.from_dict(response.json())
+
+        return response_400
+    if response.status_code == HTTPStatus.CONFLICT:
+        response_409 = ErrorResponse.from_dict(response.json())
+
+        return response_409
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = ErrorResponse.from_dict(response.json())
+
+        return response_422
+    if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
+        response_500 = ErrorResponse.from_dict(response.json())
+
+        return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[APISchemaTestRunResultConversations, ErrorResponse]]:
+    return Response(
+        status_code=HTTPStatus(response.status_code),
+        content=response.content,
+        headers=response.headers,
+        parsed=_parse_response(client=client, response=response),
+    )
+
+
+def sync_detailed(
+    test_run_id: str,
+    metric_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaTestRunResultConversations, ErrorResponse]]:
+    """Get test run result metric conversations
+
+     Get a test run result with metric conversations
+
+    Args:
+        test_run_id (str):
+        metric_id (str):
+        x_api_key (Union[None, Unset, 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[Union[APISchemaTestRunResultConversations, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        test_run_id=test_run_id,
+        metric_id=metric_id,
+        x_api_key=x_api_key,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    test_run_id: str,
+    metric_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaTestRunResultConversations, ErrorResponse]]:
+    """Get test run result metric conversations
+
+     Get a test run result with metric conversations
+
+    Args:
+        test_run_id (str):
+        metric_id (str):
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaTestRunResultConversations, ErrorResponse]
+    """
+
+    return sync_detailed(
+        test_run_id=test_run_id,
+        metric_id=metric_id,
+        client=client,
+        x_api_key=x_api_key,
+    ).parsed
+
+
+async def asyncio_detailed(
+    test_run_id: str,
+    metric_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaTestRunResultConversations, ErrorResponse]]:
+    """Get test run result metric conversations
+
+     Get a test run result with metric conversations
+
+    Args:
+        test_run_id (str):
+        metric_id (str):
+        x_api_key (Union[None, Unset, 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[Union[APISchemaTestRunResultConversations, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        test_run_id=test_run_id,
+        metric_id=metric_id,
+        x_api_key=x_api_key,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    test_run_id: str,
+    metric_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaTestRunResultConversations, ErrorResponse]]:
+    """Get test run result metric conversations
+
+     Get a test run result with metric conversations
+
+    Args:
+        test_run_id (str):
+        metric_id (str):
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaTestRunResultConversations, ErrorResponse]
+    """
+
+    return (
+        await asyncio_detailed(
+            test_run_id=test_run_id,
+            metric_id=metric_id,
+            client=client,
+            x_api_key=x_api_key,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_runs.py b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_runs.py
index d801a05..9c492c0 100644
--- a/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_runs.py
+++ b/src/maihem/api_client/maihem_client/api/test_runs/test_runs_get_test_runs.py
@@ -55,6 +55,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/tests/tests_create_test.py b/src/maihem/api_client/maihem_client/api/tests/tests_create_test.py
index 8072e6b..88b383c 100644
--- a/src/maihem/api_client/maihem_client/api/tests/tests_create_test.py
+++ b/src/maihem/api_client/maihem_client/api/tests/tests_create_test.py
@@ -57,6 +57,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/tests/tests_create_test_run.py b/src/maihem/api_client/maihem_client/api/tests/tests_create_test_run.py
index 7a3314c..e90ad16 100644
--- a/src/maihem/api_client/maihem_client/api/tests/tests_create_test_run.py
+++ b/src/maihem/api_client/maihem_client/api/tests/tests_create_test_run.py
@@ -58,6 +58,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/tests/tests_get_test.py b/src/maihem/api_client/maihem_client/api/tests/tests_get_test.py
new file mode 100644
index 0000000..61bde8f
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/api/tests/tests_get_test.py
@@ -0,0 +1,198 @@
+from http import HTTPStatus
+from typing import Any, Dict, Optional, Union
+
+import httpx
+
+from ... import errors
+from ...client import AuthenticatedClient, Client
+from ...models.api_schema_test import APISchemaTest
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Response, Unset
+
+
+def _get_kwargs(
+    test_id: str,
+    *,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Dict[str, Any]:
+    headers: Dict[str, Any] = {}
+    if not isinstance(x_api_key, Unset):
+        headers["x-api-key"] = x_api_key
+
+    _kwargs: Dict[str, Any] = {
+        "method": "get",
+        "url": f"/tests/{test_id}",
+    }
+
+    _kwargs["headers"] = headers
+    return _kwargs
+
+
+def _parse_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Optional[Union[APISchemaTest, ErrorResponse]]:
+    if response.status_code == HTTPStatus.OK:
+        response_200 = APISchemaTest.from_dict(response.json())
+
+        return response_200
+    if response.status_code == HTTPStatus.BAD_REQUEST:
+        response_400 = ErrorResponse.from_dict(response.json())
+
+        return response_400
+    if response.status_code == HTTPStatus.CONFLICT:
+        response_409 = ErrorResponse.from_dict(response.json())
+
+        return response_409
+    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
+        response_422 = ErrorResponse.from_dict(response.json())
+
+        return response_422
+    if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
+        response_500 = ErrorResponse.from_dict(response.json())
+
+        return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
+    if client.raise_on_unexpected_status:
+        raise errors.UnexpectedStatus(response.status_code, response.content)
+    else:
+        return None
+
+
+def _build_response(
+    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
+) -> Response[Union[APISchemaTest, ErrorResponse]]:
+    return Response(
+        status_code=HTTPStatus(response.status_code),
+        content=response.content,
+        headers=response.headers,
+        parsed=_parse_response(client=client, response=response),
+    )
+
+
+def sync_detailed(
+    test_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaTest, ErrorResponse]]:
+    """Get test
+
+     Gets a specified test
+
+    Args:
+        test_id (str):
+        x_api_key (Union[None, Unset, 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[Union[APISchemaTest, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        test_id=test_id,
+        x_api_key=x_api_key,
+    )
+
+    response = client.get_httpx_client().request(
+        **kwargs,
+    )
+
+    return _build_response(client=client, response=response)
+
+
+def sync(
+    test_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaTest, ErrorResponse]]:
+    """Get test
+
+     Gets a specified test
+
+    Args:
+        test_id (str):
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaTest, ErrorResponse]
+    """
+
+    return sync_detailed(
+        test_id=test_id,
+        client=client,
+        x_api_key=x_api_key,
+    ).parsed
+
+
+async def asyncio_detailed(
+    test_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Response[Union[APISchemaTest, ErrorResponse]]:
+    """Get test
+
+     Gets a specified test
+
+    Args:
+        test_id (str):
+        x_api_key (Union[None, Unset, 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[Union[APISchemaTest, ErrorResponse]]
+    """
+
+    kwargs = _get_kwargs(
+        test_id=test_id,
+        x_api_key=x_api_key,
+    )
+
+    response = await client.get_async_httpx_client().request(**kwargs)
+
+    return _build_response(client=client, response=response)
+
+
+async def asyncio(
+    test_id: str,
+    *,
+    client: AuthenticatedClient,
+    x_api_key: Union[None, Unset, str] = UNSET,
+) -> Optional[Union[APISchemaTest, ErrorResponse]]:
+    """Get test
+
+     Gets a specified test
+
+    Args:
+        test_id (str):
+        x_api_key (Union[None, Unset, 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:
+        Union[APISchemaTest, ErrorResponse]
+    """
+
+    return (
+        await asyncio_detailed(
+            test_id=test_id,
+            client=client,
+            x_api_key=x_api_key,
+        )
+    ).parsed
diff --git a/src/maihem/api_client/maihem_client/api/tests/tests_get_test_test_runs.py b/src/maihem/api_client/maihem_client/api/tests/tests_get_test_test_runs.py
index 3437f2a..edf2d91 100644
--- a/src/maihem/api_client/maihem_client/api/tests/tests_get_test_test_runs.py
+++ b/src/maihem/api_client/maihem_client/api/tests/tests_get_test_test_runs.py
@@ -56,6 +56,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/api/tests/tests_get_tests.py b/src/maihem/api_client/maihem_client/api/tests/tests_get_tests.py
index cda7a9e..ec73b0e 100644
--- a/src/maihem/api_client/maihem_client/api/tests/tests_get_tests.py
+++ b/src/maihem/api_client/maihem_client/api/tests/tests_get_tests.py
@@ -63,6 +63,10 @@ def _parse_response(
         response_500 = ErrorResponse.from_dict(response.json())
 
         return response_500
+    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
+        response_504 = ErrorResponse.from_dict(response.json())
+
+        return response_504
     if client.raise_on_unexpected_status:
         raise errors.UnexpectedStatus(response.status_code, response.content)
     else:
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test.py b/src/maihem/api_client/maihem_client/models/api_schema_test.py
index abfedf9..4475075 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_test.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test.py
@@ -5,7 +5,10 @@
 from attrs import field as _attrs_field
 from dateutil.parser import isoparse
 
+from ..models.agent_maihem_role import AgentMaihemRole
 from ..models.agent_type import AgentType
+from ..models.test_result_enum import TestResultEnum
+from ..models.test_status_enum import TestStatusEnum
 from ..types import UNSET, Unset
 
 if TYPE_CHECKING:
@@ -23,22 +26,34 @@ class APISchemaTest:
         created_at (datetime.datetime):
         updated_at (datetime.datetime):
         identifier (str):
+        initiating_agent (AgentType):
         metrics_config (APISchemaTestMetricsConfig):
         name (Union[None, Unset, str]):
-        initiating_agent (Union[Unset, AgentType]):  Default: AgentType.MAIHEM.
         conversation_turns_max (Union[None, Unset, int]):
         agent_maihem_behavior_prompt (Union[None, Unset, str]):
+        agent_maihem_roles (Union[Unset, List[AgentMaihemRole]]):
+        last_test_run_id (Union[None, Unset, str]):
+        last_test_run_at (Union[None, Unset, datetime.datetime]):
+        last_test_run_status (Union[None, TestStatusEnum, Unset]):
+        last_test_run_result (Union[None, TestResultEnum, Unset]):
+        last_test_run_result_score (Union[None, Unset, float]):
     """
 
     id: str
     created_at: datetime.datetime
     updated_at: datetime.datetime
     identifier: str
+    initiating_agent: AgentType
     metrics_config: "APISchemaTestMetricsConfig"
     name: Union[None, Unset, str] = UNSET
-    initiating_agent: Union[Unset, AgentType] = AgentType.MAIHEM
     conversation_turns_max: Union[None, Unset, int] = UNSET
     agent_maihem_behavior_prompt: Union[None, Unset, str] = UNSET
+    agent_maihem_roles: Union[Unset, List[AgentMaihemRole]] = UNSET
+    last_test_run_id: Union[None, Unset, str] = UNSET
+    last_test_run_at: Union[None, Unset, datetime.datetime] = UNSET
+    last_test_run_status: Union[None, TestStatusEnum, Unset] = UNSET
+    last_test_run_result: Union[None, TestResultEnum, Unset] = UNSET
+    last_test_run_result_score: Union[None, Unset, float] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
     def to_dict(self) -> Dict[str, Any]:
@@ -50,6 +65,8 @@ def to_dict(self) -> Dict[str, Any]:
 
         identifier = self.identifier
 
+        initiating_agent = self.initiating_agent.value
+
         metrics_config = self.metrics_config.to_dict()
 
         name: Union[None, Unset, str]
@@ -58,10 +75,6 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             name = self.name
 
-        initiating_agent: Union[Unset, str] = UNSET
-        if not isinstance(self.initiating_agent, Unset):
-            initiating_agent = self.initiating_agent.value
-
         conversation_turns_max: Union[None, Unset, int]
         if isinstance(self.conversation_turns_max, Unset):
             conversation_turns_max = UNSET
@@ -74,6 +87,49 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             agent_maihem_behavior_prompt = self.agent_maihem_behavior_prompt
 
+        agent_maihem_roles: Union[Unset, List[str]] = UNSET
+        if not isinstance(self.agent_maihem_roles, Unset):
+            agent_maihem_roles = []
+            for agent_maihem_roles_item_data in self.agent_maihem_roles:
+                agent_maihem_roles_item = agent_maihem_roles_item_data.value
+                agent_maihem_roles.append(agent_maihem_roles_item)
+
+        last_test_run_id: Union[None, Unset, str]
+        if isinstance(self.last_test_run_id, Unset):
+            last_test_run_id = UNSET
+        else:
+            last_test_run_id = self.last_test_run_id
+
+        last_test_run_at: Union[None, Unset, str]
+        if isinstance(self.last_test_run_at, Unset):
+            last_test_run_at = UNSET
+        elif isinstance(self.last_test_run_at, datetime.datetime):
+            last_test_run_at = self.last_test_run_at.isoformat()
+        else:
+            last_test_run_at = self.last_test_run_at
+
+        last_test_run_status: Union[None, Unset, str]
+        if isinstance(self.last_test_run_status, Unset):
+            last_test_run_status = UNSET
+        elif isinstance(self.last_test_run_status, TestStatusEnum):
+            last_test_run_status = self.last_test_run_status.value
+        else:
+            last_test_run_status = self.last_test_run_status
+
+        last_test_run_result: Union[None, Unset, str]
+        if isinstance(self.last_test_run_result, Unset):
+            last_test_run_result = UNSET
+        elif isinstance(self.last_test_run_result, TestResultEnum):
+            last_test_run_result = self.last_test_run_result.value
+        else:
+            last_test_run_result = self.last_test_run_result
+
+        last_test_run_result_score: Union[None, Unset, float]
+        if isinstance(self.last_test_run_result_score, Unset):
+            last_test_run_result_score = UNSET
+        else:
+            last_test_run_result_score = self.last_test_run_result_score
+
         field_dict: Dict[str, Any] = {}
         field_dict.update(self.additional_properties)
         field_dict.update(
@@ -82,17 +138,28 @@ def to_dict(self) -> Dict[str, Any]:
                 "created_at": created_at,
                 "updated_at": updated_at,
                 "identifier": identifier,
+                "initiating_agent": initiating_agent,
                 "metrics_config": metrics_config,
             }
         )
         if name is not UNSET:
             field_dict["name"] = name
-        if initiating_agent is not UNSET:
-            field_dict["initiating_agent"] = initiating_agent
         if conversation_turns_max is not UNSET:
             field_dict["conversation_turns_max"] = conversation_turns_max
         if agent_maihem_behavior_prompt is not UNSET:
             field_dict["agent_maihem_behavior_prompt"] = agent_maihem_behavior_prompt
+        if agent_maihem_roles is not UNSET:
+            field_dict["agent_maihem_roles"] = agent_maihem_roles
+        if last_test_run_id is not UNSET:
+            field_dict["last_test_run_id"] = last_test_run_id
+        if last_test_run_at is not UNSET:
+            field_dict["last_test_run_at"] = last_test_run_at
+        if last_test_run_status is not UNSET:
+            field_dict["last_test_run_status"] = last_test_run_status
+        if last_test_run_result is not UNSET:
+            field_dict["last_test_run_result"] = last_test_run_result
+        if last_test_run_result_score is not UNSET:
+            field_dict["last_test_run_result_score"] = last_test_run_result_score
 
         return field_dict
 
@@ -109,6 +176,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
 
         identifier = d.pop("identifier")
 
+        initiating_agent = AgentType(d.pop("initiating_agent"))
+
         metrics_config = APISchemaTestMetricsConfig.from_dict(d.pop("metrics_config"))
 
         def _parse_name(data: object) -> Union[None, Unset, str]:
@@ -120,13 +189,6 @@ def _parse_name(data: object) -> Union[None, Unset, str]:
 
         name = _parse_name(d.pop("name", UNSET))
 
-        _initiating_agent = d.pop("initiating_agent", UNSET)
-        initiating_agent: Union[Unset, AgentType]
-        if isinstance(_initiating_agent, Unset):
-            initiating_agent = UNSET
-        else:
-            initiating_agent = AgentType(_initiating_agent)
-
         def _parse_conversation_turns_max(data: object) -> Union[None, Unset, int]:
             if data is None:
                 return data
@@ -145,16 +207,98 @@ def _parse_agent_maihem_behavior_prompt(data: object) -> Union[None, Unset, str]
 
         agent_maihem_behavior_prompt = _parse_agent_maihem_behavior_prompt(d.pop("agent_maihem_behavior_prompt", UNSET))
 
+        agent_maihem_roles = []
+        _agent_maihem_roles = d.pop("agent_maihem_roles", UNSET)
+        for agent_maihem_roles_item_data in _agent_maihem_roles or []:
+            agent_maihem_roles_item = AgentMaihemRole(agent_maihem_roles_item_data)
+
+            agent_maihem_roles.append(agent_maihem_roles_item)
+
+        def _parse_last_test_run_id(data: object) -> Union[None, Unset, str]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, str], data)
+
+        last_test_run_id = _parse_last_test_run_id(d.pop("last_test_run_id", UNSET))
+
+        def _parse_last_test_run_at(data: object) -> Union[None, Unset, datetime.datetime]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, str):
+                    raise TypeError()
+                last_test_run_at_type_0 = isoparse(data)
+
+                return last_test_run_at_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union[None, Unset, datetime.datetime], data)
+
+        last_test_run_at = _parse_last_test_run_at(d.pop("last_test_run_at", UNSET))
+
+        def _parse_last_test_run_status(data: object) -> Union[None, TestStatusEnum, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, str):
+                    raise TypeError()
+                last_test_run_status_type_0 = TestStatusEnum(data)
+
+                return last_test_run_status_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union[None, TestStatusEnum, Unset], data)
+
+        last_test_run_status = _parse_last_test_run_status(d.pop("last_test_run_status", UNSET))
+
+        def _parse_last_test_run_result(data: object) -> Union[None, TestResultEnum, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, str):
+                    raise TypeError()
+                last_test_run_result_type_0 = TestResultEnum(data)
+
+                return last_test_run_result_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union[None, TestResultEnum, Unset], data)
+
+        last_test_run_result = _parse_last_test_run_result(d.pop("last_test_run_result", UNSET))
+
+        def _parse_last_test_run_result_score(data: object) -> Union[None, Unset, float]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, float], data)
+
+        last_test_run_result_score = _parse_last_test_run_result_score(d.pop("last_test_run_result_score", UNSET))
+
         api_schema_test = cls(
             id=id,
             created_at=created_at,
             updated_at=updated_at,
             identifier=identifier,
+            initiating_agent=initiating_agent,
             metrics_config=metrics_config,
             name=name,
-            initiating_agent=initiating_agent,
             conversation_turns_max=conversation_turns_max,
             agent_maihem_behavior_prompt=agent_maihem_behavior_prompt,
+            agent_maihem_roles=agent_maihem_roles,
+            last_test_run_id=last_test_run_id,
+            last_test_run_at=last_test_run_at,
+            last_test_run_status=last_test_run_status,
+            last_test_run_result=last_test_run_result,
+            last_test_run_result_score=last_test_run_result_score,
         )
 
         api_schema_test.additional_properties = d
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback.py b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback.py
new file mode 100644
index 0000000..636d794
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback.py
@@ -0,0 +1,123 @@
+import datetime
+from typing import Any, Dict, List, Type, TypeVar, Union, cast
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+from dateutil.parser import isoparse
+
+from ..models.api_schema_test_result_metric_feedback_feedback import APISchemaTestResultMetricFeedbackFeedback
+from ..types import UNSET, Unset
+
+T = TypeVar("T", bound="APISchemaTestResultMetricFeedback")
+
+
+@_attrs_define
+class APISchemaTestResultMetricFeedback:
+    """
+    Attributes:
+        id (str):
+        created_at (datetime.datetime):
+        updated_at (datetime.datetime):
+        test_result_metric_id (str):
+        created_by (str):
+        feedback (APISchemaTestResultMetricFeedbackFeedback):
+        comments (Union[None, Unset, str]):
+    """
+
+    id: str
+    created_at: datetime.datetime
+    updated_at: datetime.datetime
+    test_result_metric_id: str
+    created_by: str
+    feedback: APISchemaTestResultMetricFeedbackFeedback
+    comments: Union[None, Unset, str] = UNSET
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        id = self.id
+
+        created_at = self.created_at.isoformat()
+
+        updated_at = self.updated_at.isoformat()
+
+        test_result_metric_id = self.test_result_metric_id
+
+        created_by = self.created_by
+
+        feedback = self.feedback.value
+
+        comments: Union[None, Unset, str]
+        if isinstance(self.comments, Unset):
+            comments = UNSET
+        else:
+            comments = self.comments
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "id": id,
+                "created_at": created_at,
+                "updated_at": updated_at,
+                "test_result_metric_id": test_result_metric_id,
+                "created_by": created_by,
+                "feedback": feedback,
+            }
+        )
+        if comments is not UNSET:
+            field_dict["comments"] = comments
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        id = d.pop("id")
+
+        created_at = isoparse(d.pop("created_at"))
+
+        updated_at = isoparse(d.pop("updated_at"))
+
+        test_result_metric_id = d.pop("test_result_metric_id")
+
+        created_by = d.pop("created_by")
+
+        feedback = APISchemaTestResultMetricFeedbackFeedback(d.pop("feedback"))
+
+        def _parse_comments(data: object) -> Union[None, Unset, str]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, str], data)
+
+        comments = _parse_comments(d.pop("comments", UNSET))
+
+        api_schema_test_result_metric_feedback = cls(
+            id=id,
+            created_at=created_at,
+            updated_at=updated_at,
+            test_result_metric_id=test_result_metric_id,
+            created_by=created_by,
+            feedback=feedback,
+            comments=comments,
+        )
+
+        api_schema_test_result_metric_feedback.additional_properties = d
+        return api_schema_test_result_metric_feedback
+
+    @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/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_create_request.py b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_create_request.py
new file mode 100644
index 0000000..fa4a344
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_create_request.py
@@ -0,0 +1,91 @@
+from typing import Any, Dict, List, Type, TypeVar, Union, cast
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..models.api_schema_test_result_metric_feedback_create_request_feedback import (
+    APISchemaTestResultMetricFeedbackCreateRequestFeedback,
+)
+from ..types import UNSET, Unset
+
+T = TypeVar("T", bound="APISchemaTestResultMetricFeedbackCreateRequest")
+
+
+@_attrs_define
+class APISchemaTestResultMetricFeedbackCreateRequest:
+    """
+    Attributes:
+        feedback (Union[Unset, APISchemaTestResultMetricFeedbackCreateRequestFeedback]):  Default:
+            APISchemaTestResultMetricFeedbackCreateRequestFeedback.POSITIVE.
+        comments (Union[None, Unset, str]):
+    """
+
+    feedback: Union[Unset, APISchemaTestResultMetricFeedbackCreateRequestFeedback] = (
+        APISchemaTestResultMetricFeedbackCreateRequestFeedback.POSITIVE
+    )
+    comments: Union[None, Unset, str] = UNSET
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        feedback: Union[Unset, str] = UNSET
+        if not isinstance(self.feedback, Unset):
+            feedback = self.feedback.value
+
+        comments: Union[None, Unset, str]
+        if isinstance(self.comments, Unset):
+            comments = UNSET
+        else:
+            comments = self.comments
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update({})
+        if feedback is not UNSET:
+            field_dict["feedback"] = feedback
+        if comments is not UNSET:
+            field_dict["comments"] = comments
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        _feedback = d.pop("feedback", UNSET)
+        feedback: Union[Unset, APISchemaTestResultMetricFeedbackCreateRequestFeedback]
+        if isinstance(_feedback, Unset):
+            feedback = UNSET
+        else:
+            feedback = APISchemaTestResultMetricFeedbackCreateRequestFeedback(_feedback)
+
+        def _parse_comments(data: object) -> Union[None, Unset, str]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, str], data)
+
+        comments = _parse_comments(d.pop("comments", UNSET))
+
+        api_schema_test_result_metric_feedback_create_request = cls(
+            feedback=feedback,
+            comments=comments,
+        )
+
+        api_schema_test_result_metric_feedback_create_request.additional_properties = d
+        return api_schema_test_result_metric_feedback_create_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/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_create_request_feedback.py b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_create_request_feedback.py
new file mode 100644
index 0000000..0696baf
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_create_request_feedback.py
@@ -0,0 +1,9 @@
+from enum import Enum
+
+
+class APISchemaTestResultMetricFeedbackCreateRequestFeedback(str, Enum):
+    NEGATIVE = "negative"
+    POSITIVE = "positive"
+
+    def __str__(self) -> str:
+        return str(self.value)
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_feedback.py b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_feedback.py
new file mode 100644
index 0000000..674f0ff
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_result_metric_feedback_feedback.py
@@ -0,0 +1,9 @@
+from enum import Enum
+
+
+class APISchemaTestResultMetricFeedbackFeedback(str, Enum):
+    NEGATIVE = "negative"
+    POSITIVE = "positive"
+
+    def __str__(self) -> str:
+        return str(self.value)
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_run.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run.py
index 181dd6f..d3dd3f9 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_test_run.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run.py
@@ -29,6 +29,7 @@ class APISchemaTestRun:
         result (TestResultEnum):
         started_at (Union[None, Unset, datetime.datetime]):
         completed_at (Union[None, Unset, datetime.datetime]):
+        result_score (Union[None, Unset, float]):
         links (Union['APISchemaLinks', None, Unset]):
     """
 
@@ -41,6 +42,7 @@ class APISchemaTestRun:
     result: TestResultEnum
     started_at: Union[None, Unset, datetime.datetime] = UNSET
     completed_at: Union[None, Unset, datetime.datetime] = UNSET
+    result_score: Union[None, Unset, float] = UNSET
     links: Union["APISchemaLinks", None, Unset] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
@@ -77,6 +79,12 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             completed_at = self.completed_at
 
+        result_score: Union[None, Unset, float]
+        if isinstance(self.result_score, Unset):
+            result_score = UNSET
+        else:
+            result_score = self.result_score
+
         links: Union[Dict[str, Any], None, Unset]
         if isinstance(self.links, Unset):
             links = UNSET
@@ -102,6 +110,8 @@ def to_dict(self) -> Dict[str, Any]:
             field_dict["started_at"] = started_at
         if completed_at is not UNSET:
             field_dict["completed_at"] = completed_at
+        if result_score is not UNSET:
+            field_dict["result_score"] = result_score
         if links is not UNSET:
             field_dict["links"] = links
 
@@ -160,6 +170,15 @@ def _parse_completed_at(data: object) -> Union[None, Unset, datetime.datetime]:
 
         completed_at = _parse_completed_at(d.pop("completed_at", UNSET))
 
+        def _parse_result_score(data: object) -> Union[None, Unset, float]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, float], data)
+
+        result_score = _parse_result_score(d.pop("result_score", UNSET))
+
         def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             if data is None:
                 return data
@@ -187,6 +206,7 @@ def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             result=result,
             started_at=started_at,
             completed_at=completed_at,
+            result_score=result_score,
             links=links,
         )
 
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversation_counts.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversation_counts.py
new file mode 100644
index 0000000..4a8b92f
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversation_counts.py
@@ -0,0 +1,160 @@
+from typing import Any, Dict, List, Type, TypeVar, Union, cast
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+T = TypeVar("T", bound="APISchemaTestRunConversationCounts")
+
+
+@_attrs_define
+class APISchemaTestRunConversationCounts:
+    """
+    Attributes:
+        total_conversations (int):
+        result_passed (int):
+        result_failed (int):
+        result_errored (int):
+        result_pending (int):
+        result_cancelled (int):
+        status_completed (int):
+        status_failed (int):
+        status_running (int):
+        status_pending (int):
+        status_paused (int):
+        total_score (Union[None, Unset, float]):
+    """
+
+    total_conversations: int
+    result_passed: int
+    result_failed: int
+    result_errored: int
+    result_pending: int
+    result_cancelled: int
+    status_completed: int
+    status_failed: int
+    status_running: int
+    status_pending: int
+    status_paused: int
+    total_score: Union[None, Unset, float] = UNSET
+    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        total_conversations = self.total_conversations
+
+        result_passed = self.result_passed
+
+        result_failed = self.result_failed
+
+        result_errored = self.result_errored
+
+        result_pending = self.result_pending
+
+        result_cancelled = self.result_cancelled
+
+        status_completed = self.status_completed
+
+        status_failed = self.status_failed
+
+        status_running = self.status_running
+
+        status_pending = self.status_pending
+
+        status_paused = self.status_paused
+
+        total_score: Union[None, Unset, float]
+        if isinstance(self.total_score, Unset):
+            total_score = UNSET
+        else:
+            total_score = self.total_score
+
+        field_dict: Dict[str, Any] = {}
+        field_dict.update(self.additional_properties)
+        field_dict.update(
+            {
+                "total_conversations": total_conversations,
+                "result_passed": result_passed,
+                "result_failed": result_failed,
+                "result_errored": result_errored,
+                "result_pending": result_pending,
+                "result_cancelled": result_cancelled,
+                "status_completed": status_completed,
+                "status_failed": status_failed,
+                "status_running": status_running,
+                "status_pending": status_pending,
+                "status_paused": status_paused,
+            }
+        )
+        if total_score is not UNSET:
+            field_dict["total_score"] = total_score
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        d = src_dict.copy()
+        total_conversations = d.pop("total_conversations")
+
+        result_passed = d.pop("result_passed")
+
+        result_failed = d.pop("result_failed")
+
+        result_errored = d.pop("result_errored")
+
+        result_pending = d.pop("result_pending")
+
+        result_cancelled = d.pop("result_cancelled")
+
+        status_completed = d.pop("status_completed")
+
+        status_failed = d.pop("status_failed")
+
+        status_running = d.pop("status_running")
+
+        status_pending = d.pop("status_pending")
+
+        status_paused = d.pop("status_paused")
+
+        def _parse_total_score(data: object) -> Union[None, Unset, float]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, float], data)
+
+        total_score = _parse_total_score(d.pop("total_score", UNSET))
+
+        api_schema_test_run_conversation_counts = cls(
+            total_conversations=total_conversations,
+            result_passed=result_passed,
+            result_failed=result_failed,
+            result_errored=result_errored,
+            result_pending=result_pending,
+            result_cancelled=result_cancelled,
+            status_completed=status_completed,
+            status_failed=status_failed,
+            status_running=status_running,
+            status_pending=status_pending,
+            status_paused=status_paused,
+            total_score=total_score,
+        )
+
+        api_schema_test_run_conversation_counts.additional_properties = d
+        return api_schema_test_run_conversation_counts
+
+    @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/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversations.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversations.py
index 1ad23d5..c5e18fc 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversations.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run_conversations.py
@@ -29,6 +29,7 @@ class APISchemaTestRunConversations:
         result (TestResultEnum):
         started_at (Union[None, Unset, datetime.datetime]):
         completed_at (Union[None, Unset, datetime.datetime]):
+        result_score (Union[None, Unset, float]):
         links (Union['APISchemaLinks', None, Unset]):
         conversation_ids (Union[Unset, List[str]]):
     """
@@ -42,6 +43,7 @@ class APISchemaTestRunConversations:
     result: TestResultEnum
     started_at: Union[None, Unset, datetime.datetime] = UNSET
     completed_at: Union[None, Unset, datetime.datetime] = UNSET
+    result_score: Union[None, Unset, float] = UNSET
     links: Union["APISchemaLinks", None, Unset] = UNSET
     conversation_ids: Union[Unset, List[str]] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -79,6 +81,12 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             completed_at = self.completed_at
 
+        result_score: Union[None, Unset, float]
+        if isinstance(self.result_score, Unset):
+            result_score = UNSET
+        else:
+            result_score = self.result_score
+
         links: Union[Dict[str, Any], None, Unset]
         if isinstance(self.links, Unset):
             links = UNSET
@@ -108,6 +116,8 @@ def to_dict(self) -> Dict[str, Any]:
             field_dict["started_at"] = started_at
         if completed_at is not UNSET:
             field_dict["completed_at"] = completed_at
+        if result_score is not UNSET:
+            field_dict["result_score"] = result_score
         if links is not UNSET:
             field_dict["links"] = links
         if conversation_ids is not UNSET:
@@ -168,6 +178,15 @@ def _parse_completed_at(data: object) -> Union[None, Unset, datetime.datetime]:
 
         completed_at = _parse_completed_at(d.pop("completed_at", UNSET))
 
+        def _parse_result_score(data: object) -> Union[None, Unset, float]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, float], data)
+
+        result_score = _parse_result_score(d.pop("result_score", UNSET))
+
         def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             if data is None:
                 return data
@@ -197,6 +216,7 @@ def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             result=result,
             started_at=started_at,
             completed_at=completed_at,
+            result_score=result_score,
             links=links,
             conversation_ids=conversation_ids,
         )
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations.py
index 4318032..d67efa8 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations.py
@@ -11,6 +11,10 @@
 
 if TYPE_CHECKING:
     from ..models.api_schema_links import APISchemaLinks
+    from ..models.api_schema_test_run_conversation_counts import APISchemaTestRunConversationCounts
+    from ..models.api_schema_test_run_result_conversations_metric_scores_type_0 import (
+        APISchemaTestRunResultConversationsMetricScoresType0,
+    )
     from ..models.conversation_nested import ConversationNested
 
 
@@ -28,9 +32,12 @@ class APISchemaTestRunResultConversations:
         agent_target_id (str):
         status (TestStatusEnum):
         result (TestResultEnum):
+        conversation_counts (APISchemaTestRunConversationCounts):
         started_at (Union[None, Unset, datetime.datetime]):
         completed_at (Union[None, Unset, datetime.datetime]):
+        result_score (Union[None, Unset, float]):
         links (Union['APISchemaLinks', None, Unset]):
+        metric_scores (Union['APISchemaTestRunResultConversationsMetricScoresType0', None, Unset]):
         conversations (Union[Unset, List['ConversationNested']]):
     """
 
@@ -41,14 +48,20 @@ class APISchemaTestRunResultConversations:
     agent_target_id: str
     status: TestStatusEnum
     result: TestResultEnum
+    conversation_counts: "APISchemaTestRunConversationCounts"
     started_at: Union[None, Unset, datetime.datetime] = UNSET
     completed_at: Union[None, Unset, datetime.datetime] = UNSET
+    result_score: Union[None, Unset, float] = UNSET
     links: Union["APISchemaLinks", None, Unset] = UNSET
+    metric_scores: Union["APISchemaTestRunResultConversationsMetricScoresType0", None, Unset] = UNSET
     conversations: Union[Unset, List["ConversationNested"]] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
     def to_dict(self) -> Dict[str, Any]:
         from ..models.api_schema_links import APISchemaLinks
+        from ..models.api_schema_test_run_result_conversations_metric_scores_type_0 import (
+            APISchemaTestRunResultConversationsMetricScoresType0,
+        )
 
         id = self.id
 
@@ -64,6 +77,8 @@ def to_dict(self) -> Dict[str, Any]:
 
         result = self.result.value
 
+        conversation_counts = self.conversation_counts.to_dict()
+
         started_at: Union[None, Unset, str]
         if isinstance(self.started_at, Unset):
             started_at = UNSET
@@ -80,6 +95,12 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             completed_at = self.completed_at
 
+        result_score: Union[None, Unset, float]
+        if isinstance(self.result_score, Unset):
+            result_score = UNSET
+        else:
+            result_score = self.result_score
+
         links: Union[Dict[str, Any], None, Unset]
         if isinstance(self.links, Unset):
             links = UNSET
@@ -88,6 +109,14 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             links = self.links
 
+        metric_scores: Union[Dict[str, Any], None, Unset]
+        if isinstance(self.metric_scores, Unset):
+            metric_scores = UNSET
+        elif isinstance(self.metric_scores, APISchemaTestRunResultConversationsMetricScoresType0):
+            metric_scores = self.metric_scores.to_dict()
+        else:
+            metric_scores = self.metric_scores
+
         conversations: Union[Unset, List[Dict[str, Any]]] = UNSET
         if not isinstance(self.conversations, Unset):
             conversations = []
@@ -106,14 +135,19 @@ def to_dict(self) -> Dict[str, Any]:
                 "agent_target_id": agent_target_id,
                 "status": status,
                 "result": result,
+                "conversation_counts": conversation_counts,
             }
         )
         if started_at is not UNSET:
             field_dict["started_at"] = started_at
         if completed_at is not UNSET:
             field_dict["completed_at"] = completed_at
+        if result_score is not UNSET:
+            field_dict["result_score"] = result_score
         if links is not UNSET:
             field_dict["links"] = links
+        if metric_scores is not UNSET:
+            field_dict["metric_scores"] = metric_scores
         if conversations is not UNSET:
             field_dict["conversations"] = conversations
 
@@ -122,6 +156,10 @@ def to_dict(self) -> Dict[str, Any]:
     @classmethod
     def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
         from ..models.api_schema_links import APISchemaLinks
+        from ..models.api_schema_test_run_conversation_counts import APISchemaTestRunConversationCounts
+        from ..models.api_schema_test_run_result_conversations_metric_scores_type_0 import (
+            APISchemaTestRunResultConversationsMetricScoresType0,
+        )
         from ..models.conversation_nested import ConversationNested
 
         d = src_dict.copy()
@@ -139,6 +177,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
 
         result = TestResultEnum(d.pop("result"))
 
+        conversation_counts = APISchemaTestRunConversationCounts.from_dict(d.pop("conversation_counts"))
+
         def _parse_started_at(data: object) -> Union[None, Unset, datetime.datetime]:
             if data is None:
                 return data
@@ -173,6 +213,15 @@ def _parse_completed_at(data: object) -> Union[None, Unset, datetime.datetime]:
 
         completed_at = _parse_completed_at(d.pop("completed_at", UNSET))
 
+        def _parse_result_score(data: object) -> Union[None, Unset, float]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, float], data)
+
+        result_score = _parse_result_score(d.pop("result_score", UNSET))
+
         def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             if data is None:
                 return data
@@ -190,6 +239,25 @@ def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
 
         links = _parse_links(d.pop("links", UNSET))
 
+        def _parse_metric_scores(
+            data: object,
+        ) -> Union["APISchemaTestRunResultConversationsMetricScoresType0", None, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, dict):
+                    raise TypeError()
+                metric_scores_type_0 = APISchemaTestRunResultConversationsMetricScoresType0.from_dict(data)
+
+                return metric_scores_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union["APISchemaTestRunResultConversationsMetricScoresType0", None, Unset], data)
+
+        metric_scores = _parse_metric_scores(d.pop("metric_scores", UNSET))
+
         conversations = []
         _conversations = d.pop("conversations", UNSET)
         for conversations_item_data in _conversations or []:
@@ -205,9 +273,12 @@ def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             agent_target_id=agent_target_id,
             status=status,
             result=result,
+            conversation_counts=conversation_counts,
             started_at=started_at,
             completed_at=completed_at,
+            result_score=result_score,
             links=links,
+            metric_scores=metric_scores,
             conversations=conversations,
         )
 
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations_metric_scores_type_0.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations_metric_scores_type_0.py
new file mode 100644
index 0000000..c86e269
--- /dev/null
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_conversations_metric_scores_type_0.py
@@ -0,0 +1,56 @@
+from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+if TYPE_CHECKING:
+    from ..models.api_schema_test_run_result_metric_scores import APISchemaTestRunResultMetricScores
+
+
+T = TypeVar("T", bound="APISchemaTestRunResultConversationsMetricScoresType0")
+
+
+@_attrs_define
+class APISchemaTestRunResultConversationsMetricScoresType0:
+    """ """
+
+    additional_properties: Dict[str, "APISchemaTestRunResultMetricScores"] = _attrs_field(init=False, factory=dict)
+
+    def to_dict(self) -> Dict[str, Any]:
+        field_dict: Dict[str, Any] = {}
+        for prop_name, prop in self.additional_properties.items():
+            field_dict[prop_name] = prop.to_dict()
+
+        return field_dict
+
+    @classmethod
+    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
+        from ..models.api_schema_test_run_result_metric_scores import APISchemaTestRunResultMetricScores
+
+        d = src_dict.copy()
+        api_schema_test_run_result_conversations_metric_scores_type_0 = cls()
+
+        additional_properties = {}
+        for prop_name, prop_dict in d.items():
+            additional_property = APISchemaTestRunResultMetricScores.from_dict(prop_dict)
+
+            additional_properties[prop_name] = additional_property
+
+        api_schema_test_run_result_conversations_metric_scores_type_0.additional_properties = additional_properties
+        return api_schema_test_run_result_conversations_metric_scores_type_0
+
+    @property
+    def additional_keys(self) -> List[str]:
+        return list(self.additional_properties.keys())
+
+    def __getitem__(self, key: str) -> "APISchemaTestRunResultMetricScores":
+        return self.additional_properties[key]
+
+    def __setitem__(self, key: str, value: "APISchemaTestRunResultMetricScores") -> 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/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics.py
index 3a6b943..b71747c 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics.py
@@ -11,7 +11,10 @@
 
 if TYPE_CHECKING:
     from ..models.api_schema_links import APISchemaLinks
-    from ..models.api_schema_test_run_result_metrics_metric_scores import APISchemaTestRunResultMetricsMetricScores
+    from ..models.api_schema_test_run_conversation_counts import APISchemaTestRunConversationCounts
+    from ..models.api_schema_test_run_result_metrics_metric_scores_type_0 import (
+        APISchemaTestRunResultMetricsMetricScoresType0,
+    )
 
 
 T = TypeVar("T", bound="APISchemaTestRunResultMetrics")
@@ -28,10 +31,12 @@ class APISchemaTestRunResultMetrics:
         agent_target_id (str):
         status (TestStatusEnum):
         result (TestResultEnum):
+        conversation_counts (APISchemaTestRunConversationCounts):
         started_at (Union[None, Unset, datetime.datetime]):
         completed_at (Union[None, Unset, datetime.datetime]):
+        result_score (Union[None, Unset, float]):
         links (Union['APISchemaLinks', None, Unset]):
-        metric_scores (Union[Unset, APISchemaTestRunResultMetricsMetricScores]):
+        metric_scores (Union['APISchemaTestRunResultMetricsMetricScoresType0', None, Unset]):
     """
 
     id: str
@@ -41,14 +46,19 @@ class APISchemaTestRunResultMetrics:
     agent_target_id: str
     status: TestStatusEnum
     result: TestResultEnum
+    conversation_counts: "APISchemaTestRunConversationCounts"
     started_at: Union[None, Unset, datetime.datetime] = UNSET
     completed_at: Union[None, Unset, datetime.datetime] = UNSET
+    result_score: Union[None, Unset, float] = UNSET
     links: Union["APISchemaLinks", None, Unset] = UNSET
-    metric_scores: Union[Unset, "APISchemaTestRunResultMetricsMetricScores"] = UNSET
+    metric_scores: Union["APISchemaTestRunResultMetricsMetricScoresType0", None, Unset] = UNSET
     additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
 
     def to_dict(self) -> Dict[str, Any]:
         from ..models.api_schema_links import APISchemaLinks
+        from ..models.api_schema_test_run_result_metrics_metric_scores_type_0 import (
+            APISchemaTestRunResultMetricsMetricScoresType0,
+        )
 
         id = self.id
 
@@ -64,6 +74,8 @@ def to_dict(self) -> Dict[str, Any]:
 
         result = self.result.value
 
+        conversation_counts = self.conversation_counts.to_dict()
+
         started_at: Union[None, Unset, str]
         if isinstance(self.started_at, Unset):
             started_at = UNSET
@@ -80,6 +92,12 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             completed_at = self.completed_at
 
+        result_score: Union[None, Unset, float]
+        if isinstance(self.result_score, Unset):
+            result_score = UNSET
+        else:
+            result_score = self.result_score
+
         links: Union[Dict[str, Any], None, Unset]
         if isinstance(self.links, Unset):
             links = UNSET
@@ -88,9 +106,13 @@ def to_dict(self) -> Dict[str, Any]:
         else:
             links = self.links
 
-        metric_scores: Union[Unset, Dict[str, Any]] = UNSET
-        if not isinstance(self.metric_scores, Unset):
+        metric_scores: Union[Dict[str, Any], None, Unset]
+        if isinstance(self.metric_scores, Unset):
+            metric_scores = UNSET
+        elif isinstance(self.metric_scores, APISchemaTestRunResultMetricsMetricScoresType0):
             metric_scores = self.metric_scores.to_dict()
+        else:
+            metric_scores = self.metric_scores
 
         field_dict: Dict[str, Any] = {}
         field_dict.update(self.additional_properties)
@@ -103,12 +125,15 @@ def to_dict(self) -> Dict[str, Any]:
                 "agent_target_id": agent_target_id,
                 "status": status,
                 "result": result,
+                "conversation_counts": conversation_counts,
             }
         )
         if started_at is not UNSET:
             field_dict["started_at"] = started_at
         if completed_at is not UNSET:
             field_dict["completed_at"] = completed_at
+        if result_score is not UNSET:
+            field_dict["result_score"] = result_score
         if links is not UNSET:
             field_dict["links"] = links
         if metric_scores is not UNSET:
@@ -119,7 +144,10 @@ def to_dict(self) -> Dict[str, Any]:
     @classmethod
     def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
         from ..models.api_schema_links import APISchemaLinks
-        from ..models.api_schema_test_run_result_metrics_metric_scores import APISchemaTestRunResultMetricsMetricScores
+        from ..models.api_schema_test_run_conversation_counts import APISchemaTestRunConversationCounts
+        from ..models.api_schema_test_run_result_metrics_metric_scores_type_0 import (
+            APISchemaTestRunResultMetricsMetricScoresType0,
+        )
 
         d = src_dict.copy()
         id = d.pop("id")
@@ -136,6 +164,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
 
         result = TestResultEnum(d.pop("result"))
 
+        conversation_counts = APISchemaTestRunConversationCounts.from_dict(d.pop("conversation_counts"))
+
         def _parse_started_at(data: object) -> Union[None, Unset, datetime.datetime]:
             if data is None:
                 return data
@@ -170,6 +200,15 @@ def _parse_completed_at(data: object) -> Union[None, Unset, datetime.datetime]:
 
         completed_at = _parse_completed_at(d.pop("completed_at", UNSET))
 
+        def _parse_result_score(data: object) -> Union[None, Unset, float]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            return cast(Union[None, Unset, float], data)
+
+        result_score = _parse_result_score(d.pop("result_score", UNSET))
+
         def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             if data is None:
                 return data
@@ -187,12 +226,22 @@ def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
 
         links = _parse_links(d.pop("links", UNSET))
 
-        _metric_scores = d.pop("metric_scores", UNSET)
-        metric_scores: Union[Unset, APISchemaTestRunResultMetricsMetricScores]
-        if isinstance(_metric_scores, Unset):
-            metric_scores = UNSET
-        else:
-            metric_scores = APISchemaTestRunResultMetricsMetricScores.from_dict(_metric_scores)
+        def _parse_metric_scores(data: object) -> Union["APISchemaTestRunResultMetricsMetricScoresType0", None, Unset]:
+            if data is None:
+                return data
+            if isinstance(data, Unset):
+                return data
+            try:
+                if not isinstance(data, dict):
+                    raise TypeError()
+                metric_scores_type_0 = APISchemaTestRunResultMetricsMetricScoresType0.from_dict(data)
+
+                return metric_scores_type_0
+            except:  # noqa: E722
+                pass
+            return cast(Union["APISchemaTestRunResultMetricsMetricScoresType0", None, Unset], data)
+
+        metric_scores = _parse_metric_scores(d.pop("metric_scores", UNSET))
 
         api_schema_test_run_result_metrics = cls(
             id=id,
@@ -202,8 +251,10 @@ def _parse_links(data: object) -> Union["APISchemaLinks", None, Unset]:
             agent_target_id=agent_target_id,
             status=status,
             result=result,
+            conversation_counts=conversation_counts,
             started_at=started_at,
             completed_at=completed_at,
+            result_score=result_score,
             links=links,
             metric_scores=metric_scores,
         )
diff --git a/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics_metric_scores.py b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics_metric_scores_type_0.py
similarity index 84%
rename from src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics_metric_scores.py
rename to src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics_metric_scores_type_0.py
index 97c792b..9c26d95 100644
--- a/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics_metric_scores.py
+++ b/src/maihem/api_client/maihem_client/models/api_schema_test_run_result_metrics_metric_scores_type_0.py
@@ -7,11 +7,11 @@
     from ..models.api_schema_test_run_result_metric_scores import APISchemaTestRunResultMetricScores
 
 
-T = TypeVar("T", bound="APISchemaTestRunResultMetricsMetricScores")
+T = TypeVar("T", bound="APISchemaTestRunResultMetricsMetricScoresType0")
 
 
 @_attrs_define
-class APISchemaTestRunResultMetricsMetricScores:
+class APISchemaTestRunResultMetricsMetricScoresType0:
     """ """
 
     additional_properties: Dict[str, "APISchemaTestRunResultMetricScores"] = _attrs_field(init=False, factory=dict)
@@ -28,7 +28,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
         from ..models.api_schema_test_run_result_metric_scores import APISchemaTestRunResultMetricScores
 
         d = src_dict.copy()
-        api_schema_test_run_result_metrics_metric_scores = cls()
+        api_schema_test_run_result_metrics_metric_scores_type_0 = cls()
 
         additional_properties = {}
         for prop_name, prop_dict in d.items():
@@ -36,8 +36,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
 
             additional_properties[prop_name] = additional_property
 
-        api_schema_test_run_result_metrics_metric_scores.additional_properties = additional_properties
-        return api_schema_test_run_result_metrics_metric_scores
+        api_schema_test_run_result_metrics_metric_scores_type_0.additional_properties = additional_properties
+        return api_schema_test_run_result_metrics_metric_scores_type_0
 
     @property
     def additional_keys(self) -> List[str]:
diff --git a/src/maihem/schemas/tests.py b/src/maihem/schemas/tests.py
index 2eb4f4f..ede50f5 100644
--- a/src/maihem/schemas/tests.py
+++ b/src/maihem/schemas/tests.py
@@ -76,7 +76,23 @@ class TestRunResultMetricScore(BaseModel):
     errored: int
 
 
+class ConversationCounts(BaseModel):
+    total_conversations: int
+    result_passed: int
+    result_failed: int
+    result_errored: int
+    result_pending: int
+    result_cancelled: int
+    status_completed: int
+    status_failed: int
+    status_running: int
+    status_pending: int
+    status_paused: int
+    total_score: Optional[float] = None
+
+
 class TestRunResultMetrics(TestRun):
+    conversation_counts: ConversationCounts
     metric_scores: Dict[str, TestRunResultMetricScore] = {}
 
 
diff --git a/test_data/RAG_PG_essays.pdf b/test_data/RAG_PG_essays.pdf
new file mode 100644
index 0000000..f595100
Binary files /dev/null and b/test_data/RAG_PG_essays.pdf differ
diff --git a/test_data/test.pdf b/test_data/test.pdf
new file mode 100644
index 0000000..292bc93
Binary files /dev/null and b/test_data/test.pdf differ
diff --git a/test_data/test1.pdf b/test_data/test1.pdf
new file mode 100644
index 0000000..0848182
Binary files /dev/null and b/test_data/test1.pdf differ