codemie-sdk-python 0.1.698__py3-none-any.whl → 0.1.699__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -456,7 +456,7 @@ class ToolConfig(BaseModel):
456
456
  At least one of these fields must be specified for the tool configuration
457
457
  to be valid. This ensures that the tool has a way to obtain credentials.
458
458
  """
459
- if not self.tool_creds and not self.integration_id:
459
+ if not self.tool_creds and self.integration_id is None:
460
460
  raise ValueError("Either tool_creds or integration_id must be provided")
461
461
  if self.tool_creds and self.integration_id:
462
462
  raise ValueError(
@@ -652,3 +652,111 @@ class ReactionRequest(BaseModel):
652
652
  model_config = ConfigDict(extra="ignore", use_enum_values=True)
653
653
 
654
654
  reaction: ReactionType = Field(description="Reaction type: 'like' or 'dislike'")
655
+
656
+
657
+ class AssistantProjectFeature(str, Enum):
658
+ """Feature discriminator for assistant/project mappings (e.g. Teams bot).
659
+
660
+ This enum is expected to grow over time on the backend; treat unrecognized
661
+ wire values defensively rather than assuming this is the complete set.
662
+ """
663
+
664
+ TEAMS = "teams"
665
+
666
+
667
+ class AssistantProjectMappingRequest(BaseModel):
668
+ """Request body for POST /v1/assistants/{assistant_id}/projects/mapping."""
669
+
670
+ model_config = ConfigDict(extra="ignore", use_enum_values=True)
671
+
672
+ project_name: str = Field(description="Project (application) name")
673
+ feature: AssistantProjectFeature = Field(
674
+ description="Feature discriminator this mapping is for, e.g. 'teams'"
675
+ )
676
+
677
+
678
+ class AssistantProjectMappingPagination(BaseModel):
679
+ """Pagination metadata returned by GET /v1/assistants/projects/mapping."""
680
+
681
+ model_config = ConfigDict(extra="ignore")
682
+
683
+ page: int = Field(description="Current page, 0-indexed")
684
+ per_page: int = Field(description="Items per page")
685
+ total: int = Field(description="Total matching assistants across all pages")
686
+
687
+
688
+ class AssistantProjectMappingListResponse(BaseModel):
689
+ """Response for GET /v1/assistants/projects/mapping.
690
+
691
+ List items are intentionally typed as ``dict[str, Any]`` rather than
692
+ ``Assistant``/``AssistantBase``. The backend contract documents this
693
+ endpoint as returning "the same shape as GET /v1/assistants", but that
694
+ endpoint's own shape is parameterized by a ``minimal_response`` flag that
695
+ this new endpoint does not expose, and the exact per-item fields returned
696
+ here are not otherwise confirmed. Rather than guess the wire format,
697
+ callers get the raw dict and can assert on whichever fields they need
698
+ (e.g. ``item["id"]``).
699
+ """
700
+
701
+ model_config = ConfigDict(extra="ignore")
702
+
703
+ data: list[dict[str, Any]] = Field(default_factory=list)
704
+ pagination: AssistantProjectMappingPagination
705
+
706
+
707
+ class UserMappingSlotConfig(BaseModel):
708
+ """Configuration for a single integration slot in user mapping."""
709
+
710
+ model_config = ConfigDict(extra="ignore")
711
+
712
+ name: str = Field(description="Integration slot name (tool name, e.g. 'Git')")
713
+ integration_id: Optional[str] = Field(
714
+ default=None,
715
+ description="Integration ID. None = auto-lookup; empty string = explicit 'no integration'",
716
+ )
717
+ auto_lookup: Optional[bool] = Field(
718
+ default=None,
719
+ description="Whether auto-credentials lookup is enabled for this slot",
720
+ )
721
+ explicit_none: Optional[bool] = Field(
722
+ default=None,
723
+ description="User explicitly chose no integration, blocking auto-lookup override",
724
+ )
725
+
726
+
727
+ class UserMappingSaveRequest(BaseModel):
728
+ """Request body for POST /v1/assistants/{assistant_id}/users/mapping."""
729
+
730
+ model_config = ConfigDict(extra="ignore")
731
+
732
+ tools_config: List[UserMappingSlotConfig] = Field(
733
+ default_factory=list,
734
+ description="Slot configurations to save",
735
+ )
736
+ workflow_id: Optional[str] = Field(
737
+ default=None,
738
+ description="Workflow scope reference. None = assistant scope",
739
+ )
740
+ apply_to_assistant_scope: bool = Field(
741
+ default=False,
742
+ description="When True, saves at assistant scope and removes workflow-scoped override",
743
+ )
744
+
745
+
746
+ class UserMappingResponse(BaseModel):
747
+ """Response body for GET /v1/assistants/{assistant_id}/users/mapping."""
748
+
749
+ model_config = ConfigDict(extra="ignore")
750
+
751
+ tools_config: List[UserMappingSlotConfig] = Field(
752
+ default_factory=list,
753
+ description="Current effective slot configurations",
754
+ )
755
+ has_assistant_scope_selection: bool = Field(
756
+ default=False,
757
+ description="Whether an assistant-scoped mapping row exists for this user",
758
+ )
759
+ workflow_id: Optional[str] = Field(
760
+ default=None,
761
+ description="Workflow scope the response is effective for",
762
+ )
@@ -29,8 +29,12 @@ from ..models.assistant import (
29
29
  AssistantEvaluationRequest,
30
30
  ReactionRequest,
31
31
  ToolCallResumeRequest,
32
+ AssistantProjectFeature,
33
+ AssistantProjectMappingListResponse,
34
+ AssistantProjectMappingRequest,
32
35
  )
33
36
  from ..models.common import PaginationParams
37
+ from ..models.conversation import BaseResponse
34
38
  from ..utils import ApiRequestHandler, TokenSource
35
39
 
36
40
 
@@ -644,3 +648,182 @@ class AssistantService:
644
648
  Response from the API
645
649
  """
646
650
  return self._api.delete(f"/v1/assistants/{assistant_id}/reactions", dict)
651
+
652
+ def list_project_mapping(
653
+ self,
654
+ project_name: str,
655
+ feature: AssistantProjectFeature = AssistantProjectFeature.TEAMS,
656
+ page: int = 0,
657
+ per_page: int = 12,
658
+ ) -> AssistantProjectMappingListResponse:
659
+ """List assistants enabled for a project feature (e.g. Teams bot).
660
+
661
+ Accessible to any member of ``project_name``, not just project admins.
662
+
663
+ Args:
664
+ project_name: Project (application) name to list mappings for
665
+ feature: Feature discriminator, currently only "teams"
666
+ page: Page number, 0-indexed
667
+ per_page: Items per page (default 12, max 10000)
668
+
669
+ Returns:
670
+ Paginated list of assistants enabled for the project feature
671
+ """
672
+ feature_value = (
673
+ feature.value if isinstance(feature, AssistantProjectFeature) else feature
674
+ )
675
+ params = PaginationParams(page=page, per_page=per_page).to_dict()
676
+ params["feature"] = feature_value
677
+ params["project"] = project_name
678
+ return self._api.get(
679
+ "/v1/assistants/projects/mapping",
680
+ AssistantProjectMappingListResponse,
681
+ params=params,
682
+ wrap_response=False,
683
+ )
684
+
685
+ def enable_for_project(
686
+ self,
687
+ assistant_id: str,
688
+ project_name: str,
689
+ feature: AssistantProjectFeature = AssistantProjectFeature.TEAMS,
690
+ ) -> BaseResponse:
691
+ """Enable an assistant for a project feature (e.g. Teams bot).
692
+
693
+ Idempotent — calling this when the mapping already exists returns 200
694
+ with no error. Requires the caller to be a project admin/maintainer
695
+ (or application admin) for ``project_name``.
696
+
697
+ Args:
698
+ assistant_id: ID of the assistant to enable
699
+ project_name: Project (application) name to enable the mapping for
700
+ feature: Feature discriminator, currently only "teams"
701
+
702
+ Returns:
703
+ Response confirming the assistant was enabled
704
+ """
705
+ request = AssistantProjectMappingRequest(
706
+ project_name=project_name, feature=feature
707
+ )
708
+ return self._api.post(
709
+ f"/v1/assistants/{assistant_id}/projects/mapping",
710
+ BaseResponse,
711
+ json_data=request.model_dump(exclude_none=True),
712
+ )
713
+
714
+ def disable_for_project(
715
+ self,
716
+ assistant_id: str,
717
+ project_name: str,
718
+ feature: AssistantProjectFeature = AssistantProjectFeature.TEAMS,
719
+ ) -> BaseResponse:
720
+ """Disable an assistant for a project feature (e.g. Teams bot).
721
+
722
+ Raises an HTTP error (404) if the mapping does not exist. Requires the
723
+ caller to be a project admin/maintainer (or application admin) for
724
+ ``project_name``.
725
+
726
+ Args:
727
+ assistant_id: ID of the assistant to disable
728
+ project_name: Project (application) name to disable the mapping for
729
+ feature: Feature discriminator, currently only "teams"
730
+
731
+ Returns:
732
+ Response confirming the assistant was disabled
733
+ """
734
+ feature_value = (
735
+ feature.value if isinstance(feature, AssistantProjectFeature) else feature
736
+ )
737
+ params = {"project": project_name, "feature": feature_value}
738
+ return self._api.delete(
739
+ f"/v1/assistants/{assistant_id}/projects/mapping",
740
+ BaseResponse,
741
+ params=params,
742
+ )
743
+
744
+ def get_user_mapping(
745
+ self,
746
+ assistant_id: str,
747
+ workflow_id: Optional[str] = None,
748
+ ) -> dict:
749
+ """Get the effective personal integration mapping for an assistant.
750
+
751
+ Returns the merged per-slot view following the resolution order:
752
+ workflow-scoped → assistant-scoped → auto-lookup → none.
753
+
754
+ Args:
755
+ assistant_id: ID of the assistant
756
+ workflow_id: Optional workflow scope. When provided, returns the effective
757
+ selection for that workflow; when omitted, returns assistant-scoped only.
758
+
759
+ Returns:
760
+ Mapping response dict with ``tools_config`` list and
761
+ ``has_assistant_scope_selection`` boolean.
762
+ """
763
+ params: dict = {}
764
+ if workflow_id is not None:
765
+ params["workflow_id"] = workflow_id
766
+ return self._api.get(
767
+ f"/v1/assistants/{assistant_id}/users/mapping",
768
+ dict,
769
+ params=params or None,
770
+ )
771
+
772
+ def save_user_mapping(
773
+ self,
774
+ assistant_id: str,
775
+ tools_config: list,
776
+ workflow_id: Optional[str] = None,
777
+ apply_to_assistant_scope: bool = False,
778
+ ) -> dict:
779
+ """Save personal integration mapping for an assistant.
780
+
781
+ When ``workflow_id`` is supplied and ``apply_to_assistant_scope`` is False,
782
+ a workflow-scoped record is created/updated (the new default on workflow screens).
783
+ When ``apply_to_assistant_scope`` is True, the mapping is promoted to assistant
784
+ scope and any existing workflow-scoped override is removed atomically.
785
+
786
+ Args:
787
+ assistant_id: ID of the assistant
788
+ tools_config: List of slot configuration dicts (each with ``slot_id``
789
+ and optionally ``integration_id``)
790
+ workflow_id: Optional workflow scope reference
791
+ apply_to_assistant_scope: When True, saves at assistant scope
792
+
793
+ Returns:
794
+ Saved mapping response dict
795
+ """
796
+ payload: dict = {"tools_config": tools_config}
797
+ if workflow_id is not None:
798
+ payload["workflow_id"] = workflow_id
799
+ if apply_to_assistant_scope:
800
+ payload["apply_to_assistant_scope"] = True
801
+ return self._api.post(
802
+ f"/v1/assistants/{assistant_id}/users/mapping",
803
+ dict,
804
+ json_data=payload,
805
+ )
806
+
807
+ def delete_user_mapping(
808
+ self,
809
+ assistant_id: str,
810
+ workflow_id: Optional[str] = None,
811
+ ) -> dict:
812
+ """Delete personal integration mapping for an assistant.
813
+
814
+ Args:
815
+ assistant_id: ID of the assistant
816
+ workflow_id: When provided, deletes the workflow-scoped record only.
817
+ When omitted, deletes the assistant-scoped record.
818
+
819
+ Returns:
820
+ Response from the API
821
+ """
822
+ params: dict = {}
823
+ if workflow_id is not None:
824
+ params["workflow_id"] = workflow_id
825
+ return self._api.delete(
826
+ f"/v1/assistants/{assistant_id}/users/mapping",
827
+ dict,
828
+ params=params or None,
829
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codemie-sdk-python
3
- Version: 0.1.698
3
+ Version: 0.1.699
4
4
  Summary: CodeMie SDK for Python
5
5
  License: Apache-2.0
6
6
  Author: CodeMie
@@ -14,7 +14,7 @@ codemie_sdk/models/a2a.py,sha256=zCNLiwwg78rok04hMlGPcQQS1IbEV4OaMcA_1KxQ9xs,158
14
14
  codemie_sdk/models/activity_event.py,sha256=KDEzzUEfs1J9ALNo4mLP-Rq7jeTM4g-P4A5A7Z4YjzM,1072
15
15
  codemie_sdk/models/admin.py,sha256=2UGaO60ZrHHcDcV9thYBVxDyUCvtfPQhs10WswhGFJs,2298
16
16
  codemie_sdk/models/analytics.py,sha256=B9lLAddL_LylXsoOukiPqbz4HVd2itmuB6iaEbhpKiQ,10194
17
- codemie_sdk/models/assistant.py,sha256=BkMMIBKA3fibL98PsyEtlIcvZql63oVdI9Pgy9YnemI,22230
17
+ codemie_sdk/models/assistant.py,sha256=0UGqd2hOhcRfCXaSq1c5z3M5MDfYqRQzn_6gDo8URnI,26114
18
18
  codemie_sdk/models/categories.py,sha256=eq7_sw-sevNLeWpjaW3N055Xcgbbevs0Bl_rj--maUk,2303
19
19
  codemie_sdk/models/common.py,sha256=ipNNdQlv4Ct1UyIAknjJbrdjjvv0lZJYK6dnPm8wai4,1170
20
20
  codemie_sdk/models/conversation.py,sha256=r5gV5BD-Euj4OfeLYn6NBiO-S6uFQtwACVobvFgLUcA,10204
@@ -46,7 +46,7 @@ codemie_sdk/services/a2a.py,sha256=JI_heDKmQ1qYGIES_6qPosHRyVb73tKs4v7uTGpzXx4,1
46
46
  codemie_sdk/services/activity_event.py,sha256=KoD0DyeqJ0CmQPA4PAXH4uGIAQCgcJbYwDnv-MCckGc,3630
47
47
  codemie_sdk/services/admin.py,sha256=yk1xdBXDjpdW4OMOdBaURkZhAxak9h-TppKyhStLekc,4006
48
48
  codemie_sdk/services/analytics.py,sha256=wcbbzm9L4YLXy7I054jM8LYlIQnz3gB2K56--OkVT4g,23148
49
- codemie_sdk/services/assistant.py,sha256=3fHK2cJERgNJJfkvdih0h7bRHdHjlIJHBcS7EcnJ90E,22135
49
+ codemie_sdk/services/assistant.py,sha256=4pgwUXyqego0SUThX2B6FHtsPYmvPzKgr92TEgxAIoA,28835
50
50
  codemie_sdk/services/categories.py,sha256=1qd98JCcMNdpbos0O1WpMApT6TurE7OuI7zoYewnwk8,5030
51
51
  codemie_sdk/services/codemie_guardrails.py,sha256=O3yCeIQYG8W7z-sVRR4Cw9UVncqP9lPVNxUSaUZrh7I,2833
52
52
  codemie_sdk/services/conversation.py,sha256=HWedtlrVXvq4xyAgVNzJ9IZSeHMx4Se5fyp8PPIloEQ,14809
@@ -76,6 +76,6 @@ codemie_sdk/services/workflow_execution_state.py,sha256=u1xmGvaHjqvQS5ujhyvJ_Ac7
76
76
  codemie_sdk/services/workspace.py,sha256=eLwZ0fhi1BfOesrXaQlTdOll8q7ENP9b_jb5eybKSVw,5038
77
77
  codemie_sdk/utils/__init__.py,sha256=EzK_UrS5KHmAnE73Hci9LaObB5omjVUhIq4svh0gfwo,137
78
78
  codemie_sdk/utils/http.py,sha256=PWejBKa5pwzQ5eLVhdN8lYKEu1B1QtwGTRmZfnGFL6c,14158
79
- codemie_sdk_python-0.1.698.dist-info/METADATA,sha256=cIPx5mqzjEbwYqiaAlhUc9OYCjLPYuT5-vHL4rEUrfs,47938
80
- codemie_sdk_python-0.1.698.dist-info/WHEEL,sha256=L-WvLdSBvJWHXv5zrQxDvNRnIgoBzLUpcbuiw19KCuQ,88
81
- codemie_sdk_python-0.1.698.dist-info/RECORD,,
79
+ codemie_sdk_python-0.1.699.dist-info/METADATA,sha256=TN0wXA-aqcBq4G_4gFBll6v8nEoNPdOmzpSYvyPtYtc,47938
80
+ codemie_sdk_python-0.1.699.dist-info/WHEEL,sha256=L-WvLdSBvJWHXv5zrQxDvNRnIgoBzLUpcbuiw19KCuQ,88
81
+ codemie_sdk_python-0.1.699.dist-info/RECORD,,