xpander-sdk 1.60.8__py3-none-any.whl → 2.0.155__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.
- xpander_sdk/__init__.py +76 -7793
- xpander_sdk/consts/__init__.py +0 -0
- xpander_sdk/consts/api_routes.py +63 -0
- xpander_sdk/core/__init__.py +0 -0
- xpander_sdk/core/module_base.py +164 -0
- xpander_sdk/core/state.py +10 -0
- xpander_sdk/core/xpander_api_client.py +119 -0
- xpander_sdk/exceptions/__init__.py +0 -0
- xpander_sdk/exceptions/module_exception.py +45 -0
- xpander_sdk/models/__init__.py +0 -0
- xpander_sdk/models/activity.py +65 -0
- xpander_sdk/models/configuration.py +92 -0
- xpander_sdk/models/events.py +70 -0
- xpander_sdk/models/frameworks.py +64 -0
- xpander_sdk/models/shared.py +102 -0
- xpander_sdk/models/user.py +21 -0
- xpander_sdk/modules/__init__.py +0 -0
- xpander_sdk/modules/agents/__init__.py +0 -0
- xpander_sdk/modules/agents/agents_module.py +164 -0
- xpander_sdk/modules/agents/models/__init__.py +0 -0
- xpander_sdk/modules/agents/models/agent.py +477 -0
- xpander_sdk/modules/agents/models/agent_list.py +107 -0
- xpander_sdk/modules/agents/models/knowledge_bases.py +33 -0
- xpander_sdk/modules/agents/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/agents/sub_modules/agent.py +953 -0
- xpander_sdk/modules/agents/utils/__init__.py +0 -0
- xpander_sdk/modules/agents/utils/generic.py +2 -0
- xpander_sdk/modules/backend/__init__.py +0 -0
- xpander_sdk/modules/backend/backend_module.py +425 -0
- xpander_sdk/modules/backend/frameworks/__init__.py +0 -0
- xpander_sdk/modules/backend/frameworks/agno.py +627 -0
- xpander_sdk/modules/backend/frameworks/dispatch.py +36 -0
- xpander_sdk/modules/backend/utils/__init__.py +0 -0
- xpander_sdk/modules/backend/utils/mcp_oauth.py +95 -0
- xpander_sdk/modules/events/__init__.py +0 -0
- xpander_sdk/modules/events/decorators/__init__.py +0 -0
- xpander_sdk/modules/events/decorators/on_boot.py +94 -0
- xpander_sdk/modules/events/decorators/on_shutdown.py +94 -0
- xpander_sdk/modules/events/decorators/on_task.py +203 -0
- xpander_sdk/modules/events/events_module.py +629 -0
- xpander_sdk/modules/events/models/__init__.py +0 -0
- xpander_sdk/modules/events/models/deployments.py +25 -0
- xpander_sdk/modules/events/models/events.py +57 -0
- xpander_sdk/modules/events/utils/__init__.py +0 -0
- xpander_sdk/modules/events/utils/generic.py +56 -0
- xpander_sdk/modules/events/utils/git_init.py +32 -0
- xpander_sdk/modules/knowledge_bases/__init__.py +0 -0
- xpander_sdk/modules/knowledge_bases/knowledge_bases_module.py +217 -0
- xpander_sdk/modules/knowledge_bases/models/__init__.py +0 -0
- xpander_sdk/modules/knowledge_bases/models/knowledge_bases.py +11 -0
- xpander_sdk/modules/knowledge_bases/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base.py +107 -0
- xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base_document_item.py +40 -0
- xpander_sdk/modules/knowledge_bases/utils/__init__.py +0 -0
- xpander_sdk/modules/tasks/__init__.py +0 -0
- xpander_sdk/modules/tasks/models/__init__.py +0 -0
- xpander_sdk/modules/tasks/models/task.py +153 -0
- xpander_sdk/modules/tasks/models/tasks_list.py +107 -0
- xpander_sdk/modules/tasks/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/tasks/sub_modules/task.py +887 -0
- xpander_sdk/modules/tasks/tasks_module.py +492 -0
- xpander_sdk/modules/tasks/utils/__init__.py +0 -0
- xpander_sdk/modules/tasks/utils/files.py +114 -0
- xpander_sdk/modules/tools_repository/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/decorators/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/decorators/register_tool.py +108 -0
- xpander_sdk/modules/tools_repository/models/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/models/mcp.py +68 -0
- xpander_sdk/modules/tools_repository/models/tool_invocation_result.py +14 -0
- xpander_sdk/modules/tools_repository/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/sub_modules/tool.py +578 -0
- xpander_sdk/modules/tools_repository/tools_repository_module.py +259 -0
- xpander_sdk/modules/tools_repository/utils/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/utils/generic.py +57 -0
- xpander_sdk/modules/tools_repository/utils/local_tools.py +52 -0
- xpander_sdk/modules/tools_repository/utils/schemas.py +308 -0
- xpander_sdk/utils/__init__.py +0 -0
- xpander_sdk/utils/env.py +44 -0
- xpander_sdk/utils/event_loop.py +67 -0
- xpander_sdk/utils/tools.py +32 -0
- xpander_sdk-2.0.155.dist-info/METADATA +538 -0
- xpander_sdk-2.0.155.dist-info/RECORD +85 -0
- {xpander_sdk-1.60.8.dist-info → xpander_sdk-2.0.155.dist-info}/WHEEL +1 -1
- {xpander_sdk-1.60.8.dist-info → xpander_sdk-2.0.155.dist-info/licenses}/LICENSE +0 -1
- xpander_sdk/_jsii/__init__.py +0 -39
- xpander_sdk/_jsii/xpander-sdk@1.60.8.jsii.tgz +0 -0
- xpander_sdk/py.typed +0 -1
- xpander_sdk-1.60.8.dist-info/METADATA +0 -368
- xpander_sdk-1.60.8.dist-info/RECORD +0 -9
- {xpander_sdk-1.60.8.dist-info → xpander_sdk-2.0.155.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Dict, Optional
|
|
5
|
+
from pydantic import BaseModel, Field, ConfigDict
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
from xpander_sdk.modules.tasks.sub_modules.task import Task
|
|
9
|
+
from .deployments import DeployedAsset
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EventType(str, Enum):
|
|
13
|
+
WorkerRegistration = "worker-registration"
|
|
14
|
+
AgentExecution = "agent-execution"
|
|
15
|
+
WorkerHeartbeat = "worker-heartbeat"
|
|
16
|
+
WorkerFinished = "worker-finished"
|
|
17
|
+
EnvironmentConflict = "worker-environment-conflict"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EventMessageBase(BaseModel):
|
|
21
|
+
id: str = Field(default_factory=lambda: str(uuid4()))
|
|
22
|
+
event: EventType
|
|
23
|
+
data: Optional[Dict] = None
|
|
24
|
+
|
|
25
|
+
def model_dump_safe(self, **kwargs) -> dict:
|
|
26
|
+
return json.loads(self.model_dump_json(**kwargs))
|
|
27
|
+
|
|
28
|
+
model_config = ConfigDict(
|
|
29
|
+
use_enum_values=True,
|
|
30
|
+
ser_json_timedelta='iso8601',
|
|
31
|
+
ser_json_bytes='utf8'
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class WorkerRegistrationEvent(EventMessageBase):
|
|
36
|
+
event: EventType = EventType.WorkerRegistration
|
|
37
|
+
data: DeployedAsset
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class WorkerFinishedEvent(EventMessageBase):
|
|
41
|
+
event: EventType = EventType.WorkerFinished
|
|
42
|
+
data: Optional[dict] = {}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class WorkerHeartbeat(EventMessageBase):
|
|
46
|
+
event: EventType = EventType.WorkerHeartbeat
|
|
47
|
+
data: datetime = Field(default_factory=datetime.now)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WorkerExecutionRequest(EventMessageBase):
|
|
51
|
+
event: EventType = EventType.AgentExecution
|
|
52
|
+
data: Task
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class WorkerEnvironmentConflict(EventMessageBase):
|
|
56
|
+
event: EventType = EventType.EnvironmentConflict
|
|
57
|
+
error: str
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from xpander_sdk.models.configuration import Configuration
|
|
2
|
+
|
|
3
|
+
EVENT_STREAMING_ENDPOINT = "{base}/{organization_id}/events"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def backoff_delay(attempt: int) -> int:
|
|
7
|
+
"""1 s after first failure, 2 s after second, 3 s for attempts ≥ 3."""
|
|
8
|
+
return 1 if attempt == 1 else 2 if attempt == 2 else 3
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def is_not_inbound(configuration: Configuration) -> bool:
|
|
12
|
+
"""
|
|
13
|
+
Determine if the current execution context is not the inbound environment.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
bool: True if the base_url is not identified as an inbound service.
|
|
17
|
+
"""
|
|
18
|
+
return (
|
|
19
|
+
"inbound.xpander" not in configuration.base_url
|
|
20
|
+
and "inbound.stg.xpander" not in configuration.base_url
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_events_base(configuration: Configuration) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Construct the base URL used for event streaming endpoints.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
str: The base URL for event streaming based on configuration and environment.
|
|
30
|
+
"""
|
|
31
|
+
if is_not_inbound(configuration=configuration):
|
|
32
|
+
return EVENT_STREAMING_ENDPOINT.format(
|
|
33
|
+
base=(
|
|
34
|
+
"http://localhost:9016"
|
|
35
|
+
if "8085" in configuration.base_url
|
|
36
|
+
else configuration.base_url
|
|
37
|
+
),
|
|
38
|
+
organization_id=configuration.organization_id,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
is_stg = "stg.xpander" in configuration.base_url
|
|
42
|
+
base = f"https://agent-controller{'.stg' if is_stg else ''}.xpander.ai"
|
|
43
|
+
|
|
44
|
+
return EVENT_STREAMING_ENDPOINT.format(
|
|
45
|
+
base=base, organization_id=configuration.organization_id
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_events_headers(configuration: Configuration) -> dict[str, str]:
|
|
50
|
+
"""
|
|
51
|
+
Construct the headers required for requests, including authentication.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
dict[str, str]: HTTP headers including the API key for authorization.
|
|
55
|
+
"""
|
|
56
|
+
return {"x-api-key": configuration.api_key}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
from loguru import logger
|
|
5
|
+
|
|
6
|
+
def configure_git_credentials():
|
|
7
|
+
try:
|
|
8
|
+
# Read from environment variables
|
|
9
|
+
git_user = getenv("GIT_USERNAME", None)
|
|
10
|
+
git_token = getenv("GIT_TOKEN", None)
|
|
11
|
+
git_name = getenv("GIT_NAME", "xpander.ai")
|
|
12
|
+
git_email = getenv("GIT_EMAIL", "agent@xpander.ai")
|
|
13
|
+
|
|
14
|
+
if not git_user or not git_token:
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
logger.info(f"Setting up GIT for user {git_user}")
|
|
18
|
+
# Set Git global config
|
|
19
|
+
subprocess.run(["git", "config", "--global", "user.name", git_name], check=True)
|
|
20
|
+
subprocess.run(["git", "config", "--global", "user.email", git_email], check=True)
|
|
21
|
+
subprocess.run(["git", "config", "--global", "credential.helper", "store"], check=True)
|
|
22
|
+
|
|
23
|
+
# Write credentials to ~/.git-credentials
|
|
24
|
+
cred_line = f"https://{git_user}:{git_token}@github.com\n"
|
|
25
|
+
git_credentials_path = os.path.expanduser("~/.git-credentials")
|
|
26
|
+
with open(git_credentials_path, "w") as cred_file:
|
|
27
|
+
cred_file.write(cred_line)
|
|
28
|
+
|
|
29
|
+
logger.info("✅ Git configured with PAT")
|
|
30
|
+
except Exception as e:
|
|
31
|
+
logger.warning(f"Failed to configure git {str(e)}")
|
|
32
|
+
|
|
File without changes
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Knowledge Bases module for managing knowledge repositories in the xpander.ai platform.
|
|
3
|
+
|
|
4
|
+
This module provides functionality to create, list, and retrieve knowledge bases
|
|
5
|
+
within the xpander.ai Backend-as-a-Service platform.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
from httpx import HTTPStatusError
|
|
11
|
+
|
|
12
|
+
from xpander_sdk.consts.api_routes import APIRoute
|
|
13
|
+
from xpander_sdk.core.module_base import ModuleBase
|
|
14
|
+
from xpander_sdk.core.xpander_api_client import APIClient
|
|
15
|
+
from xpander_sdk.exceptions.module_exception import ModuleException
|
|
16
|
+
from xpander_sdk.models.configuration import Configuration
|
|
17
|
+
from xpander_sdk.modules.knowledge_bases.sub_modules.knowledge_base import KnowledgeBase
|
|
18
|
+
from xpander_sdk.utils.event_loop import run_sync
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class KnowledgeBases(ModuleBase):
|
|
22
|
+
"""
|
|
23
|
+
Main module for managing knowledge bases in xpander.ai.
|
|
24
|
+
|
|
25
|
+
This class provides methods for listing, creating, and retrieving knowledge
|
|
26
|
+
bases associated with AI agents in the xpander.ai platform. Both asynchronous
|
|
27
|
+
and synchronous versions are offered to accommodate different integration needs.
|
|
28
|
+
|
|
29
|
+
The module follows the singleton pattern inherited from ModuleBase, ensuring
|
|
30
|
+
consistent configuration across all operations.
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
34
|
+
>>> kb_list = knowledge_bases.list()
|
|
35
|
+
>>> specific_kb = knowledge_bases.get(knowledge_base_id="kb123")
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, configuration: Optional[Configuration] = None):
|
|
39
|
+
"""
|
|
40
|
+
Initialize the KnowledgeBases module.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
configuration (Optional[Configuration]): SDK configuration. If None,
|
|
44
|
+
will use default configuration from environment variables.
|
|
45
|
+
"""
|
|
46
|
+
super().__init__(configuration)
|
|
47
|
+
|
|
48
|
+
async def alist(self) -> List[KnowledgeBase]:
|
|
49
|
+
"""
|
|
50
|
+
Asynchronously list all available knowledge bases.
|
|
51
|
+
|
|
52
|
+
Retrieves a list of all knowledge bases accessible to the current
|
|
53
|
+
user/organization, providing essential information for exploration and management.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
List[KnowledgeBase]: List of knowledge base summary objects.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ModuleException: If the API request fails or returns an error.
|
|
60
|
+
|
|
61
|
+
Example:
|
|
62
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
63
|
+
>>> kb_list = await knowledge_bases.alist()
|
|
64
|
+
>>> for kb in kb_list:
|
|
65
|
+
... print(f"Knowledge Base: {kb.name} (ID: {kb.id})")
|
|
66
|
+
"""
|
|
67
|
+
try:
|
|
68
|
+
client = APIClient(configuration=self.configuration)
|
|
69
|
+
kbs = await client.make_request(path=APIRoute.ListKnowledgeBases)
|
|
70
|
+
return [KnowledgeBase(**kb, configuration=self.configuration) for kb in kbs]
|
|
71
|
+
except Exception as e:
|
|
72
|
+
if isinstance(e, HTTPStatusError):
|
|
73
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
74
|
+
raise ModuleException(500, f"Failed to list knowledge bases - {str(e)}")
|
|
75
|
+
|
|
76
|
+
def list(self) -> List[KnowledgeBase]:
|
|
77
|
+
"""
|
|
78
|
+
Synchronously list all available knowledge bases.
|
|
79
|
+
|
|
80
|
+
This is the synchronous version of alist(). It internally calls the
|
|
81
|
+
asynchronous method and waits for completion.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
List[KnowledgeBase]: List of knowledge base summary objects.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
ModuleException: If the API request fails or returns an error.
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
91
|
+
>>> kb_list = knowledge_bases.list()
|
|
92
|
+
>>> print(f"Found {len(kb_list)} knowledge bases")
|
|
93
|
+
"""
|
|
94
|
+
return run_sync(self.alist())
|
|
95
|
+
|
|
96
|
+
async def aget(self, knowledge_base_id: str) -> KnowledgeBase:
|
|
97
|
+
"""
|
|
98
|
+
Asynchronously retrieve a specific knowledge base by ID.
|
|
99
|
+
|
|
100
|
+
Loads and returns a full KnowledgeBase object with detailed configuration
|
|
101
|
+
and capabilities using the provided knowledge base ID.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
knowledge_base_id (str): Unique identifier of the knowledge base to retrieve.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
KnowledgeBase: Complete knowledge base object.
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
ModuleException: If the knowledge base is not found or access is denied.
|
|
111
|
+
|
|
112
|
+
Example:
|
|
113
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
114
|
+
>>> kb = await knowledge_bases.aget(knowledge_base_id="kb123")
|
|
115
|
+
>>> print(f"Loaded knowledge base: {kb.name}")
|
|
116
|
+
"""
|
|
117
|
+
try:
|
|
118
|
+
client = APIClient(configuration=self.configuration)
|
|
119
|
+
kb = await client.make_request(
|
|
120
|
+
path=APIRoute.GetKnowledgeBaseDetails.format(knowledge_base_id=knowledge_base_id)
|
|
121
|
+
)
|
|
122
|
+
return KnowledgeBase(**kb, configuration=self.configuration)
|
|
123
|
+
except Exception as e:
|
|
124
|
+
if isinstance(e, HTTPStatusError):
|
|
125
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
126
|
+
raise ModuleException(500, f"Failed to get knowledge base - {str(e)}")
|
|
127
|
+
|
|
128
|
+
def get(self, knowledge_base_id: str) -> KnowledgeBase:
|
|
129
|
+
"""
|
|
130
|
+
Synchronously retrieve a specific knowledge base by ID.
|
|
131
|
+
|
|
132
|
+
This is the synchronous version of aget(). It internally calls the
|
|
133
|
+
asynchronous method and waits for completion.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
knowledge_base_id (str): Unique identifier of the knowledge base to retrieve.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
KnowledgeBase: Complete knowledge base object.
|
|
140
|
+
|
|
141
|
+
Raises:
|
|
142
|
+
ModuleException: If the knowledge base is not found or access is denied.
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
146
|
+
>>> kb = knowledge_bases.get(knowledge_base_id="kb123")
|
|
147
|
+
>>> details = kb.details()
|
|
148
|
+
"""
|
|
149
|
+
return run_sync(self.aget(knowledge_base_id))
|
|
150
|
+
|
|
151
|
+
async def acreate(self, name: str, description: Optional[str] = "") -> KnowledgeBase:
|
|
152
|
+
"""
|
|
153
|
+
Asynchronously create a new knowledge base.
|
|
154
|
+
|
|
155
|
+
Creates a new knowledge base in the xpander.ai platform with the specified
|
|
156
|
+
name and description.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
name (str): The name of the new knowledge base.
|
|
160
|
+
description (Optional[str]): A brief description of the knowledge base.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
KnowledgeBase: Newly created knowledge base object.
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
ModuleException: If knowledge base creation fails due to API problems or configuration errors.
|
|
167
|
+
|
|
168
|
+
Example:
|
|
169
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
170
|
+
>>> new_kb = await knowledge_bases.acreate(
|
|
171
|
+
... name="New Knowledge Base",
|
|
172
|
+
... description="A demo knowledge base for testing"
|
|
173
|
+
... )
|
|
174
|
+
>>> print(f"Created knowledge base: {new_kb.id}")
|
|
175
|
+
"""
|
|
176
|
+
try:
|
|
177
|
+
client = APIClient(configuration=self.configuration)
|
|
178
|
+
created_kb = await client.make_request(
|
|
179
|
+
path=APIRoute.CreateKnowledgeBase,
|
|
180
|
+
method="POST",
|
|
181
|
+
payload={
|
|
182
|
+
"name": name,
|
|
183
|
+
"description": description,
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
return KnowledgeBase(**created_kb, configuration=self.configuration)
|
|
187
|
+
except Exception as e:
|
|
188
|
+
if isinstance(e, HTTPStatusError):
|
|
189
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
190
|
+
raise ModuleException(500, f"Failed to create knowledge base - {str(e)}")
|
|
191
|
+
|
|
192
|
+
def create(self, name: str, description: Optional[str] = "") -> KnowledgeBase:
|
|
193
|
+
"""
|
|
194
|
+
Synchronously create a new knowledge base.
|
|
195
|
+
|
|
196
|
+
This is the synchronous version of acreate(). It internally calls the
|
|
197
|
+
asynchronous method and waits for completion.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
name (str): The name of the new knowledge base.
|
|
201
|
+
description (Optional[str]): A brief description of the knowledge base.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
KnowledgeBase: Newly created knowledge base object.
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
ModuleException: If knowledge base creation fails due to API problems or configuration errors.
|
|
208
|
+
|
|
209
|
+
Example:
|
|
210
|
+
>>> knowledge_bases = KnowledgeBases()
|
|
211
|
+
>>> new_kb = knowledge_bases.create(
|
|
212
|
+
... name="New Knowledge Base",
|
|
213
|
+
... description="A demo knowledge base for testing"
|
|
214
|
+
... )
|
|
215
|
+
>>> print(f"Created knowledge base: {new_kb.id}")
|
|
216
|
+
"""
|
|
217
|
+
return run_sync(self.acreate(name=name, description=description))
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
from httpx import HTTPStatusError
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from xpander_sdk.consts.api_routes import APIRoute
|
|
7
|
+
from xpander_sdk.core.xpander_api_client import APIClient
|
|
8
|
+
from xpander_sdk.exceptions.module_exception import ModuleException
|
|
9
|
+
from xpander_sdk.models.configuration import Configuration
|
|
10
|
+
from xpander_sdk.modules.knowledge_bases.models.knowledge_bases import KnowledgeBaseSearchResult, KnowledgeBaseType
|
|
11
|
+
from xpander_sdk.modules.knowledge_bases.sub_modules.knowledge_base_document_item import KnowledgeBaseDocumentItem
|
|
12
|
+
from xpander_sdk.utils.event_loop import run_sync
|
|
13
|
+
|
|
14
|
+
class KnowledgeBase(BaseModel):
|
|
15
|
+
configuration: Optional[Configuration] = None
|
|
16
|
+
id: str = Field(...)
|
|
17
|
+
name: str = Field(...)
|
|
18
|
+
description: Optional[str] = Field(default=None)
|
|
19
|
+
type: KnowledgeBaseType = Field(...)
|
|
20
|
+
organization_id: str = Field(...)
|
|
21
|
+
total_documents: int = Field(default=0)
|
|
22
|
+
|
|
23
|
+
async def adelete(self):
|
|
24
|
+
try:
|
|
25
|
+
client = APIClient(configuration=self.configuration)
|
|
26
|
+
await client.make_request(
|
|
27
|
+
path=APIRoute.DeleteKnowledgeBase.format(knowledge_base_id=self.id),
|
|
28
|
+
method="DELETE",
|
|
29
|
+
)
|
|
30
|
+
except Exception as e:
|
|
31
|
+
if isinstance(e, HTTPStatusError):
|
|
32
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
33
|
+
raise ModuleException(500, f"Failed to delete knowledge base - {str(e)}")
|
|
34
|
+
|
|
35
|
+
def delete(self):
|
|
36
|
+
return run_sync(self.adelete())
|
|
37
|
+
|
|
38
|
+
async def alist_documents(self) -> List[KnowledgeBaseDocumentItem]:
|
|
39
|
+
try:
|
|
40
|
+
client = APIClient(configuration=self.configuration)
|
|
41
|
+
docs = await client.make_request(
|
|
42
|
+
path=APIRoute.ListKnowledgeBaseDocuments.format(knowledge_base_id=self.id),
|
|
43
|
+
method="GET",
|
|
44
|
+
)
|
|
45
|
+
return [KnowledgeBaseDocumentItem(**doc) for doc in docs]
|
|
46
|
+
except Exception as e:
|
|
47
|
+
if isinstance(e, HTTPStatusError):
|
|
48
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
49
|
+
raise ModuleException(500, f"Failed to list knowledge documents - {str(e)}")
|
|
50
|
+
|
|
51
|
+
def list_documents(self) -> List[KnowledgeBaseDocumentItem]:
|
|
52
|
+
return run_sync(self.alist_documents())
|
|
53
|
+
|
|
54
|
+
async def adelete_multiple_documents(self, document_ids: List[str]):
|
|
55
|
+
try:
|
|
56
|
+
client = APIClient(configuration=self.configuration)
|
|
57
|
+
await client.make_request(
|
|
58
|
+
path=APIRoute.KnowledgeBaseDocumentsCrud.format(knowledge_base_id=self.id),
|
|
59
|
+
payload=document_ids,
|
|
60
|
+
method="DELETE",
|
|
61
|
+
)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
if isinstance(e, HTTPStatusError):
|
|
64
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
65
|
+
raise ModuleException(500, f"Failed to delete multiple knowledge base documents - {str(e)}")
|
|
66
|
+
|
|
67
|
+
def delete_multiple_documents(self, document_ids: List[str]):
|
|
68
|
+
return run_sync(self.adelete_multiple_documents(document_ids))
|
|
69
|
+
|
|
70
|
+
async def aadd_documents(self, document_urls: List[str], sync: Optional[bool] = False) -> List[KnowledgeBaseDocumentItem]:
|
|
71
|
+
try:
|
|
72
|
+
client = APIClient(configuration=self.configuration)
|
|
73
|
+
created_docs = await client.make_request(
|
|
74
|
+
path=APIRoute.KnowledgeBaseDocumentsCrud.format(knowledge_base_id=self.id),
|
|
75
|
+
payload=[{"document_url": doc_url, "sync": sync} for doc_url in document_urls],
|
|
76
|
+
method="POST",
|
|
77
|
+
)
|
|
78
|
+
return [KnowledgeBaseDocumentItem(**doc) for doc in created_docs]
|
|
79
|
+
except Exception as e:
|
|
80
|
+
if isinstance(e, HTTPStatusError):
|
|
81
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
82
|
+
raise ModuleException(500, f"Failed to add knowledge base documents - {str(e)}")
|
|
83
|
+
|
|
84
|
+
def add_documents(self, document_urls: List[str], sync: Optional[bool] = False) -> List[KnowledgeBaseDocumentItem]:
|
|
85
|
+
return run_sync(self.aadd_documents(document_urls, sync))
|
|
86
|
+
|
|
87
|
+
async def asearch(self, search_query: str, use_bubble: Optional[bool] = False, bubble_size: Optional[int] = 1000, top_k: Optional[int] = 10) -> List[KnowledgeBaseSearchResult]:
|
|
88
|
+
try:
|
|
89
|
+
client = APIClient(configuration=self.configuration)
|
|
90
|
+
search_results = await client.make_request(
|
|
91
|
+
path=APIRoute.KnowledgeBaseDocumentsCrud.format(knowledge_base_id=self.id),
|
|
92
|
+
query={
|
|
93
|
+
"search_query": search_query,
|
|
94
|
+
"use_bubble": "true" if use_bubble else "false",
|
|
95
|
+
"bubble_size": bubble_size,
|
|
96
|
+
"top_k": top_k,
|
|
97
|
+
},
|
|
98
|
+
method="GET",
|
|
99
|
+
)
|
|
100
|
+
return [KnowledgeBaseSearchResult(**res) for res in search_results]
|
|
101
|
+
except Exception as e:
|
|
102
|
+
if isinstance(e, HTTPStatusError):
|
|
103
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
104
|
+
raise ModuleException(500, f"Failed to search in knowledge base - {str(e)}")
|
|
105
|
+
|
|
106
|
+
def search(self, search_query: str, use_bubble: Optional[bool] = False, bubble_size: Optional[int] = 1000, top_k: Optional[int] = 10) -> List[KnowledgeBaseSearchResult]:
|
|
107
|
+
return run_sync(self.asearch(search_query, use_bubble, bubble_size, top_k))
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from httpx import HTTPStatusError
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from xpander_sdk.consts.api_routes import APIRoute
|
|
7
|
+
from xpander_sdk.core.xpander_api_client import APIClient
|
|
8
|
+
from xpander_sdk.exceptions.module_exception import ModuleException
|
|
9
|
+
from xpander_sdk.models.configuration import Configuration
|
|
10
|
+
from xpander_sdk.modules.knowledge_bases.models.knowledge_bases import KnowledgeBaseType
|
|
11
|
+
|
|
12
|
+
class KnowledgeBaseDocumentItem(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Represents a document item within a Knowledge Base.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
kb_id (Optional[str]): KB identifier.
|
|
18
|
+
id (str): Document unique identifier.
|
|
19
|
+
document_url (str): URL of the document.
|
|
20
|
+
raw_data (Optional[str]): Raw textual data of the document.
|
|
21
|
+
local_env (Optional[bool]): Indicates if the document is in a local environment. Defaults to False.
|
|
22
|
+
"""
|
|
23
|
+
configuration: Optional[Configuration] = None
|
|
24
|
+
kb_id: Optional[str] = Field(description="KB identifier", default=None)
|
|
25
|
+
id: Optional[str] = Field(default=None, description="Document unique identifier")
|
|
26
|
+
document_url: str = Field(..., description="Document URL")
|
|
27
|
+
raw_data: Optional[str] = Field(description="Raw data (textual)", default=None)
|
|
28
|
+
|
|
29
|
+
async def delete(self):
|
|
30
|
+
try:
|
|
31
|
+
client = APIClient(configuration=self.configuration)
|
|
32
|
+
await client.make_request(
|
|
33
|
+
path=APIRoute.KnowledgeBaseDocumentsCrud.format(knowledge_base_id=self.kb_id),
|
|
34
|
+
payload=[self.id],
|
|
35
|
+
method="DELETE",
|
|
36
|
+
)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
if isinstance(e, HTTPStatusError):
|
|
39
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
40
|
+
raise ModuleException(500, f"Failed to delete knowledge base document - {str(e)}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|