llama-deploy-core 0.3.0a6__py3-none-any.whl → 0.3.0a8__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.
@@ -1 +1 @@
1
- DEFAULT_DEPLOYMENT_FILE_PATH = "llama_deploy.yaml"
1
+ DEFAULT_DEPLOYMENT_FILE_PATH = "."
@@ -1,11 +1,288 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import tomllib
1
5
  from pathlib import Path
2
6
  from typing import Any
3
7
 
4
8
  import yaml
5
- from pydantic import BaseModel, ConfigDict, Field, model_validator
9
+ from llama_deploy.core.path_util import validate_path_traversal
10
+ from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator
11
+
12
+ DEFAULT_DEPLOYMENT_NAME = "default"
13
+
14
+
15
+ def read_deployment_config(source_root: Path, config_path: Path) -> "DeploymentConfig":
16
+ """
17
+ Read the deployment config from the config directory.
18
+
19
+ - first checks for a llamadeploy.toml in the config_path
20
+ - then checks for a tool config in the pyproject.toml
21
+ - then check for a legacy yaml config (if config_path is a file, uses that, otherwise uses the config_path/llama_deploy.yaml)
22
+ - based on what was resolved here, discovers the package.json, if any ui, and resolves its values from the package.json
23
+
24
+ Args:
25
+ source_root: path to the root of the source code. References should not exit this directory.
26
+ config_path: path to a deployment config file, or directory containing a deployment config file.
27
+
28
+ Returns:
29
+ DeploymentConfig: the deployment config
30
+ """
31
+ config_file: Path | None = None
32
+ if (source_root / config_path).is_file():
33
+ config_file = Path(config_path.name)
34
+ if str(config_file) in {"llama_deploy.toml", "pyproject.toml"}:
35
+ config_file = None
36
+ config_path = config_path.parent
37
+ local_toml_path = source_root / config_path / "llama_deploy.toml"
38
+ pyproject_path = source_root / config_path / "pyproject.toml"
39
+ toml_config: DeploymentConfig = DeploymentConfig()
40
+ # local TOML format
41
+ if local_toml_path.exists():
42
+ with open(local_toml_path, "rb") as toml_file:
43
+ toml_data = tomllib.load(toml_file)
44
+ if isinstance(toml_data, dict):
45
+ toml_config = DeploymentConfig.model_validate(toml_data)
46
+ # pyproject.toml format
47
+ elif pyproject_path.exists():
48
+ with open(pyproject_path, "rb") as pyproject_file:
49
+ pyproject = tomllib.load(pyproject_file)
50
+ tool = pyproject.get("tool", {})
51
+ project_name: str | None = None
52
+ project_metadata = pyproject.get("project", {})
53
+ if isinstance(project_metadata, dict):
54
+ name = project_metadata.get("name")
55
+ if isinstance(name, str):
56
+ project_name = name
57
+ if isinstance(tool, dict):
58
+ llama_deploy = tool.get("llamadeploy", {})
59
+ if isinstance(llama_deploy, dict):
60
+ if "name" not in llama_deploy:
61
+ llama_deploy["name"] = project_name
62
+ toml_config = DeploymentConfig.model_validate(llama_deploy)
63
+ # legacy yaml format, (and why not support yaml in the new format too, since this is doing everything all the ways)
64
+ if toml_config.has_no_workflows():
65
+ yaml_path = (
66
+ source_root / config_path / (config_file or Path("llama_deploy.yaml"))
67
+ )
68
+ if yaml_path.exists():
69
+ with open(yaml_path, "r", encoding="utf-8") as yaml_file:
70
+ yaml_loaded = yaml.safe_load(yaml_file) or {}
71
+
72
+ old_config: DeploymentConfig | None = None
73
+ new_config: DeploymentConfig | None = None
74
+ try:
75
+ old_config = DeprecatedDeploymentConfig.model_validate(
76
+ yaml_loaded
77
+ ).to_deployment_config()
78
+ except ValidationError:
79
+ pass
80
+ try:
81
+ new_config = DeploymentConfig.model_validate(yaml_loaded)
82
+ except ValidationError:
83
+ pass
84
+ loaded: DeploymentConfig | None = new_config
85
+ if (
86
+ old_config is not None
87
+ and old_config.is_valid()
88
+ and (new_config is None or not new_config.is_valid())
89
+ ):
90
+ loaded = old_config
91
+ if loaded is not None:
92
+ toml_config = toml_config.merge_config(loaded)
93
+
94
+ # package.json format
95
+ if toml_config.ui is not None:
96
+ package_json_path = (
97
+ source_root / config_path / toml_config.ui.directory / "package.json"
98
+ )
99
+ if package_json_path.exists():
100
+ with open(package_json_path, "r", encoding="utf-8") as package_json_file:
101
+ package_json = json.load(package_json_file)
102
+ if isinstance(package_json, dict):
103
+ # Standard packageManager fallback, e.g. "pnpm@9.0.0" -> "pnpm"
104
+ pkg_manager_value = package_json.get("packageManager")
105
+ pkg_manager_name: str | None = None
106
+ if isinstance(pkg_manager_value, str) and pkg_manager_value:
107
+ pkg_manager_name = pkg_manager_value.split("@", 1)[0] or None
108
+
109
+ llama_deploy = package_json.get("llamadeploy", {})
110
+
111
+ if isinstance(llama_deploy, dict):
112
+ # Prepare payload without leaking Path objects into Pydantic
113
+ ui_dir = toml_config.ui.directory if toml_config.ui else None
114
+ ui_payload: dict[str, object] = {**llama_deploy}
115
+ if "directory" not in ui_payload and ui_dir is not None:
116
+ ui_payload["directory"] = ui_dir
117
+ if (
118
+ "package_manager" not in ui_payload
119
+ and pkg_manager_name is not None
120
+ ):
121
+ ui_payload["package_manager"] = pkg_manager_name
122
+
123
+ ui_config = UIConfig.model_validate(ui_payload)
124
+ if ui_config.build_output_dir is not None:
125
+ ui_config.build_output_dir = str(
126
+ Path(toml_config.ui.directory) / ui_config.build_output_dir
127
+ )
128
+ toml_config.ui = ui_config.merge_config(toml_config.ui)
129
+
130
+ if toml_config.ui is not None:
131
+ validate_path_traversal(
132
+ config_path / toml_config.ui.directory, source_root, "ui_source"
133
+ )
134
+ if toml_config.ui.build_output_dir:
135
+ validate_path_traversal(
136
+ config_path / toml_config.ui.build_output_dir,
137
+ source_root,
138
+ "ui_build_output_dir",
139
+ )
140
+
141
+ return toml_config
142
+
143
+
144
+ def resolve_config_parent(root: Path, deployment_path: Path) -> Path:
145
+ path = root / deployment_path
146
+ if path.is_file():
147
+ return path.parent
148
+ else:
149
+ return path
150
+
151
+
152
+ DEFAULT_UI_PACKAGE_MANAGER = "npm"
153
+ DEFAULT_UI_BUILD_COMMAND = "build"
154
+ DEFAULT_UI_SERVE_COMMAND = "dev"
155
+ DEFAULT_UI_PROXY_PORT = 4502
156
+
157
+
158
+ class DeploymentConfig(BaseModel):
159
+ name: str = Field(
160
+ default=DEFAULT_DEPLOYMENT_NAME,
161
+ description="The url safe path name of the deployment.",
162
+ )
163
+ app: str | None = Field(
164
+ None,
165
+ description="A full bundle of all workflows as an 'app'. \"path.to_import:app_name\"",
166
+ )
167
+ workflows: dict[str, str] = Field(
168
+ default_factory=dict,
169
+ description='Deprecated: A map of workflow names to their import paths. "nice_name": "path.to_import:workflow_name"',
170
+ )
171
+ env_files: list[str] = Field(
172
+ default_factory=list,
173
+ description="The environment files to load. Defaults to ['.env']",
174
+ )
175
+ env: dict[str, str] = Field(
176
+ default_factory=dict,
177
+ description="Arbitrary environment variables to set. Defaults to {}",
178
+ )
179
+ ui: UIConfig | None = Field(
180
+ None,
181
+ description="The UI configuration.",
182
+ )
183
+
184
+ def merge_config(self, config: "DeploymentConfig") -> "DeploymentConfig":
185
+ """Merge the config with another config."""
6
186
 
187
+ return DeploymentConfig(
188
+ name=_pick_non_default(self.name, config.name, "default"),
189
+ app=self.app or config.app,
190
+ workflows={**self.workflows, **config.workflows},
191
+ env_files=list(set(self.env_files + config.env_files)),
192
+ env={**self.env, **config.env},
193
+ ui=self.ui.merge_config(config.ui)
194
+ if config.ui is not None and self.ui is not None
195
+ else self.ui or config.ui,
196
+ )
7
197
 
8
- class ServiceSource(BaseModel):
198
+ def has_no_workflows(self) -> bool:
199
+ """Check if the config has no workflows."""
200
+ return len(self.workflows) == 0 and self.app is None
201
+
202
+ def has_both_app_and_workflows(self) -> bool:
203
+ """Check if the config has both app and workflows."""
204
+ return self.app is not None and len(self.workflows) > 0
205
+
206
+ def is_valid(self) -> bool:
207
+ """Check if the config is valid."""
208
+ try:
209
+ self.validate()
210
+ return True
211
+ except ValueError:
212
+ return False
213
+
214
+ def validate(self) -> None:
215
+ """Validate the config."""
216
+ if self.has_no_workflows():
217
+ raise ValueError("Config must have at least one workflow.")
218
+ if self.has_both_app_and_workflows():
219
+ raise ValueError("Config cannot have both app and workflows configured.")
220
+
221
+ def build_output_path(self) -> Path | None:
222
+ """get the build output path, or default to the ui directory/dist"""
223
+ if self.ui is None:
224
+ return None
225
+ return (
226
+ Path(self.ui.build_output_dir)
227
+ if self.ui.build_output_dir
228
+ else Path(self.ui.directory) / "dist"
229
+ )
230
+
231
+
232
+ def _pick_non_default[T](a: T, b: T, default: T) -> T:
233
+ if a != default:
234
+ return a
235
+ return b or default
236
+
237
+
238
+ class UIConfig(BaseModel):
239
+ directory: str = Field(
240
+ ...,
241
+ description="The directory containing the UI, relative to the pyproject.toml directory",
242
+ )
243
+ build_output_dir: str | None = Field(
244
+ None,
245
+ description="The directory containing the built UI, relative to the pyproject.toml directory. Defaults to 'dist' relative to the ui_directory, if defined",
246
+ )
247
+ package_manager: str = Field(
248
+ DEFAULT_UI_PACKAGE_MANAGER,
249
+ description=f"The package manager to use to build the UI. Defaults to '{DEFAULT_UI_PACKAGE_MANAGER}'",
250
+ )
251
+ build_command: str = Field(
252
+ DEFAULT_UI_BUILD_COMMAND,
253
+ description=f"The npm script command to build the UI. Defaults to '{DEFAULT_UI_BUILD_COMMAND}' if not specified",
254
+ )
255
+ serve_command: str = Field(
256
+ DEFAULT_UI_SERVE_COMMAND,
257
+ description=f"The command to serve the UI. Defaults to '{DEFAULT_UI_SERVE_COMMAND}' if not specified",
258
+ )
259
+ proxy_port: int = Field(
260
+ DEFAULT_UI_PROXY_PORT,
261
+ description=f"The port to proxy the UI to. Defaults to '{DEFAULT_UI_PROXY_PORT}' if not specified",
262
+ )
263
+
264
+ def merge_config(self, config: "UIConfig") -> "UIConfig":
265
+ """Merge the config with the default config."""
266
+
267
+ return UIConfig(
268
+ directory=self.directory,
269
+ build_output_dir=self.build_output_dir or config.build_output_dir,
270
+ package_manager=_pick_non_default(
271
+ self.package_manager, config.package_manager, DEFAULT_UI_PACKAGE_MANAGER
272
+ ),
273
+ build_command=_pick_non_default(
274
+ self.build_command, config.build_command, DEFAULT_UI_BUILD_COMMAND
275
+ ),
276
+ serve_command=_pick_non_default(
277
+ self.serve_command, config.serve_command, DEFAULT_UI_SERVE_COMMAND
278
+ ),
279
+ proxy_port=_pick_non_default(
280
+ self.proxy_port, config.proxy_port, DEFAULT_UI_PROXY_PORT
281
+ ),
282
+ )
283
+
284
+
285
+ class ServiceSourceV0(BaseModel):
9
286
  """Configuration for where to load the workflow or other source. Path is relative to the config file its declared within."""
10
287
 
11
288
  location: str
@@ -19,10 +296,10 @@ class ServiceSource(BaseModel):
19
296
  return data
20
297
 
21
298
 
22
- class Service(BaseModel):
299
+ class DerecatedService(BaseModel):
23
300
  """Configuration for a single service."""
24
301
 
25
- source: ServiceSource | None = Field(None)
302
+ source: ServiceSourceV0 | None = Field(None)
26
303
  import_path: str | None = Field(None)
27
304
  env: dict[str, str] | None = Field(None)
28
305
  env_files: list[str] | None = Field(None)
@@ -54,22 +331,15 @@ class Service(BaseModel):
54
331
  return Path(module_name).name, workflow_name
55
332
 
56
333
 
57
- class UIService(Service):
58
- port: int = Field(
59
- default=3000,
60
- description="The TCP port to use for the nextjs server",
61
- )
62
-
63
-
64
- class DeploymentConfig(BaseModel):
334
+ class DeprecatedDeploymentConfig(BaseModel):
65
335
  """Model definition mapping a deployment config file."""
66
336
 
67
337
  model_config = ConfigDict(populate_by_name=True, extra="ignore")
68
338
 
69
339
  name: str
70
340
  default_service: str | None = Field(None)
71
- services: dict[str, Service]
72
- ui: UIService | None = None
341
+ services: dict[str, DerecatedService]
342
+ ui: DerecatedService | None = None
73
343
 
74
344
  @model_validator(mode="before")
75
345
  @classmethod
@@ -82,18 +352,42 @@ class DeploymentConfig(BaseModel):
82
352
  return data
83
353
 
84
354
  @classmethod
85
- def from_yaml_bytes(cls, src: bytes) -> "DeploymentConfig":
86
- """Read config data from bytes containing yaml code."""
87
- config = yaml.safe_load(src) or {}
88
- return cls(**config)
89
-
90
- @classmethod
91
- def from_yaml(cls, path: Path, name: str | None = None) -> "DeploymentConfig":
355
+ def from_yaml(
356
+ cls,
357
+ path: Path,
358
+ ) -> "DeprecatedDeploymentConfig":
92
359
  """Read config data from a yaml file."""
93
360
  with open(path, "r", encoding="utf-8") as yaml_file:
94
361
  config = yaml.safe_load(yaml_file) or {}
95
362
 
96
- instance = cls(**config)
97
- if name:
98
- instance.name = name
363
+ instance = cls.model_validate(config)
99
364
  return instance
365
+
366
+ def to_deployment_config(self) -> DeploymentConfig:
367
+ """Convert the deployment config to a DeploymentConfig."""
368
+ workflows = {}
369
+ env_files = []
370
+ env = {}
371
+ ui_directory: str | None = None
372
+ for service_name, service in self.services.items():
373
+ if service.import_path:
374
+ path, name = service.module_location()
375
+ workflows[service_name] = f"{path}:{name}"
376
+ if service.env_files:
377
+ env_files.extend(service.env_files)
378
+ if service.env:
379
+ env.update(service.env)
380
+ if self.default_service:
381
+ workflows["default"] = workflows[self.default_service]
382
+ env_files = list(set(env_files))
383
+
384
+ if self.ui:
385
+ ui_directory = self.ui.source.location
386
+
387
+ return DeploymentConfig(
388
+ name=self.name,
389
+ workflows=workflows,
390
+ env_files=env_files,
391
+ env=env,
392
+ ui=UIConfig(directory=ui_directory) if ui_directory else None,
393
+ )
@@ -261,3 +261,11 @@ def get_current_branch() -> str | None:
261
261
  """
262
262
  result = _run_process(["git", "branch", "--show-current"])
263
263
  return result.strip() if result.strip() else None
264
+
265
+
266
+ def get_git_root() -> Path:
267
+ """
268
+ get the root of the current git repo
269
+ """
270
+ result = _run_process(["git", "rev-parse", "--show-toplevel"])
271
+ return Path(result.strip())
@@ -0,0 +1,24 @@
1
+ from pathlib import Path
2
+
3
+
4
+ def validate_path_traversal(
5
+ path: Path, source_root: Path, path_type: str = "path"
6
+ ) -> None:
7
+ """Validates that a path is within the source root to prevent path traversal attacks.
8
+
9
+ Args:
10
+ path: The path to validate
11
+ source_root: The root directory that paths should be relative to
12
+ path_type: Description of the path type for error messages
13
+
14
+ Raises:
15
+ DeploymentError: If the path is outside the source root
16
+ """
17
+ resolved_path = (source_root / path).resolve()
18
+ resolved_source_root = source_root.resolve()
19
+
20
+ if not resolved_path.is_relative_to(resolved_source_root):
21
+ msg = (
22
+ f"{path_type} {path} is not a subdirectory of the source root {source_root}"
23
+ )
24
+ raise RuntimeError(msg)
@@ -1,4 +1,4 @@
1
- from .base import Base
1
+ from .base import Base, LogEvent
2
2
  from .deployments import (
3
3
  DeploymentCreate,
4
4
  DeploymentResponse,
@@ -13,6 +13,7 @@ from .projects import ProjectsListResponse, ProjectSummary
13
13
 
14
14
  __all__ = [
15
15
  "Base",
16
+ "LogEvent",
16
17
  "DeploymentCreate",
17
18
  "DeploymentResponse",
18
19
  "DeploymentUpdate",
@@ -1,3 +1,5 @@
1
+ from datetime import datetime
2
+
1
3
  from pydantic import BaseModel, ConfigDict
2
4
 
3
5
  base_config = ConfigDict(
@@ -18,3 +20,10 @@ base_config = ConfigDict(
18
20
 
19
21
  class Base(BaseModel):
20
22
  model_config = base_config
23
+
24
+
25
+ class LogEvent(Base):
26
+ pod: str
27
+ container: str
28
+ text: str
29
+ timestamp: datetime
@@ -30,6 +30,7 @@ class DeploymentResponse(Base):
30
30
  secret_names: list[str] | None = None
31
31
  apiserver_url: HttpUrl | None
32
32
  status: LlamaDeploymentPhase
33
+ warning: str | None = None
33
34
 
34
35
 
35
36
  class DeploymentsListResponse(Base):
@@ -65,7 +66,7 @@ class LlamaDeploymentSpec(Base):
65
66
 
66
67
  projectId: str
67
68
  repoUrl: str
68
- deploymentFilePath: str = "llama_deploy.yaml"
69
+ deploymentFilePath: str = "."
69
70
  gitRef: str | None = None
70
71
  gitSha: str | None = None
71
72
  name: str
@@ -164,7 +165,6 @@ def apply_deployment_update(
164
165
  updated_spec.staticAssetsPath = (
165
166
  str(update.static_assets_path) if update.static_assets_path else None
166
167
  )
167
- print(f"staticAssetsPath: {updated_spec.staticAssetsPath}")
168
168
 
169
169
  # Track secret changes
170
170
  secret_adds: dict[str, str] = {}
@@ -1,5 +1,4 @@
1
1
  from pathlib import Path
2
- from typing import Optional
3
2
 
4
3
  from pydantic import BaseModel, Field
5
4
 
@@ -10,8 +10,7 @@ def resolve_ui_root(config_parent: Path, config: DeploymentConfig) -> Path | Non
10
10
  """Return the absolute path to the UI root if UI is configured; otherwise None."""
11
11
  if config.ui is None:
12
12
  return None
13
- rel = config.ui.source.location if config.ui.source else "."
14
- return (config_parent / rel).resolve()
13
+ return (config_parent / config.ui.directory).resolve()
15
14
 
16
15
 
17
16
  def ui_build_output_path(config_parent: Path, config: DeploymentConfig) -> Path | None:
@@ -20,22 +19,26 @@ def ui_build_output_path(config_parent: Path, config: DeploymentConfig) -> Path
20
19
  Right now, assumes its just `/dist` in the UI root.
21
20
 
22
21
  Returns:
23
- - True if a package.json exists and contains a "build" script
24
- - False if a package.json exists but lacks a "build" script
22
+ - Path to the build output directory if a package.json exists and contains a "build" script
25
23
  - None if there is no UI configured or no package.json exists
26
24
  """
27
25
  ui_root = resolve_ui_root(config_parent, config)
28
26
  if ui_root is None:
29
27
  return None
28
+ if config.ui is None:
29
+ return None
30
30
  package_json = ui_root / "package.json"
31
31
  if not package_json.exists():
32
32
  return None
33
33
  try:
34
34
  with open(package_json, "r", encoding="utf-8") as f:
35
35
  pkg = json.load(f)
36
+ if not isinstance(pkg, dict):
37
+ return None
36
38
  scripts = pkg.get("scripts", {}) or {}
37
- if "build" in scripts:
38
- return (ui_root / "dist").relative_to(config_parent)
39
+ if config.ui.build_command in scripts:
40
+ return config.build_output_path()
41
+ return None
39
42
  except Exception:
40
43
  # Do not raise for malformed package.json in validation contexts
41
44
  return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: llama-deploy-core
3
- Version: 0.3.0a6
3
+ Version: 0.3.0a8
4
4
  Summary: Core models and schemas for LlamaDeploy
5
5
  License: MIT
6
6
  Requires-Dist: pydantic>=2.0.0
@@ -0,0 +1,14 @@
1
+ llama_deploy/core/__init__.py,sha256=112612bf2e928c2e0310d6556bb13fc28c00db70297b90a8527486cd2562e408,43
2
+ llama_deploy/core/config.py,sha256=69bb0ea8ac169eaa4e808cd60a098b616bddd3145d26c6c35e56db38496b0e6a,35
3
+ llama_deploy/core/deployment_config.py,sha256=ff10cc96f2c64abc4761eb83c5372fd22f3770159b45503818264723b578de4e,15092
4
+ llama_deploy/core/git/git_util.py,sha256=c581c1da13871b4e89eda58f56ddb074139454c06ae9b04c0b396fdb2b9a5176,9193
5
+ llama_deploy/core/path_util.py,sha256=14d50c0c337c8450ed46cafc88436027056b365a48370a69cdb76c88d7c26fd1,798
6
+ llama_deploy/core/schema/__init__.py,sha256=cc60a6fb54983d7ca13e2cc86d414a0d006a79c20e44344701f9fbe3b1d21577,739
7
+ llama_deploy/core/schema/base.py,sha256=c02e33e35e7e4540b3065a82267febeb6da169222210a1d1c2479f6a7f1c6a4b,802
8
+ llama_deploy/core/schema/deployments.py,sha256=fe4c540d39a3e369e3fa286df128398043f591ddc4a623ccb2d432596c53dca6,6108
9
+ llama_deploy/core/schema/git_validation.py,sha256=27b306aa6ecabe58cab6381d92551545f263fe7550c58b3087115410bc71fd21,1915
10
+ llama_deploy/core/schema/projects.py,sha256=c97eda38207d80354c2ee3a237cba9c3f6838148197cfa2d97b9a18d3da1a38b,294
11
+ llama_deploy/core/ui_build.py,sha256=290dafa951918e5593b9035570fa4c66791d7e5ea785bd372ad11e99e8283857,1514
12
+ llama_deploy_core-0.3.0a8.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
13
+ llama_deploy_core-0.3.0a8.dist-info/METADATA,sha256=f5fe24509ec6739b64202009cd19dc590052aa2a35cddf114ba985e430969993,402
14
+ llama_deploy_core-0.3.0a8.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- llama_deploy/core/__init__.py,sha256=112612bf2e928c2e0310d6556bb13fc28c00db70297b90a8527486cd2562e408,43
2
- llama_deploy/core/config.py,sha256=41c5a1baa25a67f0bb58b701ef8f0b8b3281714d7116580b8f87674eb9e396a3,51
3
- llama_deploy/core/deployment_config.py,sha256=2907106ca4cb504fda407bf2c7b1114a50ed12da00b3876e4340016f2ffbb78d,3143
4
- llama_deploy/core/git/git_util.py,sha256=d3a57ce6c8bce3da26bd554df222988ea02fb1e20f3f5192dad69a2bbd1395a4,9007
5
- llama_deploy/core/schema/__init__.py,sha256=3e838d5304bc1f11c42590ba78267405e957e11add783e280d00bf5766728072,713
6
- llama_deploy/core/schema/base.py,sha256=2de6d23e58c36b6bb311ec0aea4b902661867056c1250c6b7ce3bad17141fe15,677
7
- llama_deploy/core/schema/deployments.py,sha256=b23a458f71cebc4b13ab32e922ba6759dcb7f69eeca2b5e28cda10766a109251,6157
8
- llama_deploy/core/schema/git_validation.py,sha256=ce58491992252fd0bba6dcf3fc776f57995eb407a531aeb0a050a4f0587f6e50,1943
9
- llama_deploy/core/schema/projects.py,sha256=c97eda38207d80354c2ee3a237cba9c3f6838148197cfa2d97b9a18d3da1a38b,294
10
- llama_deploy/core/ui_build.py,sha256=88226f6f2b9a91b86de7d4c49024ef254d946b6519057712bb51bcae8a8deaeb,1472
11
- llama_deploy_core-0.3.0a6.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
12
- llama_deploy_core-0.3.0a6.dist-info/METADATA,sha256=fb6f43d57436b11908fa44388c04c3326e3322b3329a4941522ac3032dfb251c,402
13
- llama_deploy_core-0.3.0a6.dist-info/RECORD,,