llama-deploy-appserver 0.2.7a1__py3-none-any.whl → 0.3.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.
Files changed (38) hide show
  1. llama_deploy/appserver/app.py +274 -26
  2. llama_deploy/appserver/bootstrap.py +55 -25
  3. llama_deploy/appserver/configure_logging.py +189 -0
  4. llama_deploy/appserver/correlation_id.py +24 -0
  5. llama_deploy/appserver/deployment.py +70 -412
  6. llama_deploy/appserver/deployment_config_parser.py +12 -130
  7. llama_deploy/appserver/interrupts.py +55 -0
  8. llama_deploy/appserver/process_utils.py +214 -0
  9. llama_deploy/appserver/py.typed +0 -0
  10. llama_deploy/appserver/routers/__init__.py +4 -3
  11. llama_deploy/appserver/routers/deployments.py +163 -382
  12. llama_deploy/appserver/routers/status.py +4 -31
  13. llama_deploy/appserver/routers/ui_proxy.py +255 -0
  14. llama_deploy/appserver/settings.py +99 -49
  15. llama_deploy/appserver/types.py +0 -3
  16. llama_deploy/appserver/workflow_loader.py +431 -0
  17. llama_deploy/appserver/workflow_store/agent_data_store.py +100 -0
  18. llama_deploy/appserver/workflow_store/keyed_lock.py +32 -0
  19. llama_deploy/appserver/workflow_store/lru_cache.py +49 -0
  20. llama_deploy_appserver-0.3.0.dist-info/METADATA +25 -0
  21. llama_deploy_appserver-0.3.0.dist-info/RECORD +24 -0
  22. {llama_deploy_appserver-0.2.7a1.dist-info → llama_deploy_appserver-0.3.0.dist-info}/WHEEL +1 -1
  23. llama_deploy/appserver/__main__.py +0 -14
  24. llama_deploy/appserver/client/__init__.py +0 -3
  25. llama_deploy/appserver/client/base.py +0 -30
  26. llama_deploy/appserver/client/client.py +0 -49
  27. llama_deploy/appserver/client/models/__init__.py +0 -4
  28. llama_deploy/appserver/client/models/apiserver.py +0 -356
  29. llama_deploy/appserver/client/models/model.py +0 -82
  30. llama_deploy/appserver/run_autodeploy.py +0 -141
  31. llama_deploy/appserver/server.py +0 -60
  32. llama_deploy/appserver/source_managers/__init__.py +0 -5
  33. llama_deploy/appserver/source_managers/base.py +0 -33
  34. llama_deploy/appserver/source_managers/git.py +0 -48
  35. llama_deploy/appserver/source_managers/local.py +0 -51
  36. llama_deploy/appserver/tracing.py +0 -237
  37. llama_deploy_appserver-0.2.7a1.dist-info/METADATA +0 -23
  38. llama_deploy_appserver-0.2.7a1.dist-info/RECORD +0 -28
@@ -0,0 +1,431 @@
1
+ import configparser
2
+ import functools
3
+ import importlib
4
+ import logging
5
+ import os
6
+ import socket
7
+ import subprocess
8
+ import sys
9
+ from dataclasses import dataclass
10
+ from importlib.metadata import version as pkg_version
11
+ from pathlib import Path
12
+ from textwrap import dedent
13
+
14
+ from dotenv import dotenv_values
15
+ from llama_deploy.appserver.deployment_config_parser import (
16
+ DeploymentConfig,
17
+ )
18
+ from llama_deploy.appserver.process_utils import run_process, spawn_process
19
+ from llama_deploy.appserver.settings import ApiserverSettings, settings
20
+ from llama_deploy.core.ui_build import ui_build_output_path
21
+ from packaging.version import InvalidVersion, Version
22
+ from workflows import Workflow
23
+ from workflows.server import WorkflowServer
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ DEFAULT_SERVICE_ID = "default"
28
+
29
+
30
+ def load_workflows(config: DeploymentConfig) -> dict[str, Workflow]:
31
+ """
32
+ Creates WorkflowService instances according to the configuration object.
33
+
34
+ """
35
+ workflow_services: dict[str, Workflow] = {}
36
+
37
+ if config.app:
38
+ module_name, app_name = config.app.split(":", 1)
39
+ module = importlib.import_module(module_name)
40
+ workflow = getattr(module, app_name)
41
+ if not isinstance(workflow, WorkflowServer):
42
+ raise ValueError(
43
+ f"Workflow {app_name} in {module_name} is not a WorkflowServer object"
44
+ )
45
+ # kludge to get the workflows
46
+ workflow_services = workflow._workflows
47
+ else:
48
+ for service_id, workflow_name in config.workflows.items():
49
+ module_name, workflow_name = workflow_name.split(":", 1)
50
+ module = importlib.import_module(module_name)
51
+ workflow = getattr(module, workflow_name)
52
+ if not isinstance(workflow, Workflow):
53
+ logger.warning(
54
+ f"Workflow {workflow_name} in {module_name} is not a Workflow object",
55
+ )
56
+ workflow_services[service_id] = workflow
57
+
58
+ return workflow_services
59
+
60
+
61
+ def load_environment_variables(config: DeploymentConfig, source_root: Path) -> None:
62
+ """
63
+ Load environment variables from the deployment config.
64
+ """
65
+ for key, value in parse_environment_variables(config, source_root).items():
66
+ if value:
67
+ os.environ[key] = value
68
+
69
+
70
+ def parse_environment_variables(
71
+ config: DeploymentConfig, source_root: Path
72
+ ) -> dict[str, str]:
73
+ """
74
+ Parse environment variables from the deployment config.
75
+ """
76
+ env_vars = {**config.env} if config.env else {}
77
+ for env_file in config.env_files or []:
78
+ env_file_path = source_root / env_file
79
+ values = dotenv_values(env_file_path)
80
+ env_vars.update(**values)
81
+ return env_vars
82
+
83
+
84
+ @functools.cache
85
+ def are_we_editable_mode() -> bool:
86
+ """
87
+ Check if we're in editable mode.
88
+ """
89
+ # Heuristic: if the package path does not include 'site-packages', treat as editable
90
+ top_level_pkg = "llama_deploy.appserver"
91
+ try:
92
+ pkg = importlib.import_module(top_level_pkg)
93
+ pkg_path = Path(getattr(pkg, "__file__", "")).resolve()
94
+ if not pkg_path.exists():
95
+ return False
96
+
97
+ return "site-packages" not in pkg_path.parts
98
+ except Exception:
99
+ return False
100
+
101
+
102
+ def inject_appserver_into_target(
103
+ config: DeploymentConfig, source_root: Path, sdists: list[Path] | None = None
104
+ ) -> None:
105
+ """
106
+ Ensures uv, and uses it to add the appserver as a dependency to the target app.
107
+ - If sdists are provided, they will be installed directly for offline-ish installs (still fetches dependencies)
108
+ - If the appserver is currently editable, it will be installed directly from the source repo
109
+ - otherwise fetches the current version from pypi
110
+
111
+ Args:
112
+ config: The deployment config
113
+ source_root: The root directory of the deployment
114
+ sdists: A list of tar.gz sdists files to install instead of installing the appserver
115
+ """
116
+ path = settings.resolved_config_parent
117
+ logger.info(f"Installing ensuring venv at {path} and adding appserver to it")
118
+ _ensure_uv_available()
119
+ _install_and_add_appserver_if_missing(path, source_root, sdists=sdists)
120
+
121
+
122
+ def _get_installed_version_within_target(path: Path) -> Version | None:
123
+ try:
124
+ result = subprocess.check_output(
125
+ [
126
+ "uv",
127
+ "run",
128
+ "python",
129
+ "-c",
130
+ dedent("""
131
+ from importlib.metadata import version
132
+ try:
133
+ print(version("llama-deploy-appserver"))
134
+ except Exception:
135
+ pass
136
+ """),
137
+ ],
138
+ cwd=path,
139
+ stderr=subprocess.DEVNULL,
140
+ )
141
+ try:
142
+ return Version(result.decode("utf-8").strip())
143
+ except InvalidVersion:
144
+ return None
145
+ except subprocess.CalledProcessError:
146
+ return None
147
+
148
+
149
+ def _get_current_version() -> Version:
150
+ return Version(pkg_version("llama-deploy-appserver"))
151
+
152
+
153
+ def _is_missing_or_outdated(path: Path) -> Version | None:
154
+ """
155
+ returns the current version if the installed version is missing or outdated, otherwise None
156
+ """
157
+ installed = _get_installed_version_within_target(path)
158
+ current = _get_current_version()
159
+ if installed is None or installed < current:
160
+ return current
161
+ return None
162
+
163
+
164
+ def _install_and_add_appserver_if_missing(
165
+ path: Path,
166
+ source_root: Path,
167
+ save_version: bool = False,
168
+ sdists: list[Path] | None = None,
169
+ ) -> None:
170
+ """
171
+ Ensure venv, install project deps, and add the appserver to the venv if it's missing or outdated
172
+ """
173
+
174
+ if not (source_root / path / "pyproject.toml").exists():
175
+ logger.warning(
176
+ f"No pyproject.toml found at {source_root / path}, skipping appserver injection. The server will likely not be able to install your workflows."
177
+ )
178
+ return
179
+
180
+ def run_uv(cmd: str, args: list[str] = [], extra_env: dict[str, str] | None = None):
181
+ env = os.environ.copy()
182
+ if extra_env:
183
+ env.update(extra_env)
184
+ run_process(
185
+ ["uv", cmd] + args,
186
+ cwd=source_root / path,
187
+ prefix=f"[uv {cmd}]",
188
+ color_code="36",
189
+ use_tty=False,
190
+ line_transform=_exclude_venv_warning,
191
+ env=env,
192
+ )
193
+
194
+ def ensure_venv(path: Path, force: bool = False) -> Path:
195
+ venv_path = source_root / path / ".venv"
196
+ if force or not venv_path.exists():
197
+ run_uv("venv", [str(venv_path)])
198
+ return venv_path
199
+
200
+ editable = are_we_editable_mode()
201
+ venv_path = ensure_venv(path, force=editable)
202
+ run_uv(
203
+ "sync",
204
+ ["--no-dev", "--inexact"],
205
+ extra_env={"UV_PROJECT_ENVIRONMENT": str(venv_path)},
206
+ )
207
+
208
+ if sdists:
209
+ run_uv(
210
+ "pip",
211
+ ["install"]
212
+ + [str(s.absolute()) for s in sdists]
213
+ + ["--prefix", str(venv_path)],
214
+ )
215
+ elif are_we_editable_mode():
216
+ same_python_version = _same_python_version(venv_path)
217
+ if not same_python_version.is_same:
218
+ logger.error(
219
+ f"Python version mismatch. Current: {same_python_version.current_version} != Project: {same_python_version.target_version}. During development, the target environment must be running the same Python version, otherwise the appserver cannot be installed."
220
+ )
221
+ raise RuntimeError(
222
+ f"Python version mismatch. Current: {same_python_version.current_version} != Project: {same_python_version.target_version}"
223
+ )
224
+ pyproject = _find_development_pyproject()
225
+ if pyproject is None:
226
+ raise RuntimeError("No pyproject.toml found in llama-deploy-appserver")
227
+ base = (source_root.resolve() / path).resolve()
228
+ rel = Path(os.path.relpath(pyproject, start=base))
229
+ target = f"file://{str(rel)}"
230
+
231
+ run_uv(
232
+ "pip",
233
+ [
234
+ "install",
235
+ "--reinstall-package",
236
+ "llama-deploy-appserver",
237
+ target,
238
+ "--prefix",
239
+ str(venv_path),
240
+ ],
241
+ )
242
+
243
+ else:
244
+ version = _is_missing_or_outdated(path)
245
+ if version is not None:
246
+ if save_version:
247
+ run_uv("add", [f"llama-deploy-appserver>={version}"])
248
+ else:
249
+ run_uv(
250
+ "pip",
251
+ [
252
+ "install",
253
+ f"llama-deploy-appserver=={version}",
254
+ "--prefix",
255
+ str(venv_path),
256
+ ],
257
+ )
258
+
259
+
260
+ def _find_development_pyproject() -> Path | None:
261
+ dir = Path(__file__).parent.resolve()
262
+ while not (dir / "pyproject.toml").exists():
263
+ dir = dir.parent
264
+ if dir == dir.root:
265
+ return None
266
+ return dir
267
+
268
+
269
+ def _exclude_venv_warning(line: str) -> str | None:
270
+ if "use `--active` to target the active environment instead" in line:
271
+ return None
272
+ return line
273
+
274
+
275
+ def _ensure_uv_available() -> None:
276
+ # Check if uv is available on the path
277
+ uv_available = False
278
+ try:
279
+ subprocess.check_call(
280
+ ["uv", "--version"],
281
+ stdout=subprocess.DEVNULL,
282
+ stderr=subprocess.DEVNULL,
283
+ )
284
+ uv_available = True
285
+ except (subprocess.CalledProcessError, FileNotFoundError):
286
+ pass
287
+ if not uv_available:
288
+ # bootstrap uv with pip
289
+ try:
290
+ run_process(
291
+ [
292
+ sys.executable,
293
+ "-m",
294
+ "pip",
295
+ "install",
296
+ "uv",
297
+ ],
298
+ prefix="[python -m pip]",
299
+ color_code="31", # red
300
+ )
301
+ except subprocess.CalledProcessError as e:
302
+ msg = f"Unable to install uv. Environment must include uv, or uv must be installed with pip: {e.stderr}"
303
+ raise RuntimeError(msg)
304
+
305
+
306
+ @dataclass
307
+ class SamePythonVersionResult:
308
+ is_same: bool
309
+ current_version: str
310
+ target_version: str | None
311
+
312
+
313
+ def _same_python_version(venv_path: Path) -> SamePythonVersionResult:
314
+ current_version = f"{sys.version_info.major}.{sys.version_info.minor}"
315
+ target_version = None
316
+ cfg = venv_path / "pyvenv.cfg"
317
+ if cfg.exists():
318
+ parser = configparser.ConfigParser()
319
+ parser.read_string("[venv]\n" + cfg.read_text())
320
+ ver_str = parser["venv"].get("version_info", "").strip()
321
+ if ver_str:
322
+ try:
323
+ v = Version(ver_str)
324
+ target_version = f"{v.major}.{v.minor}"
325
+ except InvalidVersion:
326
+ pass
327
+ return SamePythonVersionResult(
328
+ is_same=current_version == target_version,
329
+ current_version=current_version,
330
+ target_version=target_version,
331
+ )
332
+
333
+
334
+ def install_ui(config: DeploymentConfig, config_parent: Path) -> None:
335
+ if config.ui is None:
336
+ return
337
+ package_manager = config.ui.package_manager
338
+ try:
339
+ run_process(
340
+ [package_manager, "install"],
341
+ cwd=config_parent / config.ui.directory,
342
+ prefix=f"[{package_manager} install]",
343
+ color_code="33",
344
+ # auto download the package manager
345
+ env={**os.environ.copy(), "COREPACK_ENABLE_DOWNLOAD_PROMPT": "0"},
346
+ )
347
+ except BaseException as e:
348
+ if "No such file or directory" in str(e):
349
+ raise RuntimeError(
350
+ f"Package manager {package_manager} not found. Please download and enable corepack, or install the package manager manually."
351
+ )
352
+ raise e
353
+
354
+
355
+ def _ui_env(config: DeploymentConfig, settings: ApiserverSettings) -> dict[str, str]:
356
+ env = os.environ.copy()
357
+ env["LLAMA_DEPLOY_DEPLOYMENT_URL_ID"] = config.name
358
+ env["LLAMA_DEPLOY_DEPLOYMENT_BASE_PATH"] = f"/deployments/{config.name}/ui"
359
+ if config.ui is not None:
360
+ env["PORT"] = str(settings.proxy_ui_port)
361
+ return env
362
+
363
+
364
+ def build_ui(
365
+ config_parent: Path, config: DeploymentConfig, settings: ApiserverSettings
366
+ ) -> bool:
367
+ """
368
+ Returns True if the UI was built (and supports building), otherwise False if there's no build command
369
+ """
370
+ if config.ui is None:
371
+ return False
372
+ path = Path(config.ui.directory)
373
+ env = _ui_env(config, settings)
374
+
375
+ has_build = ui_build_output_path(config_parent, config)
376
+ if has_build is None:
377
+ return False
378
+
379
+ run_process(
380
+ ["npm", "run", "build"],
381
+ cwd=config_parent / path,
382
+ env=env,
383
+ prefix="[npm run build]",
384
+ color_code="34",
385
+ )
386
+ return True
387
+
388
+
389
+ def start_dev_ui_process(
390
+ root: Path, settings: ApiserverSettings, config: DeploymentConfig
391
+ ) -> None | subprocess.Popen:
392
+ ui_port = settings.proxy_ui_port
393
+ ui = config.ui
394
+ if ui is None:
395
+ return None
396
+
397
+ # If a UI dev server is already listening on the configured port, do not start another
398
+ def _is_port_open(port: int) -> bool:
399
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
400
+ sock.settimeout(0.2)
401
+ try:
402
+ return sock.connect_ex(("127.0.0.1", port)) == 0
403
+ except Exception:
404
+ return False
405
+
406
+ if _is_port_open(ui_port):
407
+ logger.info(
408
+ f"Detected process already running on port {ui_port}; not starting a new one."
409
+ )
410
+ return None
411
+ # start the ui process
412
+ env = _ui_env(config, settings)
413
+ # Transform first 20 lines to replace the default UI port with the main server port
414
+ line_counter = 0
415
+
416
+ def _transform(line: str) -> str:
417
+ nonlocal line_counter
418
+ if line_counter < 20:
419
+ line = line.replace(f":{ui_port}", f":{settings.port}")
420
+ line_counter += 1
421
+ return line
422
+
423
+ return spawn_process(
424
+ ["npm", "run", ui.serve_command],
425
+ cwd=root / (ui.directory),
426
+ env=env,
427
+ prefix=f"[npm run {ui.serve_command}]",
428
+ color_code="35",
429
+ line_transform=_transform,
430
+ use_tty=False,
431
+ )
@@ -0,0 +1,100 @@
1
+ import logging
2
+ import os
3
+ from typing import List
4
+
5
+ from llama_cloud.client import AsyncLlamaCloud, httpx
6
+ from llama_cloud_services.beta.agent_data import AsyncAgentDataClient
7
+ from llama_deploy.appserver.settings import ApiserverSettings
8
+ from llama_deploy.core.deployment_config import DeploymentConfig
9
+ from typing_extensions import override
10
+ from workflows.server import AbstractWorkflowStore, HandlerQuery, PersistentHandler
11
+
12
+ from .keyed_lock import AsyncKeyedLock
13
+ from .lru_cache import LRUCache
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class AgentDataStore(AbstractWorkflowStore):
19
+ def __init__(
20
+ self, settings: DeploymentConfig, server_settings: ApiserverSettings
21
+ ) -> None:
22
+ agent_url_id: str | None = server_settings.cloud_persistence_name
23
+ collection = "workflow_contexts"
24
+ if agent_url_id is not None:
25
+ parts = agent_url_id.split(":")
26
+ if len(parts) > 1:
27
+ collection = parts[1]
28
+ agent_url_id = parts[0]
29
+ else:
30
+ agent_url_id = settings.name
31
+
32
+ self.settings = settings
33
+ project_id = os.getenv("LLAMA_DEPLOY_PROJECT_ID")
34
+ self.client = AsyncAgentDataClient(
35
+ type=PersistentHandler,
36
+ collection=collection,
37
+ agent_url_id=agent_url_id,
38
+ client=AsyncLlamaCloud(
39
+ base_url=os.getenv("LLAMA_CLOUD_BASE_URL"),
40
+ token=os.getenv("LLAMA_CLOUD_API_KEY"),
41
+ httpx_client=httpx.AsyncClient(
42
+ headers={"Project-Id": project_id} if project_id else None,
43
+ ),
44
+ ),
45
+ )
46
+ self.lock = AsyncKeyedLock()
47
+ # workflow id -> agent data id
48
+ self.cache = LRUCache[str, str](maxsize=1024)
49
+
50
+ @override
51
+ async def query(self, query: HandlerQuery) -> List[PersistentHandler]:
52
+ filters = {}
53
+ if query.handler_id_in is not None:
54
+ filters["handler_id"] = {
55
+ "includes": query.handler_id_in,
56
+ }
57
+ if query.workflow_name_in is not None:
58
+ filters["workflow_name"] = {
59
+ "includes": query.workflow_name_in,
60
+ }
61
+ if query.status_in is not None:
62
+ filters["status"] = {
63
+ "includes": query.status_in,
64
+ }
65
+ results = await self.client.search(
66
+ filter=filters,
67
+ page_size=1000,
68
+ )
69
+ return [x.data for x in results.items]
70
+
71
+ @override
72
+ async def update(self, handler: PersistentHandler) -> None:
73
+ async with self.lock.acquire(handler.handler_id):
74
+ id = await self._get_item_id(handler)
75
+ if id is None:
76
+ item = await self.client.create_item(
77
+ data=handler,
78
+ )
79
+ if item.id is None:
80
+ raise ValueError(f"Failed to create handler {handler.handler_id}")
81
+ self.cache.set(handler.handler_id, item.id)
82
+ else:
83
+ await self.client.update_item(
84
+ item_id=id,
85
+ data=handler,
86
+ )
87
+
88
+ async def _get_item_id(self, handler: PersistentHandler) -> str | None:
89
+ cached_id = self.cache.get(handler.handler_id, None)
90
+ if cached_id is not None:
91
+ return cached_id
92
+ results = await self.client.search(
93
+ filter={"handler_id": {"eq": handler.handler_id}},
94
+ page_size=1,
95
+ )
96
+ if not results.items:
97
+ return None
98
+ id = results.items[0].id
99
+ self.cache.set(handler.handler_id, id)
100
+ return id
@@ -0,0 +1,32 @@
1
+ import asyncio
2
+ from collections import Counter
3
+ from contextlib import asynccontextmanager
4
+
5
+
6
+ class AsyncKeyedLock:
7
+ def __init__(self):
8
+ self._locks: dict[str, asyncio.Lock] = {}
9
+ self._refcnt = Counter()
10
+ self._registry_lock = asyncio.Lock() # protects _locks/_refcnt
11
+
12
+ @asynccontextmanager
13
+ async def acquire(self, key: str):
14
+ async with self._registry_lock:
15
+ lock = self._locks.get(key)
16
+ if lock is None:
17
+ lock = asyncio.Lock()
18
+ self._locks[key] = lock
19
+ self._refcnt[key] += 1
20
+
21
+ try:
22
+ await lock.acquire()
23
+ try:
24
+ yield
25
+ finally:
26
+ lock.release()
27
+ finally:
28
+ async with self._registry_lock:
29
+ self._refcnt[key] -= 1
30
+ if self._refcnt[key] == 0:
31
+ self._locks.pop(key, None)
32
+ del self._refcnt[key]
@@ -0,0 +1,49 @@
1
+ from collections import OrderedDict
2
+ from typing import Generic, TypeVar, overload
3
+
4
+ K = TypeVar("K")
5
+ V = TypeVar("V")
6
+
7
+
8
+ class LRUCache(Generic[K, V]):
9
+ def __init__(self, maxsize: int = 128):
10
+ self.maxsize = maxsize
11
+ self._store: OrderedDict[K, V] = OrderedDict()
12
+
13
+ @overload
14
+ def get(self, key: K) -> V | None: ...
15
+
16
+ @overload
17
+ def get(self, key: K, default: V) -> V: ...
18
+
19
+ def get(self, key: K, default: V | None = None) -> V | None:
20
+ if key not in self._store:
21
+ return default
22
+ # mark as recently used
23
+ value = self._store.pop(key)
24
+ self._store[key] = value
25
+ return value
26
+
27
+ def set(self, key: K, value: V):
28
+ if key in self._store:
29
+ # remove old so we can push to end
30
+ self._store.pop(key)
31
+ elif len(self._store) >= self.maxsize:
32
+ # evict least recently used (first item)
33
+ self._store.popitem(last=False)
34
+ self._store[key] = value
35
+
36
+ def __contains__(self, key: K) -> bool:
37
+ return key in self._store
38
+
39
+ def __getitem__(self, key: K) -> V:
40
+ return self.get(key)
41
+
42
+ def __setitem__(self, key: K, value: V):
43
+ self.set(key, value)
44
+
45
+ def __len__(self) -> int:
46
+ return len(self._store)
47
+
48
+ def __iter__(self):
49
+ return iter(self._store)
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.3
2
+ Name: llama-deploy-appserver
3
+ Version: 0.3.0
4
+ Summary: Application server components for LlamaDeploy
5
+ Author: Massimiliano Pippi, Adrian Lyjak
6
+ Author-email: Massimiliano Pippi <mpippi@gmail.com>, Adrian Lyjak <adrianlyjak@gmail.com>
7
+ License: MIT
8
+ Requires-Dist: llama-index-workflows[server]>=2.2.0
9
+ Requires-Dist: pydantic-settings>=2.10.1
10
+ Requires-Dist: uvicorn>=0.24.0
11
+ Requires-Dist: fastapi>=0.100.0
12
+ Requires-Dist: websockets>=12.0
13
+ Requires-Dist: llama-deploy-core>=0.3.0,<0.4.0
14
+ Requires-Dist: httpx>=0.24.0,<1.0.0
15
+ Requires-Dist: prometheus-fastapi-instrumentator>=7.1.0
16
+ Requires-Dist: packaging>=25.0
17
+ Requires-Dist: structlog>=25.4.0
18
+ Requires-Dist: rich>=14.1.0
19
+ Requires-Dist: pyyaml>=6.0.2
20
+ Requires-Dist: llama-cloud-services>=0.6.60
21
+ Requires-Python: >=3.11, <4
22
+ Description-Content-Type: text/markdown
23
+
24
+ > [!WARNING]
25
+ > This repository contains pre-release software. It is unstable, incomplete, and subject to breaking changes. Not recommended for use.
@@ -0,0 +1,24 @@
1
+ llama_deploy/appserver/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
2
+ llama_deploy/appserver/app.py,sha256=1150ac9d6b2e4bd0bbe4cc70a16249381887e86f49c68492a3ab61024d4567b7,9520
3
+ llama_deploy/appserver/bootstrap.py,sha256=fa32be007f18b4b3af92c878bac417416c9afb09b1beddf51b5cd73115e6b7c6,2453
4
+ llama_deploy/appserver/configure_logging.py,sha256=194dd1ebed3c1d9065d9174f7828d557a577eaac8fb0443b3102430b1f578c19,6329
5
+ llama_deploy/appserver/correlation_id.py,sha256=8ac5bc6160c707b93a9fb818b64dd369a4ef7a53f9f91a6b3d90c4cf446f7327,572
6
+ llama_deploy/appserver/deployment.py,sha256=8bc298caaf765b5fea345287de14f7b9a4aedc06261220f4ed00d1dde9bec502,6092
7
+ llama_deploy/appserver/deployment_config_parser.py,sha256=e2b6c483203d96ab795c4e55df15c694c20458d5a03fab89c2b71e481291a2d3,510
8
+ llama_deploy/appserver/interrupts.py,sha256=14f262a0cedc00bb3aecd3d6c14c41ba0e88e7d2a6df02cd35b5bea1940822a2,1622
9
+ llama_deploy/appserver/process_utils.py,sha256=befee4918c6cf72082dca8bf807afb61ad3d6c83f01bc0c007594b47930570d8,6056
10
+ llama_deploy/appserver/py.typed,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
11
+ llama_deploy/appserver/routers/__init__.py,sha256=ee2d14ebf4b067c844947ed1cc98186456e8bfa4919282722eaaf8cca345a138,214
12
+ llama_deploy/appserver/routers/deployments.py,sha256=e7bafd72c1b4b809e5ad57442594a997c85ecab998b8430da65899faa910db1c,7572
13
+ llama_deploy/appserver/routers/status.py,sha256=2af74bc40e52dc5944af2df98c6a021fea7b0cfcda88b56ac124dc383120758c,282
14
+ llama_deploy/appserver/routers/ui_proxy.py,sha256=f63c36c201070594a4011320192d724b1c534d0ec655c49ba65c4e9911dbdd97,8633
15
+ llama_deploy/appserver/settings.py,sha256=279dad9d80f4b54215cb8073bc46ee2beebfbc8ed75f40bccfbb387593f6975a,4984
16
+ llama_deploy/appserver/stats.py,sha256=1f3989f6705a6de3e4d61ee8cdd189fbe04a2c53ec5e720b2e5168acc331427f,691
17
+ llama_deploy/appserver/types.py,sha256=4edc991aafb6b8497f068d12387455df292da3ff8440223637641ab1632553ec,2133
18
+ llama_deploy/appserver/workflow_loader.py,sha256=c15890a00976e022edcdf2af04bf699c02fba020bb06c47960a4911e08255501,14146
19
+ llama_deploy/appserver/workflow_store/agent_data_store.py,sha256=7b8d1b8cb6f741ff631d668fc955ca76a82e8da0bf8a27ee3bc9a8ef71123701,3594
20
+ llama_deploy/appserver/workflow_store/keyed_lock.py,sha256=bb1504d9de09d51a8f60721cc77b14d4051ac5a897ace6f9d9cba494f068465e,950
21
+ llama_deploy/appserver/workflow_store/lru_cache.py,sha256=7511231b6aba81ea96044cf644cd9c1f11d78190b7b7f578b1b5a55e2c218f9f,1323
22
+ llama_deploy_appserver-0.3.0.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
23
+ llama_deploy_appserver-0.3.0.dist-info/METADATA,sha256=0ee9fc6166c50252991baad2f7186a6b58fc3321e349df0074f809e2a77d34ea,974
24
+ llama_deploy_appserver-0.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.7.21
2
+ Generator: uv 0.7.20
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,14 +0,0 @@
1
- import uvicorn
2
- from prometheus_client import start_http_server
3
-
4
- from .settings import settings
5
-
6
- if __name__ == "__main__":
7
- if settings.prometheus_enabled:
8
- start_http_server(settings.prometheus_port)
9
-
10
- uvicorn.run(
11
- "llama_deploy.appserver.app:app",
12
- host=settings.host,
13
- port=settings.port,
14
- )
@@ -1,3 +0,0 @@
1
- from .client import Client
2
-
3
- __all__ = ["Client"]