llama-deploy-appserver 0.3.27__py3-none-any.whl → 0.4.0__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.
- llama_deploy/appserver/workflow_store/agent_data_store.py +132 -40
- {llama_deploy_appserver-0.3.27.dist-info → llama_deploy_appserver-0.4.0.dist-info}/METADATA +2 -3
- {llama_deploy_appserver-0.3.27.dist-info → llama_deploy_appserver-0.4.0.dist-info}/RECORD +4 -4
- {llama_deploy_appserver-0.3.27.dist-info → llama_deploy_appserver-0.4.0.dist-info}/WHEEL +0 -0
|
@@ -2,10 +2,9 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
|
-
from typing import Any, List
|
|
5
|
+
from typing import Any, List
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
from llama_cloud_services.beta.agent_data import AsyncAgentDataClient
|
|
7
|
+
import httpx
|
|
9
8
|
from llama_deploy.appserver.settings import ApiserverSettings
|
|
10
9
|
from llama_deploy.core.client.ssl_util import get_httpx_verify_param
|
|
11
10
|
from llama_deploy.core.deployment_config import DeploymentConfig
|
|
@@ -21,8 +20,12 @@ else:
|
|
|
21
20
|
|
|
22
21
|
logger = logging.getLogger(__name__)
|
|
23
22
|
|
|
23
|
+
DEFAULT_BASE_URL = "https://api.cloud.llamaindex.ai"
|
|
24
|
+
|
|
24
25
|
|
|
25
26
|
class AgentDataStore(AbstractWorkflowStore):
|
|
27
|
+
"""Workflow store backed by LlamaCloud Agent Data API using raw httpx."""
|
|
28
|
+
|
|
26
29
|
def __init__(
|
|
27
30
|
self, settings: DeploymentConfig, server_settings: ApiserverSettings
|
|
28
31
|
) -> None:
|
|
@@ -37,71 +40,149 @@ class AgentDataStore(AbstractWorkflowStore):
|
|
|
37
40
|
agent_url_id = settings.name
|
|
38
41
|
|
|
39
42
|
self.settings = settings
|
|
40
|
-
|
|
41
|
-
self.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
token=os.getenv("LLAMA_CLOUD_API_KEY"),
|
|
48
|
-
httpx_client=httpx.AsyncClient(
|
|
49
|
-
headers={"Project-Id": project_id} if project_id else None,
|
|
50
|
-
verify=get_httpx_verify_param(),
|
|
51
|
-
),
|
|
52
|
-
),
|
|
53
|
-
)
|
|
43
|
+
self.collection = collection
|
|
44
|
+
self.deployment_name = agent_url_id
|
|
45
|
+
|
|
46
|
+
self.base_url = os.getenv("LLAMA_CLOUD_BASE_URL", DEFAULT_BASE_URL).rstrip("/")
|
|
47
|
+
self.api_key = os.getenv("LLAMA_CLOUD_API_KEY")
|
|
48
|
+
self.project_id = os.getenv("LLAMA_DEPLOY_PROJECT_ID")
|
|
49
|
+
|
|
54
50
|
self.lock = AsyncKeyedLock()
|
|
55
51
|
# workflow id -> agent data id
|
|
56
52
|
self.cache = LRUCache[str, str](maxsize=1024)
|
|
57
53
|
|
|
54
|
+
def _get_headers(self) -> dict[str, str]:
|
|
55
|
+
"""Build HTTP headers for API requests."""
|
|
56
|
+
headers = {
|
|
57
|
+
"Content-Type": "application/json",
|
|
58
|
+
}
|
|
59
|
+
if self.api_key:
|
|
60
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
61
|
+
if self.project_id:
|
|
62
|
+
headers["Project-Id"] = self.project_id
|
|
63
|
+
return headers
|
|
64
|
+
|
|
65
|
+
def _get_client(self) -> httpx.AsyncClient:
|
|
66
|
+
"""Create a new httpx client."""
|
|
67
|
+
return httpx.AsyncClient(
|
|
68
|
+
headers=self._get_headers(),
|
|
69
|
+
verify=get_httpx_verify_param(),
|
|
70
|
+
)
|
|
71
|
+
|
|
58
72
|
@override
|
|
59
73
|
async def query(self, query: HandlerQuery) -> List[PersistentHandler]:
|
|
60
74
|
filters = self._build_filters(query)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
search_request = {
|
|
76
|
+
"deployment_name": self.deployment_name,
|
|
77
|
+
"collection": self.collection,
|
|
78
|
+
"filter": filters,
|
|
79
|
+
"page_size": 1000,
|
|
80
|
+
}
|
|
81
|
+
async with self._get_client() as client:
|
|
82
|
+
response = await client.post(
|
|
83
|
+
f"{self.base_url}/api/v1/beta/agent-data/:search",
|
|
84
|
+
json=search_request,
|
|
85
|
+
)
|
|
86
|
+
response.raise_for_status()
|
|
87
|
+
data = response.json()
|
|
88
|
+
|
|
89
|
+
items = data.get("items", [])
|
|
90
|
+
return [PersistentHandler(**item["data"]) for item in items]
|
|
66
91
|
|
|
67
92
|
@override
|
|
68
93
|
async def update(self, handler: PersistentHandler) -> None:
|
|
69
94
|
async with self.lock.acquire(handler.handler_id):
|
|
70
95
|
id = await self._get_item_id(handler)
|
|
71
96
|
if id is None:
|
|
72
|
-
item = await self.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if item.id is None:
|
|
97
|
+
item = await self._create_item(handler)
|
|
98
|
+
item_id = item.get("id")
|
|
99
|
+
if item_id is None:
|
|
76
100
|
raise ValueError(f"Failed to create handler {handler.handler_id}")
|
|
77
|
-
self.cache.set(handler.handler_id,
|
|
101
|
+
self.cache.set(handler.handler_id, item_id)
|
|
78
102
|
else:
|
|
79
|
-
await self.
|
|
80
|
-
item_id=id,
|
|
81
|
-
data=handler,
|
|
82
|
-
)
|
|
103
|
+
await self._update_item(id, handler)
|
|
83
104
|
|
|
84
105
|
@override
|
|
85
106
|
async def delete(self, query: HandlerQuery) -> int:
|
|
86
107
|
filters = self._build_filters(query)
|
|
87
|
-
|
|
108
|
+
search_request = {
|
|
109
|
+
"deployment_name": self.deployment_name,
|
|
110
|
+
"collection": self.collection,
|
|
111
|
+
"filter": filters,
|
|
112
|
+
"page_size": 1000,
|
|
113
|
+
}
|
|
114
|
+
async with self._get_client() as client:
|
|
115
|
+
response = await client.post(
|
|
116
|
+
f"{self.base_url}/api/v1/beta/agent-data/:search",
|
|
117
|
+
json=search_request,
|
|
118
|
+
)
|
|
119
|
+
response.raise_for_status()
|
|
120
|
+
data = response.json()
|
|
121
|
+
|
|
122
|
+
items = data.get("items", [])
|
|
88
123
|
await asyncio.gather(
|
|
89
|
-
*[self.
|
|
124
|
+
*[self._delete_item(item["id"]) for item in items if item.get("id")]
|
|
90
125
|
)
|
|
91
|
-
return len(
|
|
126
|
+
return len(items)
|
|
127
|
+
|
|
128
|
+
async def _create_item(self, handler: PersistentHandler) -> dict[str, Any]:
|
|
129
|
+
"""Create a new agent data item."""
|
|
130
|
+
create_request = {
|
|
131
|
+
"deployment_name": self.deployment_name,
|
|
132
|
+
"collection": self.collection,
|
|
133
|
+
"data": handler.model_dump(mode="json"),
|
|
134
|
+
}
|
|
135
|
+
async with self._get_client() as client:
|
|
136
|
+
response = await client.post(
|
|
137
|
+
f"{self.base_url}/api/v1/beta/agent-data",
|
|
138
|
+
json=create_request,
|
|
139
|
+
)
|
|
140
|
+
response.raise_for_status()
|
|
141
|
+
return response.json()
|
|
142
|
+
|
|
143
|
+
async def _update_item(self, item_id: str, handler: PersistentHandler) -> None:
|
|
144
|
+
"""Update an existing agent data item."""
|
|
145
|
+
update_request = {
|
|
146
|
+
"data": handler.model_dump(mode="json"),
|
|
147
|
+
}
|
|
148
|
+
async with self._get_client() as client:
|
|
149
|
+
response = await client.put(
|
|
150
|
+
f"{self.base_url}/api/v1/beta/agent-data/{item_id}",
|
|
151
|
+
json=update_request,
|
|
152
|
+
)
|
|
153
|
+
response.raise_for_status()
|
|
154
|
+
|
|
155
|
+
async def _delete_item(self, item_id: str) -> None:
|
|
156
|
+
"""Delete an agent data item."""
|
|
157
|
+
async with self._get_client() as client:
|
|
158
|
+
response = await client.delete(
|
|
159
|
+
f"{self.base_url}/api/v1/beta/agent-data/{item_id}",
|
|
160
|
+
)
|
|
161
|
+
response.raise_for_status()
|
|
92
162
|
|
|
93
163
|
async def _get_item_id(self, handler: PersistentHandler) -> str | None:
|
|
94
164
|
cached_id = self.cache.get(handler.handler_id)
|
|
95
165
|
if cached_id is not None:
|
|
96
166
|
return cached_id
|
|
97
167
|
search_filter = {"handler_id": {"eq": handler.handler_id}}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
168
|
+
search_request = {
|
|
169
|
+
"deployment_name": self.deployment_name,
|
|
170
|
+
"collection": self.collection,
|
|
171
|
+
"filter": search_filter,
|
|
172
|
+
"page_size": 1,
|
|
173
|
+
}
|
|
174
|
+
async with self._get_client() as client:
|
|
175
|
+
response = await client.post(
|
|
176
|
+
f"{self.base_url}/api/v1/beta/agent-data/:search",
|
|
177
|
+
json=search_request,
|
|
178
|
+
)
|
|
179
|
+
response.raise_for_status()
|
|
180
|
+
data = response.json()
|
|
181
|
+
|
|
182
|
+
items = data.get("items", [])
|
|
183
|
+
if not items:
|
|
103
184
|
return None
|
|
104
|
-
id =
|
|
185
|
+
id = items[0].get("id")
|
|
105
186
|
if id is None:
|
|
106
187
|
return None
|
|
107
188
|
self.cache.set(handler.handler_id, id)
|
|
@@ -121,4 +202,15 @@ class AgentDataStore(AbstractWorkflowStore):
|
|
|
121
202
|
filters["status"] = {
|
|
122
203
|
"includes": query.status_in,
|
|
123
204
|
}
|
|
205
|
+
if query.is_idle is not None:
|
|
206
|
+
if query.is_idle:
|
|
207
|
+
# Filter for handlers where idle_since is set (any valid datetime)
|
|
208
|
+
filters["idle_since"] = {
|
|
209
|
+
"gte": "1970-01-01T00:00:00Z",
|
|
210
|
+
}
|
|
211
|
+
else:
|
|
212
|
+
# Filter for handlers where idle_since is not set (null)
|
|
213
|
+
filters["idle_since"] = {
|
|
214
|
+
"eq": None,
|
|
215
|
+
}
|
|
124
216
|
return filters
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: llama-deploy-appserver
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Application server components for LlamaDeploy
|
|
5
5
|
Author: Massimiliano Pippi, Adrian Lyjak
|
|
6
6
|
Author-email: Massimiliano Pippi <mpippi@gmail.com>, Adrian Lyjak <adrianlyjak@gmail.com>
|
|
@@ -9,14 +9,13 @@ Requires-Dist: llama-index-workflows[server]>=2.12.0,<2.13.0
|
|
|
9
9
|
Requires-Dist: pydantic-settings>=2.10.1
|
|
10
10
|
Requires-Dist: fastapi>=0.100.0
|
|
11
11
|
Requires-Dist: websockets>=12.0
|
|
12
|
-
Requires-Dist: llama-deploy-core>=0.
|
|
12
|
+
Requires-Dist: llama-deploy-core>=0.4.0,<0.5.0
|
|
13
13
|
Requires-Dist: httpx>=0.24.0,<1.0.0
|
|
14
14
|
Requires-Dist: prometheus-fastapi-instrumentator>=7.1.0
|
|
15
15
|
Requires-Dist: packaging>=25.0
|
|
16
16
|
Requires-Dist: structlog>=25.4.0
|
|
17
17
|
Requires-Dist: rich>=14.1.0
|
|
18
18
|
Requires-Dist: pyyaml>=6.0.2
|
|
19
|
-
Requires-Dist: llama-cloud-services>=0.6.60
|
|
20
19
|
Requires-Dist: watchfiles>=1.1.0
|
|
21
20
|
Requires-Dist: uvicorn>=0.35.0
|
|
22
21
|
Requires-Dist: typing-extensions>=4.15.0 ; python_full_version < '3.12'
|
|
@@ -16,9 +16,9 @@ llama_deploy/appserver/settings.py,sha256=aa4512d2f1f28b8ee7d3fedc8c61f77bce9f80
|
|
|
16
16
|
llama_deploy/appserver/stats.py,sha256=1f3989f6705a6de3e4d61ee8cdd189fbe04a2c53ec5e720b2e5168acc331427f,691
|
|
17
17
|
llama_deploy/appserver/types.py,sha256=4edc991aafb6b8497f068d12387455df292da3ff8440223637641ab1632553ec,2133
|
|
18
18
|
llama_deploy/appserver/workflow_loader.py,sha256=c1422bda79423528f1f22fe793c9c43cb411dd883a05a80c5a161f04efd9489e,15713
|
|
19
|
-
llama_deploy/appserver/workflow_store/agent_data_store.py,sha256=
|
|
19
|
+
llama_deploy/appserver/workflow_store/agent_data_store.py,sha256=816710c9957c37792ce38e97a2c57cd8079953d55489b445675646ff74b4e13e,7710
|
|
20
20
|
llama_deploy/appserver/workflow_store/keyed_lock.py,sha256=72bcfafbce56d5b36d53aff764b573c2dca2b3f5bc59f2d8baa80be0e4db6e34,1037
|
|
21
21
|
llama_deploy/appserver/workflow_store/lru_cache.py,sha256=10b7d69e4be7d929d9dac009b59635b20fbed4603fb004bc35cbdc3ce538af8b,1454
|
|
22
|
-
llama_deploy_appserver-0.
|
|
23
|
-
llama_deploy_appserver-0.
|
|
24
|
-
llama_deploy_appserver-0.
|
|
22
|
+
llama_deploy_appserver-0.4.0.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
|
|
23
|
+
llama_deploy_appserver-0.4.0.dist-info/METADATA,sha256=41f69121b36ccb0494337a86cf0b83ec247e69ce5c39235cc7c9af0609fff919,1117
|
|
24
|
+
llama_deploy_appserver-0.4.0.dist-info/RECORD,,
|
|
File without changes
|