llama-deploy-appserver 0.2.7a1__py3-none-any.whl → 0.3.0a2__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/__main__.py +0 -4
- llama_deploy/appserver/app.py +105 -25
- llama_deploy/appserver/bootstrap.py +76 -24
- llama_deploy/appserver/deployment.py +7 -421
- llama_deploy/appserver/deployment_config_parser.py +35 -59
- llama_deploy/appserver/routers/__init__.py +4 -3
- llama_deploy/appserver/routers/deployments.py +162 -385
- llama_deploy/appserver/routers/status.py +4 -31
- llama_deploy/appserver/routers/ui_proxy.py +213 -0
- llama_deploy/appserver/settings.py +57 -55
- llama_deploy/appserver/types.py +0 -3
- llama_deploy/appserver/workflow_loader.py +383 -0
- {llama_deploy_appserver-0.2.7a1.dist-info → llama_deploy_appserver-0.3.0a2.dist-info}/METADATA +3 -6
- llama_deploy_appserver-0.3.0a2.dist-info/RECORD +17 -0
- {llama_deploy_appserver-0.2.7a1.dist-info → llama_deploy_appserver-0.3.0a2.dist-info}/WHEEL +1 -1
- llama_deploy/appserver/client/__init__.py +0 -3
- llama_deploy/appserver/client/base.py +0 -30
- llama_deploy/appserver/client/client.py +0 -49
- llama_deploy/appserver/client/models/__init__.py +0 -4
- llama_deploy/appserver/client/models/apiserver.py +0 -356
- llama_deploy/appserver/client/models/model.py +0 -82
- llama_deploy/appserver/run_autodeploy.py +0 -141
- llama_deploy/appserver/server.py +0 -60
- llama_deploy/appserver/source_managers/__init__.py +0 -5
- llama_deploy/appserver/source_managers/base.py +0 -33
- llama_deploy/appserver/source_managers/git.py +0 -48
- llama_deploy/appserver/source_managers/local.py +0 -51
- llama_deploy/appserver/tracing.py +0 -237
- llama_deploy_appserver-0.2.7a1.dist-info/RECORD +0 -28
@@ -1,48 +0,0 @@
|
|
1
|
-
import shutil
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
from git import Repo
|
6
|
-
|
7
|
-
from .base import SourceManager, SyncPolicy
|
8
|
-
|
9
|
-
|
10
|
-
class GitSourceManager(SourceManager):
|
11
|
-
"""A SourceManager specialized for sources of type `git`."""
|
12
|
-
|
13
|
-
def sync(
|
14
|
-
self,
|
15
|
-
source: str,
|
16
|
-
destination: str | None = None,
|
17
|
-
sync_policy: SyncPolicy = SyncPolicy.REPLACE,
|
18
|
-
) -> None:
|
19
|
-
"""Clones the repository at URL `source` into a local path `destination`.
|
20
|
-
|
21
|
-
Args:
|
22
|
-
source: The URL of the git repository. It can optionally contain a branch target using the name convention
|
23
|
-
`git_repo_url@branch_name`. For example, "https://example.com/llama_deploy.git@branch_name".
|
24
|
-
destination: The path in the local filesystem where to clone the git repository.
|
25
|
-
"""
|
26
|
-
if not destination:
|
27
|
-
raise ValueError("Destination cannot be empty")
|
28
|
-
|
29
|
-
if Path(destination).exists():
|
30
|
-
# FIXME: pull when SyncPolicy is MERGE
|
31
|
-
shutil.rmtree(destination)
|
32
|
-
|
33
|
-
url, branch_name = self._parse_source(source)
|
34
|
-
kwargs: dict[str, Any] = {"url": url, "to_path": destination}
|
35
|
-
if branch_name:
|
36
|
-
kwargs["multi_options"] = [f"-b {branch_name}", "--single-branch"]
|
37
|
-
|
38
|
-
Repo.clone_from(**kwargs) # type: ignore
|
39
|
-
|
40
|
-
@staticmethod
|
41
|
-
def _parse_source(source: str) -> tuple[str, str | None]:
|
42
|
-
branch_name = None
|
43
|
-
toks = source.split("@")
|
44
|
-
url = toks[0]
|
45
|
-
if len(toks) > 1:
|
46
|
-
branch_name = toks[1]
|
47
|
-
|
48
|
-
return url, branch_name
|
@@ -1,51 +0,0 @@
|
|
1
|
-
import shutil
|
2
|
-
from pathlib import Path
|
3
|
-
|
4
|
-
from .base import SourceManager, SyncPolicy
|
5
|
-
|
6
|
-
|
7
|
-
class LocalSourceManager(SourceManager):
|
8
|
-
"""A SourceManager specialized for sources of type `local`."""
|
9
|
-
|
10
|
-
def sync(
|
11
|
-
self,
|
12
|
-
source: str,
|
13
|
-
destination: str | None = None,
|
14
|
-
sync_policy: SyncPolicy = SyncPolicy.REPLACE,
|
15
|
-
) -> None:
|
16
|
-
"""Copies the folder with path `source` into a local path `destination`.
|
17
|
-
|
18
|
-
Args:
|
19
|
-
source: The filesystem path to the folder containing the source code.
|
20
|
-
destination: The path in the local filesystem where to copy the source directory.
|
21
|
-
"""
|
22
|
-
if sync_policy == SyncPolicy.SKIP:
|
23
|
-
return
|
24
|
-
|
25
|
-
if not destination:
|
26
|
-
raise ValueError("Destination cannot be empty")
|
27
|
-
|
28
|
-
if Path(source).is_absolute():
|
29
|
-
raise ValueError("Source path must be relative to the deployment file")
|
30
|
-
|
31
|
-
base = self._base_path or Path()
|
32
|
-
final_path = base / source
|
33
|
-
destination_path = Path(destination)
|
34
|
-
dirs_exist_ok: bool = False
|
35
|
-
if destination_path.exists():
|
36
|
-
# Path is a non-empty directory
|
37
|
-
if sync_policy == SyncPolicy.REPLACE:
|
38
|
-
shutil.rmtree(destination_path)
|
39
|
-
elif sync_policy == SyncPolicy.MERGE:
|
40
|
-
dirs_exist_ok = True
|
41
|
-
|
42
|
-
try:
|
43
|
-
shutil.copytree(
|
44
|
-
final_path, destination_path / source, dirs_exist_ok=dirs_exist_ok
|
45
|
-
)
|
46
|
-
except Exception as e:
|
47
|
-
msg = f"Unable to copy {source} into {destination}: {e}"
|
48
|
-
raise ValueError(msg) from e
|
49
|
-
|
50
|
-
def relative_path(self, source: str) -> str:
|
51
|
-
return source
|
@@ -1,237 +0,0 @@
|
|
1
|
-
"""Tracing utilities for llama_deploy."""
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from contextlib import contextmanager, nullcontext
|
5
|
-
from functools import wraps
|
6
|
-
from typing import TYPE_CHECKING, Any, Callable, Generator, TypeVar
|
7
|
-
|
8
|
-
if TYPE_CHECKING:
|
9
|
-
from llama_deploy.appserver.settings import ApiserverSettings
|
10
|
-
|
11
|
-
|
12
|
-
logger = logging.getLogger(__name__)
|
13
|
-
|
14
|
-
# Since opentelemetry is optional, we have to use Any to type the tracer
|
15
|
-
_tracer: Any | None = None
|
16
|
-
_tracing_enabled = False
|
17
|
-
_null_context = nullcontext()
|
18
|
-
|
19
|
-
F = TypeVar("F", bound=Callable[..., Any])
|
20
|
-
|
21
|
-
|
22
|
-
def configure_tracing(settings: "ApiserverSettings") -> None:
|
23
|
-
"""Configure OpenTelemetry tracing based on the provided configuration."""
|
24
|
-
global _tracer, _tracing_enabled
|
25
|
-
|
26
|
-
if not settings.tracing_enabled:
|
27
|
-
logger.debug("Tracing is disabled")
|
28
|
-
_tracing_enabled = False
|
29
|
-
return
|
30
|
-
|
31
|
-
try:
|
32
|
-
from opentelemetry import trace # type: ignore[import]
|
33
|
-
from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor # type: ignore[import]
|
34
|
-
from opentelemetry.sdk.resources import SERVICE_NAME, Resource # type: ignore[import]
|
35
|
-
from opentelemetry.sdk.trace import TracerProvider # type: ignore[import]
|
36
|
-
from opentelemetry.sdk.trace.export import BatchSpanProcessor # type: ignore[import]
|
37
|
-
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased # type: ignore[import]
|
38
|
-
|
39
|
-
# Create resource with service name
|
40
|
-
resource = Resource.create({SERVICE_NAME: settings.tracing_service_name})
|
41
|
-
|
42
|
-
# Create tracer provider with sampling
|
43
|
-
tracer_provider = TracerProvider(
|
44
|
-
resource=resource, sampler=TraceIdRatioBased(settings.tracing_sample_rate)
|
45
|
-
)
|
46
|
-
|
47
|
-
# Configure exporter based on config
|
48
|
-
if settings.tracing_exporter == "console":
|
49
|
-
from opentelemetry.sdk.trace.export import ConsoleSpanExporter # type: ignore[import]
|
50
|
-
|
51
|
-
exporter = ConsoleSpanExporter()
|
52
|
-
|
53
|
-
elif settings.tracing_exporter == "otlp":
|
54
|
-
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( # type: ignore[import]
|
55
|
-
OTLPSpanExporter,
|
56
|
-
)
|
57
|
-
|
58
|
-
if not settings.tracing_endpoint:
|
59
|
-
raise ValueError("OTLP exporter requires an endpoint")
|
60
|
-
exporter = OTLPSpanExporter(
|
61
|
-
endpoint=f"{settings.tracing_endpoint}/v1/traces",
|
62
|
-
insecure=settings.tracing_insecure,
|
63
|
-
timeout=settings.tracing_timeout,
|
64
|
-
)
|
65
|
-
else:
|
66
|
-
raise ValueError(f"Unsupported exporter: {settings.tracing_exporter}")
|
67
|
-
|
68
|
-
# Add span processor
|
69
|
-
span_processor = BatchSpanProcessor(exporter)
|
70
|
-
tracer_provider.add_span_processor(span_processor)
|
71
|
-
|
72
|
-
# Set the global tracer provider
|
73
|
-
trace.set_tracer_provider(tracer_provider)
|
74
|
-
|
75
|
-
# Initialize global tracer
|
76
|
-
_tracer = trace.get_tracer(__name__)
|
77
|
-
_tracing_enabled = True
|
78
|
-
|
79
|
-
# Setup auto-instrumentation
|
80
|
-
AsyncioInstrumentor().instrument()
|
81
|
-
|
82
|
-
logger.info(
|
83
|
-
f"Tracing configured with {settings.tracing_exporter} exporter, service: {settings.tracing_service_name}"
|
84
|
-
)
|
85
|
-
|
86
|
-
except ImportError as e:
|
87
|
-
msg = (
|
88
|
-
f"Tracing is enabled but OpenTelemetry instrumentation packages are missing: {e}. "
|
89
|
-
"Run `pip install llama_deploy[observability]`"
|
90
|
-
)
|
91
|
-
logger.warning(msg)
|
92
|
-
_tracing_enabled = False
|
93
|
-
except Exception as e:
|
94
|
-
logger.error(f"Failed to configure tracing: {e}")
|
95
|
-
_tracing_enabled = False
|
96
|
-
|
97
|
-
|
98
|
-
def get_tracer() -> Any | None:
|
99
|
-
"""Get the configured tracer instance."""
|
100
|
-
return _tracer if _tracing_enabled else None
|
101
|
-
|
102
|
-
|
103
|
-
def is_tracing_enabled() -> bool:
|
104
|
-
"""Check if tracing is enabled."""
|
105
|
-
return _tracing_enabled
|
106
|
-
|
107
|
-
|
108
|
-
def trace_method(
|
109
|
-
span_name: str | None = None, attributes: dict | None = None
|
110
|
-
) -> Callable[[F], F]:
|
111
|
-
"""Decorator to add tracing to synchronous methods."""
|
112
|
-
|
113
|
-
def decorator(func: F) -> F:
|
114
|
-
if not _tracing_enabled:
|
115
|
-
return func
|
116
|
-
|
117
|
-
@wraps(func)
|
118
|
-
def wrapper(*args, **kwargs): # type: ignore
|
119
|
-
tracer = get_tracer()
|
120
|
-
if not tracer:
|
121
|
-
return func(*args, **kwargs)
|
122
|
-
|
123
|
-
name = span_name or f"{func.__module__}.{func.__qualname__}" # type: ignore
|
124
|
-
with tracer.start_as_current_span(name) as span:
|
125
|
-
if attributes:
|
126
|
-
span.set_attributes(attributes)
|
127
|
-
|
128
|
-
if hasattr(func, "__annotations__"):
|
129
|
-
for i, (param_name, _) in enumerate(func.__annotations__.items()):
|
130
|
-
if i < len(args) and param_name not in {"self", "cls"}:
|
131
|
-
span.set_attribute(
|
132
|
-
f"arg.{param_name}", str(args[i])[:100]
|
133
|
-
) # Truncate long values
|
134
|
-
|
135
|
-
try:
|
136
|
-
result = func(*args, **kwargs)
|
137
|
-
span.set_attribute("success", True)
|
138
|
-
return result
|
139
|
-
except Exception as e:
|
140
|
-
span.set_attribute("success", False)
|
141
|
-
span.set_attribute("error.type", type(e).__name__)
|
142
|
-
span.set_attribute("error.message", str(e))
|
143
|
-
raise
|
144
|
-
|
145
|
-
return wrapper # type: ignore
|
146
|
-
|
147
|
-
return decorator
|
148
|
-
|
149
|
-
|
150
|
-
def trace_async_method(
|
151
|
-
span_name: str | None = None, attributes: dict | None = None
|
152
|
-
) -> Callable[[F], F]:
|
153
|
-
"""Decorator to add tracing to asynchronous methods."""
|
154
|
-
|
155
|
-
def decorator(func: F) -> F:
|
156
|
-
if not _tracing_enabled:
|
157
|
-
return func
|
158
|
-
|
159
|
-
@wraps(func)
|
160
|
-
async def wrapper(*args, **kwargs): # type: ignore
|
161
|
-
tracer = get_tracer()
|
162
|
-
if not tracer:
|
163
|
-
return await func(*args, **kwargs)
|
164
|
-
|
165
|
-
name = span_name or f"{func.__module__}.{func.__qualname__}" # type: ignore
|
166
|
-
with tracer.start_as_current_span(name) as span:
|
167
|
-
if attributes:
|
168
|
-
span.set_attributes(attributes)
|
169
|
-
|
170
|
-
if hasattr(func, "__annotations__"):
|
171
|
-
for i, (param_name, _) in enumerate(func.__annotations__.items()):
|
172
|
-
if i < len(args) and param_name not in {"self", "cls"}:
|
173
|
-
span.set_attribute(
|
174
|
-
f"arg.{param_name}", str(args[i])[:100]
|
175
|
-
) # Truncate long values
|
176
|
-
|
177
|
-
try:
|
178
|
-
result = await func(*args, **kwargs)
|
179
|
-
span.set_attribute("success", True)
|
180
|
-
return result
|
181
|
-
except Exception as e:
|
182
|
-
span.set_attribute("success", False)
|
183
|
-
span.set_attribute("error.type", type(e).__name__)
|
184
|
-
span.set_attribute("error.message", str(e))
|
185
|
-
raise
|
186
|
-
|
187
|
-
return wrapper # type: ignore
|
188
|
-
|
189
|
-
return decorator
|
190
|
-
|
191
|
-
|
192
|
-
@contextmanager
|
193
|
-
def create_span(
|
194
|
-
name: str, attributes: dict | None = None
|
195
|
-
) -> Generator[Any, None, None]:
|
196
|
-
tracer = get_tracer()
|
197
|
-
if tracer is None:
|
198
|
-
yield
|
199
|
-
return
|
200
|
-
|
201
|
-
with tracer.start_as_current_span(name) as span:
|
202
|
-
if attributes:
|
203
|
-
for k, v in attributes.items():
|
204
|
-
span.set_attribute(k, v)
|
205
|
-
yield span
|
206
|
-
|
207
|
-
|
208
|
-
def add_span_attribute(key: str, value: Any) -> None:
|
209
|
-
"""Add an attribute to the current span if tracing is enabled."""
|
210
|
-
if not _tracing_enabled:
|
211
|
-
return
|
212
|
-
|
213
|
-
try:
|
214
|
-
from opentelemetry import trace # type: ignore[import]
|
215
|
-
|
216
|
-
current_span = trace.get_current_span()
|
217
|
-
if current_span:
|
218
|
-
current_span.set_attribute(key, str(value))
|
219
|
-
except Exception:
|
220
|
-
# Silently ignore tracing errors
|
221
|
-
pass
|
222
|
-
|
223
|
-
|
224
|
-
def add_span_event(name: str, attributes: dict | None = None) -> None:
|
225
|
-
"""Add an event to the current span if tracing is enabled."""
|
226
|
-
if not _tracing_enabled:
|
227
|
-
return
|
228
|
-
|
229
|
-
try:
|
230
|
-
from opentelemetry import trace # type: ignore[import]
|
231
|
-
|
232
|
-
current_span = trace.get_current_span()
|
233
|
-
if current_span:
|
234
|
-
current_span.add_event(name, attributes or {})
|
235
|
-
except Exception:
|
236
|
-
# Silently ignore tracing errors
|
237
|
-
pass
|
@@ -1,28 +0,0 @@
|
|
1
|
-
llama_deploy/appserver/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
|
2
|
-
llama_deploy/appserver/__main__.py,sha256=2dd2fe1f9ceff01038198515f30c107a82dc83ffd8c038d123f41893bf7fe4cb,333
|
3
|
-
llama_deploy/appserver/app.py,sha256=fbe5fa15e7dbb1ab4b98e29f838434023894b6adac8e099bc42ea9c4df990867,1506
|
4
|
-
llama_deploy/appserver/bootstrap.py,sha256=13b332df52ef763e20fe2ff9bcc20917508fee8153fae80569d942dc6be03793,1505
|
5
|
-
llama_deploy/appserver/client/__init__.py,sha256=1675fd1c7fb675700396e35fb9c83df093cc7ebb8ca01a4df4447d95991542f4,49
|
6
|
-
llama_deploy/appserver/client/base.py,sha256=2d6e5b263b55b393bc3ff383109d868e3c7a1e298388958476ec028c810004cf,1137
|
7
|
-
llama_deploy/appserver/client/client.py,sha256=7af5ab5359ed4cd8802749461f213b7b646984108023592eb15a04904dd96211,1312
|
8
|
-
llama_deploy/appserver/client/models/__init__.py,sha256=d1cb7f4948b34831f88951d51b2bd63699ae60bee07dbcfe8d20c4c77719e213,142
|
9
|
-
llama_deploy/appserver/client/models/apiserver.py,sha256=f258710196b55b5dd3d157a4d112d98947932314e6024019919749dced063a19,12511
|
10
|
-
llama_deploy/appserver/client/models/model.py,sha256=1f81dff71866610735f30efa978182f568e6fec5eff262a73ad526ecf3ffba6b,2655
|
11
|
-
llama_deploy/appserver/deployment.py,sha256=184dfe95476dd8eea8d3d63b9fed60ed37136f6f38ffa8d8fa66be107ded4e31,19207
|
12
|
-
llama_deploy/appserver/deployment_config_parser.py,sha256=4b4e2f20336c3b46db5ae64fccb663a8f1c4f970d24daebc8362809ab665ff80,4032
|
13
|
-
llama_deploy/appserver/routers/__init__.py,sha256=f882ea036d83f8239de66b6a17ae0a51865402e115310960680adff8ded49dab,129
|
14
|
-
llama_deploy/appserver/routers/deployments.py,sha256=7839423ea6c4621ddf5e18d91394cf0caecb0f099779b79f8f199dfd8f2e7583,14570
|
15
|
-
llama_deploy/appserver/routers/status.py,sha256=17b12f37ac92092fa5494b0ea3477f512972c05fc23c5fa56dc498e8e6120c75,1400
|
16
|
-
llama_deploy/appserver/run_autodeploy.py,sha256=36316cbe2df413d374dcef013f90ed5774a02a2012576356160e22397ae91bed,5000
|
17
|
-
llama_deploy/appserver/server.py,sha256=68b8db645e3b7323c140d12607812d9d21382aef5a5a1609d3cf30429440eddf,1991
|
18
|
-
llama_deploy/appserver/settings.py,sha256=1f0bbc8e69edd4007b6be3988b3576699470a1fb06fd3a38d977ef45be1e688b,2891
|
19
|
-
llama_deploy/appserver/source_managers/__init__.py,sha256=d52f325a4c84f16cfb220337afddcc6145dcfebc44564dc665d33442480e8f84,175
|
20
|
-
llama_deploy/appserver/source_managers/base.py,sha256=f8ef6f6b851b39d37e7f5ddd631656a8d0e1015470adfc59a53699e83b33e533,1400
|
21
|
-
llama_deploy/appserver/source_managers/git.py,sha256=ba197235f18297a29895f23a2534040337eddd0c2046fed88ac7f2d0a3038415,1577
|
22
|
-
llama_deploy/appserver/source_managers/local.py,sha256=9e80d5f2a2247779e15c6a7b19ceef75dec7e9b0877ac350530d0f5d81ac2d3f,1690
|
23
|
-
llama_deploy/appserver/stats.py,sha256=1f3989f6705a6de3e4d61ee8cdd189fbe04a2c53ec5e720b2e5168acc331427f,691
|
24
|
-
llama_deploy/appserver/tracing.py,sha256=211e0695041f2ebf3a05471035fdcff582263b8150df2a459b54932bed9a9194,8199
|
25
|
-
llama_deploy/appserver/types.py,sha256=f9e1e037f196d7a55af06095404ed33c8620d5c95f61c8bc87df75b6e714897f,2237
|
26
|
-
llama_deploy_appserver-0.2.7a1.dist-info/WHEEL,sha256=cc8ae5806c5874a696cde0fcf78fdf73db4982e7c824f3ceab35e2b65182fa1a,79
|
27
|
-
llama_deploy_appserver-0.2.7a1.dist-info/METADATA,sha256=7b2c8925c464b72bf518926eb786afff346ff5bb1dad7caf254802ecf8350dd2,845
|
28
|
-
llama_deploy_appserver-0.2.7a1.dist-info/RECORD,,
|