agentex-sdk 0.8.1__py3-none-any.whl → 0.8.2__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.
- agentex/_version.py +1 -1
- agentex/lib/cli/commands/agents.py +44 -73
- agentex/lib/sdk/config/environment_config.py +113 -73
- agentex/lib/sdk/config/validation.py +62 -61
- {agentex_sdk-0.8.1.dist-info → agentex_sdk-0.8.2.dist-info}/METADATA +1 -1
- {agentex_sdk-0.8.1.dist-info → agentex_sdk-0.8.2.dist-info}/RECORD +9 -9
- {agentex_sdk-0.8.1.dist-info → agentex_sdk-0.8.2.dist-info}/licenses/LICENSE +1 -1
- {agentex_sdk-0.8.1.dist-info → agentex_sdk-0.8.2.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.8.1.dist-info → agentex_sdk-0.8.2.dist-info}/entry_points.txt +0 -0
agentex/_version.py
CHANGED
|
@@ -83,26 +83,24 @@ def delete(
|
|
|
83
83
|
@agents.command()
|
|
84
84
|
def cleanup_workflows(
|
|
85
85
|
agent_name: str = typer.Argument(..., help="Name of the agent to cleanup workflows for"),
|
|
86
|
-
force: bool = typer.Option(
|
|
86
|
+
force: bool = typer.Option(
|
|
87
|
+
False, help="Force cleanup using direct Temporal termination (bypasses development check)"
|
|
88
|
+
),
|
|
87
89
|
):
|
|
88
90
|
"""
|
|
89
91
|
Clean up all running workflows for an agent.
|
|
90
|
-
|
|
92
|
+
|
|
91
93
|
By default, uses graceful cancellation via agent RPC.
|
|
92
94
|
With --force, directly terminates workflows via Temporal client.
|
|
93
95
|
This is a convenience command that does the same thing as 'agentex tasks cleanup'.
|
|
94
96
|
"""
|
|
95
97
|
try:
|
|
96
98
|
console.print(f"[blue]Cleaning up workflows for agent '{agent_name}'...[/blue]")
|
|
97
|
-
|
|
98
|
-
cleanup_agent_workflows(
|
|
99
|
-
|
|
100
|
-
force=force,
|
|
101
|
-
development_only=True
|
|
102
|
-
)
|
|
103
|
-
|
|
99
|
+
|
|
100
|
+
cleanup_agent_workflows(agent_name=agent_name, force=force, development_only=True)
|
|
101
|
+
|
|
104
102
|
console.print(f"[green]✓ Workflow cleanup completed for agent '{agent_name}'[/green]")
|
|
105
|
-
|
|
103
|
+
|
|
106
104
|
except Exception as e:
|
|
107
105
|
console.print(f"[red]Cleanup failed: {str(e)}[/red]")
|
|
108
106
|
logger.exception("Agent workflow cleanup failed")
|
|
@@ -112,12 +110,8 @@ def cleanup_workflows(
|
|
|
112
110
|
@agents.command()
|
|
113
111
|
def build(
|
|
114
112
|
manifest: str = typer.Option(..., help="Path to the manifest you want to use"),
|
|
115
|
-
registry: str | None = typer.Option(
|
|
116
|
-
|
|
117
|
-
),
|
|
118
|
-
repository_name: str | None = typer.Option(
|
|
119
|
-
None, help="Repository name to use for the built image"
|
|
120
|
-
),
|
|
113
|
+
registry: str | None = typer.Option(None, help="Registry URL for pushing the built image"),
|
|
114
|
+
repository_name: str | None = typer.Option(None, help="Repository name to use for the built image"),
|
|
121
115
|
platforms: str | None = typer.Option(
|
|
122
116
|
None, help="Platform to build the image for. Please enter a comma separated list of platforms."
|
|
123
117
|
),
|
|
@@ -126,9 +120,7 @@ def build(
|
|
|
126
120
|
None,
|
|
127
121
|
help="Docker build secret in the format 'id=secret-id,src=path-to-secret-file'",
|
|
128
122
|
),
|
|
129
|
-
tag: str | None = typer.Option(
|
|
130
|
-
None, help="Image tag to use (defaults to 'latest')"
|
|
131
|
-
),
|
|
123
|
+
tag: str | None = typer.Option(None, help="Image tag to use (defaults to 'latest')"),
|
|
132
124
|
build_arg: builtins.list[str] | None = typer.Option( # noqa: B008
|
|
133
125
|
None,
|
|
134
126
|
help="Docker build argument in the format 'KEY=VALUE' (can be used multiple times)",
|
|
@@ -143,7 +135,7 @@ def build(
|
|
|
143
135
|
if push and not registry:
|
|
144
136
|
typer.echo("Error: --registry is required when --push is enabled", err=True)
|
|
145
137
|
raise typer.Exit(1)
|
|
146
|
-
|
|
138
|
+
|
|
147
139
|
# Only proceed with build if we have a registry (for now, to match existing behavior)
|
|
148
140
|
if not registry:
|
|
149
141
|
typer.echo("No registry provided, skipping image build")
|
|
@@ -175,10 +167,7 @@ def build(
|
|
|
175
167
|
@agents.command()
|
|
176
168
|
def run(
|
|
177
169
|
manifest: str = typer.Option(..., help="Path to the manifest you want to use"),
|
|
178
|
-
cleanup_on_start: bool = typer.Option(
|
|
179
|
-
False,
|
|
180
|
-
help="Clean up existing workflows for this agent before starting"
|
|
181
|
-
),
|
|
170
|
+
cleanup_on_start: bool = typer.Option(False, help="Clean up existing workflows for this agent before starting"),
|
|
182
171
|
# Debug options
|
|
183
172
|
debug: bool = typer.Option(False, help="Enable debug mode for both worker and ACP (disables auto-reload)"),
|
|
184
173
|
debug_worker: bool = typer.Option(False, help="Enable debug mode for temporal worker only"),
|
|
@@ -190,26 +179,22 @@ def run(
|
|
|
190
179
|
Run an agent locally from the given manifest.
|
|
191
180
|
"""
|
|
192
181
|
typer.echo(f"Running agent from manifest: {manifest}")
|
|
193
|
-
|
|
182
|
+
|
|
194
183
|
# Optionally cleanup existing workflows before starting
|
|
195
184
|
if cleanup_on_start:
|
|
196
185
|
try:
|
|
197
186
|
# Parse manifest to get agent name
|
|
198
187
|
manifest_obj = AgentManifest.from_yaml(file_path=manifest)
|
|
199
188
|
agent_name = manifest_obj.agent.name
|
|
200
|
-
|
|
189
|
+
|
|
201
190
|
console.print(f"[yellow]Cleaning up existing workflows for agent '{agent_name}'...[/yellow]")
|
|
202
|
-
cleanup_agent_workflows(
|
|
203
|
-
agent_name=agent_name,
|
|
204
|
-
force=False,
|
|
205
|
-
development_only=True
|
|
206
|
-
)
|
|
191
|
+
cleanup_agent_workflows(agent_name=agent_name, force=False, development_only=True)
|
|
207
192
|
console.print("[green]✓ Pre-run cleanup completed[/green]")
|
|
208
|
-
|
|
193
|
+
|
|
209
194
|
except Exception as e:
|
|
210
195
|
console.print(f"[yellow]⚠ Pre-run cleanup failed: {str(e)}[/yellow]")
|
|
211
196
|
logger.warning(f"Pre-run cleanup failed: {e}")
|
|
212
|
-
|
|
197
|
+
|
|
213
198
|
# Create debug configuration based on CLI flags
|
|
214
199
|
debug_config = None
|
|
215
200
|
if debug or debug_worker or debug_acp:
|
|
@@ -224,19 +209,19 @@ def run(
|
|
|
224
209
|
mode = DebugMode.ACP
|
|
225
210
|
else:
|
|
226
211
|
mode = DebugMode.NONE
|
|
227
|
-
|
|
212
|
+
|
|
228
213
|
debug_config = DebugConfig(
|
|
229
214
|
enabled=True,
|
|
230
215
|
mode=mode,
|
|
231
216
|
port=debug_port,
|
|
232
217
|
wait_for_attach=wait_for_debugger,
|
|
233
|
-
auto_port=False # Use fixed port to match VS Code launch.json
|
|
218
|
+
auto_port=False, # Use fixed port to match VS Code launch.json
|
|
234
219
|
)
|
|
235
|
-
|
|
220
|
+
|
|
236
221
|
console.print(f"[blue]🐛 Debug mode enabled: {mode.value}[/blue]")
|
|
237
222
|
if wait_for_debugger:
|
|
238
223
|
console.print("[yellow]⏳ Processes will wait for debugger attachment[/yellow]")
|
|
239
|
-
|
|
224
|
+
|
|
240
225
|
try:
|
|
241
226
|
run_agent(manifest_path=manifest, debug_config=debug_config)
|
|
242
227
|
except Exception as e:
|
|
@@ -247,30 +232,23 @@ def run(
|
|
|
247
232
|
|
|
248
233
|
@agents.command()
|
|
249
234
|
def deploy(
|
|
250
|
-
cluster: str = typer.Option(
|
|
251
|
-
..., help="Target cluster name (must match kubectl context)"
|
|
252
|
-
),
|
|
235
|
+
cluster: str = typer.Option(..., help="Target cluster name (must match kubectl context)"),
|
|
253
236
|
manifest: str = typer.Option("manifest.yaml", help="Path to the manifest file"),
|
|
254
237
|
namespace: str | None = typer.Option(
|
|
255
238
|
None,
|
|
256
239
|
help="Override Kubernetes namespace (defaults to namespace from environments.yaml)",
|
|
257
240
|
),
|
|
258
241
|
environment: str | None = typer.Option(
|
|
259
|
-
None,
|
|
260
|
-
|
|
261
|
-
tag: str | None = typer.Option(None, help="Override the image tag for deployment"),
|
|
262
|
-
repository: str | None = typer.Option(
|
|
263
|
-
None, help="Override the repository for deployment"
|
|
264
|
-
),
|
|
265
|
-
interactive: bool = typer.Option(
|
|
266
|
-
True, "--interactive/--no-interactive", help="Enable interactive prompts"
|
|
242
|
+
None,
|
|
243
|
+
help="Environment name (dev, prod, etc.) - must be defined in environments.yaml. If not provided, the namespace must be set explicitly.",
|
|
267
244
|
),
|
|
245
|
+
tag: str | None = typer.Option(None, help="Override the image tag for deployment"),
|
|
246
|
+
repository: str | None = typer.Option(None, help="Override the repository for deployment"),
|
|
247
|
+
interactive: bool = typer.Option(True, "--interactive/--no-interactive", help="Enable interactive prompts"),
|
|
268
248
|
):
|
|
269
249
|
"""Deploy an agent to a Kubernetes cluster using Helm"""
|
|
270
250
|
|
|
271
|
-
console.print(
|
|
272
|
-
Panel.fit("🚀 [bold blue]Deploy Agent[/bold blue]", border_style="blue")
|
|
273
|
-
)
|
|
251
|
+
console.print(Panel.fit("🚀 [bold blue]Deploy Agent[/bold blue]", border_style="blue"))
|
|
274
252
|
|
|
275
253
|
try:
|
|
276
254
|
# Validate manifest exists
|
|
@@ -281,17 +259,12 @@ def deploy(
|
|
|
281
259
|
|
|
282
260
|
# Validate manifest and environments configuration
|
|
283
261
|
try:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
console.print(f"[green]✓[/green] Environment config validated: {environment}")
|
|
291
|
-
else:
|
|
292
|
-
agent_env_config = None
|
|
293
|
-
console.print(f"[yellow]⚠[/yellow] No environment provided, skipping environment-specific config")
|
|
294
|
-
|
|
262
|
+
_, environments_config = validate_manifest_and_environments(
|
|
263
|
+
str(manifest_path), required_environment=environment
|
|
264
|
+
)
|
|
265
|
+
agent_env_config = environments_config.get_config_for_env(environment)
|
|
266
|
+
console.print(f"[green]✓[/green] Environment config validated: {environment}")
|
|
267
|
+
|
|
295
268
|
except EnvironmentsValidationError as e:
|
|
296
269
|
error_msg = generate_helpful_error_message(e, "Environment validation failed")
|
|
297
270
|
console.print(f"[red]Configuration Error:[/red]\n{error_msg}")
|
|
@@ -310,9 +283,13 @@ def deploy(
|
|
|
310
283
|
console.print(f"[blue]ℹ[/blue] Using namespace from environments.yaml: {namespace_from_config}")
|
|
311
284
|
namespace = namespace_from_config
|
|
312
285
|
else:
|
|
313
|
-
raise DeploymentError(
|
|
286
|
+
raise DeploymentError(
|
|
287
|
+
f"No namespace found in environments.yaml for environment: {environment}, and not passed in as --namespace"
|
|
288
|
+
)
|
|
314
289
|
elif not namespace:
|
|
315
|
-
raise DeploymentError(
|
|
290
|
+
raise DeploymentError(
|
|
291
|
+
"No namespace provided, and not passed in as --namespace and no environment provided to read from an environments.yaml file"
|
|
292
|
+
)
|
|
316
293
|
|
|
317
294
|
# Confirm deployment (only in interactive mode)
|
|
318
295
|
console.print("\n[bold]Deployment Summary:[/bold]")
|
|
@@ -325,9 +302,7 @@ def deploy(
|
|
|
325
302
|
|
|
326
303
|
if interactive:
|
|
327
304
|
proceed = questionary.confirm("Proceed with deployment?").ask()
|
|
328
|
-
proceed = handle_questionary_cancellation(
|
|
329
|
-
proceed, "deployment confirmation"
|
|
330
|
-
)
|
|
305
|
+
proceed = handle_questionary_cancellation(proceed, "deployment confirmation")
|
|
331
306
|
|
|
332
307
|
if not proceed:
|
|
333
308
|
console.print("Deployment cancelled")
|
|
@@ -337,9 +312,7 @@ def deploy(
|
|
|
337
312
|
|
|
338
313
|
check_and_switch_cluster_context(cluster)
|
|
339
314
|
if not validate_namespace(namespace, cluster):
|
|
340
|
-
console.print(
|
|
341
|
-
f"[red]Error:[/red] Namespace '{namespace}' does not exist in cluster '{cluster}'"
|
|
342
|
-
)
|
|
315
|
+
console.print(f"[red]Error:[/red] Namespace '{namespace}' does not exist in cluster '{cluster}'")
|
|
343
316
|
raise typer.Exit(1)
|
|
344
317
|
|
|
345
318
|
deploy_overrides = InputDeployOverrides(repository=repository, image_tag=tag)
|
|
@@ -356,9 +329,7 @@ def deploy(
|
|
|
356
329
|
# Use the already loaded manifest object
|
|
357
330
|
release_name = f"{manifest_obj.agent.name}-{cluster}"
|
|
358
331
|
|
|
359
|
-
console.print(
|
|
360
|
-
"\n[bold green]🎉 Deployment completed successfully![/bold green]"
|
|
361
|
-
)
|
|
332
|
+
console.print("\n[bold green]🎉 Deployment completed successfully![/bold green]")
|
|
362
333
|
console.print("\nTo check deployment status:")
|
|
363
334
|
console.print(f" kubectl get pods -n {namespace}")
|
|
364
335
|
console.print(f" helm status {release_name} -n {namespace}")
|
|
@@ -18,13 +18,12 @@ from agentex.lib.utils.model_utils import BaseModel as UtilsBaseModel
|
|
|
18
18
|
|
|
19
19
|
class AgentAuthConfig(BaseModel):
|
|
20
20
|
"""Authentication configuration for an agent in a specific environment."""
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
principal: Dict[str, Any] = Field(
|
|
23
|
-
...,
|
|
24
|
-
description="Principal configuration for agent authorization and registration"
|
|
23
|
+
..., description="Principal configuration for agent authorization and registration"
|
|
25
24
|
)
|
|
26
|
-
|
|
27
|
-
@field_validator(
|
|
25
|
+
|
|
26
|
+
@field_validator("principal")
|
|
28
27
|
@classmethod
|
|
29
28
|
def validate_principal_required_fields(cls, v: Any) -> Dict[str, Any]:
|
|
30
29
|
"""Ensure principal has required fields for agent registration."""
|
|
@@ -35,125 +34,166 @@ class AgentAuthConfig(BaseModel):
|
|
|
35
34
|
|
|
36
35
|
class AgentKubernetesConfig(BaseModel):
|
|
37
36
|
"""Kubernetes configuration for an agent in a specific environment."""
|
|
38
|
-
|
|
39
|
-
namespace: str = Field(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
@field_validator('namespace')
|
|
37
|
+
|
|
38
|
+
namespace: str = Field(..., description="Kubernetes namespace where the agent will be deployed")
|
|
39
|
+
|
|
40
|
+
@field_validator("namespace")
|
|
45
41
|
@classmethod
|
|
46
42
|
def validate_namespace_format(cls, v: str) -> str:
|
|
47
43
|
"""Ensure namespace follows Kubernetes naming conventions."""
|
|
48
44
|
if not v or not v.strip():
|
|
49
45
|
raise ValueError("Namespace cannot be empty")
|
|
50
|
-
|
|
46
|
+
|
|
51
47
|
# Basic Kubernetes namespace validation
|
|
52
48
|
namespace = v.strip().lower()
|
|
53
|
-
if not namespace.replace(
|
|
54
|
-
raise ValueError(
|
|
55
|
-
|
|
56
|
-
"hyphens, and periods"
|
|
57
|
-
)
|
|
58
|
-
|
|
49
|
+
if not namespace.replace("-", "").replace(".", "").isalnum():
|
|
50
|
+
raise ValueError(f"Namespace '{v}' must contain only lowercase letters, numbers, hyphens, and periods")
|
|
51
|
+
|
|
59
52
|
if len(namespace) > 63:
|
|
60
53
|
raise ValueError(f"Namespace '{v}' cannot exceed 63 characters")
|
|
61
|
-
|
|
54
|
+
|
|
62
55
|
return namespace
|
|
63
56
|
|
|
64
57
|
|
|
65
58
|
class AgentEnvironmentConfig(BaseModel):
|
|
66
59
|
"""Complete configuration for an agent in a specific environment."""
|
|
67
|
-
|
|
68
|
-
kubernetes: AgentKubernetesConfig | None = Field(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
auth: AgentAuthConfig = Field(
|
|
73
|
-
...,
|
|
74
|
-
description="Authentication and authorization configuration"
|
|
75
|
-
)
|
|
76
|
-
helm_repository_name: str = Field(
|
|
77
|
-
default="scale-egp",
|
|
78
|
-
description="Helm repository name for the environment"
|
|
60
|
+
|
|
61
|
+
kubernetes: AgentKubernetesConfig | None = Field(default=None, description="Kubernetes deployment configuration")
|
|
62
|
+
environment: str | None = Field(
|
|
63
|
+
default=None,
|
|
64
|
+
description="The environment keyword that this specific environment maps to: either dev, staging, prod",
|
|
79
65
|
)
|
|
66
|
+
auth: AgentAuthConfig = Field(..., description="Authentication and authorization configuration")
|
|
67
|
+
helm_repository_name: str = Field(default="scale-egp", description="Helm repository name for the environment")
|
|
80
68
|
helm_repository_url: str = Field(
|
|
81
|
-
default="https://scale-egp-helm-charts-us-west-2.s3.amazonaws.com/charts",
|
|
82
|
-
description="Helm repository url for the environment"
|
|
69
|
+
default="https://scale-egp-helm-charts-us-west-2.s3.amazonaws.com/charts",
|
|
70
|
+
description="Helm repository url for the environment",
|
|
83
71
|
)
|
|
84
72
|
helm_overrides: Dict[str, Any] = Field(
|
|
85
|
-
default_factory=dict,
|
|
86
|
-
description="Helm chart value overrides for environment-specific tuning"
|
|
73
|
+
default_factory=dict, description="Helm chart value overrides for environment-specific tuning"
|
|
87
74
|
)
|
|
88
75
|
|
|
89
76
|
|
|
90
77
|
class AgentEnvironmentsConfig(UtilsBaseModel):
|
|
91
78
|
"""All environment configurations for an agent."""
|
|
92
|
-
|
|
93
|
-
schema_version: str = Field(
|
|
94
|
-
default="v1",
|
|
95
|
-
description="Schema version for validation and compatibility"
|
|
96
|
-
)
|
|
79
|
+
|
|
80
|
+
schema_version: str = Field(default="v1", description="Schema version for validation and compatibility")
|
|
97
81
|
environments: Dict[str, AgentEnvironmentConfig] = Field(
|
|
98
|
-
...,
|
|
99
|
-
description="Environment-specific configurations (dev, prod, etc.)"
|
|
82
|
+
..., description="Environment-specific configurations (dev, prod, etc.)"
|
|
100
83
|
)
|
|
101
|
-
|
|
102
|
-
@field_validator(
|
|
84
|
+
|
|
85
|
+
@field_validator("schema_version")
|
|
103
86
|
@classmethod
|
|
104
87
|
def validate_schema_version(cls, v: str) -> str:
|
|
105
88
|
"""Ensure schema version is supported."""
|
|
106
|
-
supported_versions = [
|
|
89
|
+
supported_versions = ["v1"]
|
|
107
90
|
if v not in supported_versions:
|
|
108
|
-
raise ValueError(
|
|
109
|
-
f"Schema version '{v}' not supported. "
|
|
110
|
-
f"Supported versions: {', '.join(supported_versions)}"
|
|
111
|
-
)
|
|
91
|
+
raise ValueError(f"Schema version '{v}' not supported. Supported versions: {', '.join(supported_versions)}")
|
|
112
92
|
return v
|
|
113
|
-
|
|
114
|
-
@field_validator(
|
|
93
|
+
|
|
94
|
+
@field_validator("environments")
|
|
115
95
|
@classmethod
|
|
116
96
|
def validate_environments_not_empty(cls, v: Dict[str, AgentEnvironmentConfig]) -> Dict[str, AgentEnvironmentConfig]:
|
|
117
97
|
"""Ensure at least one environment is defined."""
|
|
118
98
|
if not v:
|
|
119
99
|
raise ValueError("At least one environment must be defined")
|
|
120
100
|
return v
|
|
121
|
-
|
|
101
|
+
|
|
122
102
|
def get_config_for_env(self, env_name: str) -> AgentEnvironmentConfig:
|
|
123
103
|
"""Get configuration for a specific environment.
|
|
124
|
-
|
|
104
|
+
|
|
125
105
|
Args:
|
|
126
106
|
env_name: Name of the environment (e.g., 'dev', 'prod')
|
|
127
|
-
|
|
107
|
+
|
|
128
108
|
Returns:
|
|
129
109
|
AgentEnvironmentConfig for the specified environment
|
|
130
|
-
|
|
110
|
+
|
|
131
111
|
Raises:
|
|
132
112
|
ValueError: If environment is not found
|
|
133
113
|
"""
|
|
134
114
|
if env_name not in self.environments:
|
|
135
|
-
available_envs =
|
|
115
|
+
available_envs = ", ".join(self.environments.keys())
|
|
136
116
|
raise ValueError(
|
|
137
|
-
f"Environment '{env_name}' not found in environments.yaml. "
|
|
138
|
-
f"Available environments: {available_envs}"
|
|
117
|
+
f"Environment '{env_name}' not found in environments.yaml. Available environments: {available_envs}"
|
|
139
118
|
)
|
|
140
119
|
return self.environments[env_name]
|
|
141
|
-
|
|
120
|
+
|
|
121
|
+
def get_configs_for_env(self, env_target: str) -> dict[str, AgentEnvironmentConfig]:
|
|
122
|
+
"""Get configuration for a specific environment based on the expected mapping.
|
|
123
|
+
The environment is either:
|
|
124
|
+
1. explicitly specified like so using a key-map in the environments conifg:
|
|
125
|
+
environments:
|
|
126
|
+
dev-aws:
|
|
127
|
+
environment: "dev"
|
|
128
|
+
kubernetes:
|
|
129
|
+
namespace: "sgp-000-hello-acp"
|
|
130
|
+
auth:
|
|
131
|
+
principal:
|
|
132
|
+
user_id: 73d0c8bd-4726-434c-9686-eb627d89f078
|
|
133
|
+
account_id: 6887f093600ecd59bbbd3095
|
|
134
|
+
helm_overrides:
|
|
135
|
+
|
|
136
|
+
or: it it can be defined at the top level:
|
|
137
|
+
dev:
|
|
138
|
+
kubernetes:
|
|
139
|
+
namespace: "sgp-000-hello-acp"
|
|
140
|
+
auth:
|
|
141
|
+
principal:
|
|
142
|
+
user_id: 73d0c8bd-4726-434c-9686-eb627d89f078
|
|
143
|
+
account_id: 6887f093600ecd59bbbd3095
|
|
144
|
+
helm_overrides:
|
|
145
|
+
|
|
146
|
+
if the environment field is not explicitly set, we assume its the same as
|
|
147
|
+
the name of the environment
|
|
148
|
+
Args:
|
|
149
|
+
env_target: Name of the environment target (e.g., 'dev', 'prod')
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
AgentEnvironmentConfig for the specified environment
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
ValueError: If environment is not found
|
|
156
|
+
"""
|
|
157
|
+
envs_to_deploy = {}
|
|
158
|
+
if env_target in self.environments:
|
|
159
|
+
# this supports if the top-level key is just "dev, staging, etc" and matches
|
|
160
|
+
# the environment name exactly without any explicit mapping
|
|
161
|
+
envs_to_deploy[env_target] = self.environments[env_target]
|
|
162
|
+
|
|
163
|
+
for env_name, config in self.environments.items():
|
|
164
|
+
if config.environment == env_target:
|
|
165
|
+
envs_to_deploy[env_name] = config
|
|
166
|
+
|
|
167
|
+
if len(envs_to_deploy) == 0:
|
|
168
|
+
## this just finds environments for each target, so "available_envs" refers to each target environment
|
|
169
|
+
|
|
170
|
+
available_envs = set()
|
|
171
|
+
for env_name, config in self.environments.items():
|
|
172
|
+
if config.environment is not None:
|
|
173
|
+
available_envs.add(config.environment)
|
|
174
|
+
else:
|
|
175
|
+
available_envs.add(env_name)
|
|
176
|
+
raise ValueError(
|
|
177
|
+
f"Environment '{env_target}' not found in environments.yaml. Available environments: {available_envs}"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
return envs_to_deploy
|
|
181
|
+
|
|
142
182
|
def list_environments(self) -> list[str]:
|
|
143
183
|
"""Get list of all configured environment names."""
|
|
144
184
|
return list(self.environments.keys())
|
|
145
|
-
|
|
185
|
+
|
|
146
186
|
@classmethod
|
|
147
187
|
@override
|
|
148
188
|
def from_yaml(cls, file_path: str) -> "AgentEnvironmentsConfig":
|
|
149
189
|
"""Load configuration from environments.yaml file.
|
|
150
|
-
|
|
190
|
+
|
|
151
191
|
Args:
|
|
152
192
|
file_path: Path to environments.yaml file
|
|
153
|
-
|
|
193
|
+
|
|
154
194
|
Returns:
|
|
155
195
|
Parsed and validated AgentEnvironmentsConfig
|
|
156
|
-
|
|
196
|
+
|
|
157
197
|
Raises:
|
|
158
198
|
FileNotFoundError: If file doesn't exist
|
|
159
199
|
ValueError: If file is invalid or doesn't validate
|
|
@@ -161,16 +201,16 @@ class AgentEnvironmentsConfig(UtilsBaseModel):
|
|
|
161
201
|
path = Path(file_path)
|
|
162
202
|
if not path.exists():
|
|
163
203
|
raise FileNotFoundError(f"environments.yaml not found: {file_path}")
|
|
164
|
-
|
|
204
|
+
|
|
165
205
|
try:
|
|
166
|
-
with open(path,
|
|
206
|
+
with open(path, "r") as f:
|
|
167
207
|
data = yaml.safe_load(f)
|
|
168
|
-
|
|
208
|
+
|
|
169
209
|
if not data:
|
|
170
210
|
raise ValueError("environments.yaml file is empty")
|
|
171
|
-
|
|
211
|
+
|
|
172
212
|
return cls.model_validate(data)
|
|
173
|
-
|
|
213
|
+
|
|
174
214
|
except yaml.YAMLError as e:
|
|
175
215
|
raise ValueError(f"Invalid YAML format in {file_path}: {e}") from e
|
|
176
216
|
except Exception as e:
|
|
@@ -179,18 +219,18 @@ class AgentEnvironmentsConfig(UtilsBaseModel):
|
|
|
179
219
|
|
|
180
220
|
def load_environments_config_from_manifest_dir(manifest_dir: Path) -> AgentEnvironmentsConfig | None:
|
|
181
221
|
"""Helper function to load environments.yaml from same directory as manifest.yaml.
|
|
182
|
-
|
|
222
|
+
|
|
183
223
|
Args:
|
|
184
224
|
manifest_dir: Directory containing manifest.yaml
|
|
185
|
-
|
|
225
|
+
|
|
186
226
|
Returns:
|
|
187
227
|
AgentEnvironmentsConfig if environments.yaml exists, None otherwise
|
|
188
|
-
|
|
228
|
+
|
|
189
229
|
Raises:
|
|
190
230
|
ValueError: If environments.yaml exists but is invalid
|
|
191
231
|
"""
|
|
192
232
|
environments_file = manifest_dir / "environments.yaml"
|
|
193
233
|
if not environments_file.exists():
|
|
194
234
|
return None
|
|
195
|
-
|
|
235
|
+
|
|
196
236
|
return AgentEnvironmentsConfig.from_yaml(str(environments_file))
|
|
@@ -4,6 +4,7 @@ Validation framework for agent configuration files.
|
|
|
4
4
|
This module provides validation functions for agent configurations,
|
|
5
5
|
with clear error messages and best practices enforcement.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
from __future__ import annotations
|
|
8
9
|
|
|
9
10
|
from typing import Any, Dict, List, Optional
|
|
@@ -17,7 +18,7 @@ logger = make_logger(__name__)
|
|
|
17
18
|
|
|
18
19
|
class ConfigValidationError(Exception):
|
|
19
20
|
"""Exception raised when configuration validation fails."""
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
def __init__(self, message: str, file_path: Optional[str] = None):
|
|
22
23
|
self.file_path = file_path
|
|
23
24
|
super().__init__(message)
|
|
@@ -25,88 +26,95 @@ class ConfigValidationError(Exception):
|
|
|
25
26
|
|
|
26
27
|
class EnvironmentsValidationError(ConfigValidationError):
|
|
27
28
|
"""Exception raised when environments.yaml validation fails."""
|
|
29
|
+
|
|
28
30
|
pass
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
def validate_environments_config(
|
|
32
|
-
environments_config: AgentEnvironmentsConfig,
|
|
33
|
-
required_environments: Optional[List[str]] = None
|
|
34
|
+
environments_config: AgentEnvironmentsConfig, required_environments: Optional[List[str]] = None
|
|
34
35
|
) -> None:
|
|
35
36
|
"""
|
|
36
37
|
Validate environments configuration with comprehensive checks.
|
|
37
|
-
|
|
38
|
+
|
|
38
39
|
Args:
|
|
39
40
|
environments_config: The loaded environments configuration
|
|
40
41
|
required_environments: List of environment names that must be present
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
Raises:
|
|
43
44
|
EnvironmentsValidationError: If validation fails
|
|
44
45
|
"""
|
|
45
46
|
# Check for required environments
|
|
46
47
|
if required_environments:
|
|
48
|
+
# this must exist as a top-level key or via the environment indicator
|
|
47
49
|
missing_envs: List[str] = []
|
|
50
|
+
environment_mappings = [env.environment for env in environments_config.environments.values() if env.environment]
|
|
51
|
+
top_level_envs = [env for env in environments_config.environments]
|
|
52
|
+
all_envs = set(environment_mappings + top_level_envs)
|
|
48
53
|
for env_name in required_environments:
|
|
49
|
-
if env_name not in
|
|
54
|
+
if env_name not in all_envs:
|
|
50
55
|
missing_envs.append(env_name)
|
|
51
|
-
|
|
56
|
+
|
|
52
57
|
if missing_envs:
|
|
53
|
-
available_envs = list(environments_config.environments.keys())
|
|
54
58
|
raise EnvironmentsValidationError(
|
|
55
59
|
f"Missing required environments: {', '.join(missing_envs)}. "
|
|
56
|
-
f"Available environments: {', '.join(
|
|
60
|
+
f"Available environments: {', '.join(all_envs)}"
|
|
57
61
|
)
|
|
58
|
-
|
|
62
|
+
|
|
63
|
+
# if environment mappings are set, you cannot have a top-level env_name that maps to an `environment: value`
|
|
64
|
+
# and another environment that has the mapping i.e.
|
|
65
|
+
# enviorments:
|
|
66
|
+
# dev:
|
|
67
|
+
# ....
|
|
68
|
+
# dev1:
|
|
69
|
+
# environment: dev
|
|
70
|
+
# this is invalid because its unclear if "dev" refers to just that top-level environment or the mapping
|
|
71
|
+
#
|
|
59
72
|
# Validate each environment configuration
|
|
60
73
|
for env_name, env_config in environments_config.environments.items():
|
|
61
74
|
try:
|
|
62
75
|
_validate_single_environment_config(env_name, env_config)
|
|
63
76
|
except Exception as e:
|
|
64
|
-
raise EnvironmentsValidationError(
|
|
65
|
-
f"Environment '{env_name}' configuration error: {str(e)}"
|
|
66
|
-
) from e
|
|
77
|
+
raise EnvironmentsValidationError(f"Environment '{env_name}' configuration error: {str(e)}") from e
|
|
67
78
|
|
|
68
79
|
|
|
69
80
|
def _validate_single_environment_config(env_name: str, env_config: AgentEnvironmentConfig) -> None:
|
|
70
81
|
"""
|
|
71
82
|
Validate a single environment configuration.
|
|
72
|
-
|
|
83
|
+
|
|
73
84
|
Args:
|
|
74
85
|
env_name: Name of the environment
|
|
75
86
|
env_config: AgentEnvironmentConfig instance
|
|
76
|
-
|
|
87
|
+
|
|
77
88
|
Raises:
|
|
78
89
|
ValueError: If validation fails
|
|
79
90
|
"""
|
|
80
91
|
# Validate namespace naming conventions if kubernetes config exists
|
|
81
92
|
if env_config.kubernetes and env_config.kubernetes.namespace:
|
|
82
93
|
namespace = env_config.kubernetes.namespace
|
|
83
|
-
|
|
94
|
+
|
|
84
95
|
# Check for common namespace naming issues
|
|
85
96
|
if namespace != namespace.lower():
|
|
86
97
|
logger.warning(
|
|
87
|
-
f"Namespace '{namespace}' contains uppercase letters. "
|
|
88
|
-
"Kubernetes namespaces should be lowercase."
|
|
98
|
+
f"Namespace '{namespace}' contains uppercase letters. Kubernetes namespaces should be lowercase."
|
|
89
99
|
)
|
|
90
|
-
|
|
91
|
-
if namespace.startswith(
|
|
92
|
-
raise ValueError(
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
|
|
100
|
+
|
|
101
|
+
if namespace.startswith("-") or namespace.endswith("-"):
|
|
102
|
+
raise ValueError(f"Namespace '{namespace}' cannot start or end with hyphens")
|
|
103
|
+
|
|
96
104
|
# Validate auth principal
|
|
97
105
|
principal = env_config.auth.principal
|
|
98
|
-
if not principal.get(
|
|
106
|
+
if not principal.get("user_id"):
|
|
99
107
|
raise ValueError("Auth principal must contain non-empty 'user_id'")
|
|
100
|
-
|
|
108
|
+
|
|
101
109
|
# Check for environment-specific user_id patterns
|
|
102
|
-
user_id = principal[
|
|
110
|
+
user_id = principal["user_id"]
|
|
103
111
|
if isinstance(user_id, str):
|
|
104
|
-
if not any(env_name.lower() in user_id.lower() for env_name in [
|
|
112
|
+
if not any(env_name.lower() in user_id.lower() for env_name in ["dev", "prod", "staging", env_name]):
|
|
105
113
|
logger.warning(
|
|
106
114
|
f"User ID '{user_id}' doesn't contain environment indicator. "
|
|
107
115
|
f"Consider including '{env_name}' in the user_id for clarity."
|
|
108
116
|
)
|
|
109
|
-
|
|
117
|
+
|
|
110
118
|
# Validate helm overrides if present
|
|
111
119
|
if env_config.helm_overrides:
|
|
112
120
|
_validate_helm_overrides(env_config.helm_overrides)
|
|
@@ -115,26 +123,26 @@ def _validate_single_environment_config(env_name: str, env_config: AgentEnvironm
|
|
|
115
123
|
def _validate_helm_overrides(helm_overrides: Dict[str, Any]) -> None:
|
|
116
124
|
"""
|
|
117
125
|
Validate helm override configuration.
|
|
118
|
-
|
|
126
|
+
|
|
119
127
|
Args:
|
|
120
128
|
helm_overrides: Dictionary of helm overrides
|
|
121
|
-
|
|
129
|
+
|
|
122
130
|
Raises:
|
|
123
131
|
ValueError: If validation fails
|
|
124
132
|
"""
|
|
125
133
|
# Check for common helm override issues
|
|
126
|
-
if
|
|
127
|
-
resources = helm_overrides[
|
|
134
|
+
if "resources" in helm_overrides:
|
|
135
|
+
resources = helm_overrides["resources"]
|
|
128
136
|
if isinstance(resources, dict):
|
|
129
137
|
# Validate resource format
|
|
130
|
-
if
|
|
131
|
-
for resource_type in [
|
|
138
|
+
if "requests" in resources or "limits" in resources:
|
|
139
|
+
for resource_type in ["requests", "limits"]:
|
|
132
140
|
if resource_type in resources:
|
|
133
141
|
resource_config: Any = resources[resource_type]
|
|
134
142
|
if isinstance(resource_config, dict):
|
|
135
143
|
# Check for valid resource specifications
|
|
136
144
|
for key, value in resource_config.items():
|
|
137
|
-
if key in [
|
|
145
|
+
if key in ["cpu", "memory"] and not isinstance(value, str):
|
|
138
146
|
logger.warning(
|
|
139
147
|
f"Resource {key} should be a string (e.g., '500m', '1Gi'), "
|
|
140
148
|
f"got {type(value).__name__}: {value}"
|
|
@@ -144,13 +152,13 @@ def _validate_helm_overrides(helm_overrides: Dict[str, Any]) -> None:
|
|
|
144
152
|
def validate_environments_yaml_file(file_path: str) -> AgentEnvironmentsConfig:
|
|
145
153
|
"""
|
|
146
154
|
Load and validate environments.yaml file.
|
|
147
|
-
|
|
155
|
+
|
|
148
156
|
Args:
|
|
149
157
|
file_path: Path to environments.yaml file
|
|
150
|
-
|
|
158
|
+
|
|
151
159
|
Returns:
|
|
152
160
|
Validated AgentEnvironmentsConfig
|
|
153
|
-
|
|
161
|
+
|
|
154
162
|
Raises:
|
|
155
163
|
EnvironmentsValidationError: If file is invalid
|
|
156
164
|
"""
|
|
@@ -164,66 +172,59 @@ def validate_environments_yaml_file(file_path: str) -> AgentEnvironmentsConfig:
|
|
|
164
172
|
"📋 Why required:\n"
|
|
165
173
|
" Environment-specific settings (auth, namespace, resources)\n"
|
|
166
174
|
" must be separated from global manifest for proper isolation.",
|
|
167
|
-
file_path=file_path
|
|
175
|
+
file_path=file_path,
|
|
168
176
|
) from None
|
|
169
177
|
except Exception as e:
|
|
170
|
-
raise EnvironmentsValidationError(
|
|
171
|
-
f"Invalid environments.yaml file: {str(e)}",
|
|
172
|
-
file_path=file_path
|
|
173
|
-
) from e
|
|
178
|
+
raise EnvironmentsValidationError(f"Invalid environments.yaml file: {str(e)}", file_path=file_path) from e
|
|
174
179
|
|
|
175
180
|
|
|
176
181
|
def validate_manifest_and_environments(
|
|
177
|
-
manifest_path: str,
|
|
178
|
-
required_environment: Optional[str] = None
|
|
182
|
+
manifest_path: str, required_environment: Optional[str] = None
|
|
179
183
|
) -> tuple[str, AgentEnvironmentsConfig]:
|
|
180
184
|
"""
|
|
181
185
|
Validate both manifest.yaml and environments.yaml files together.
|
|
182
|
-
|
|
186
|
+
|
|
183
187
|
Args:
|
|
184
188
|
manifest_path: Path to manifest.yaml file
|
|
185
189
|
required_environment: Specific environment that must be present
|
|
186
|
-
|
|
190
|
+
|
|
187
191
|
Returns:
|
|
188
192
|
Tuple of (manifest_path, environments_config)
|
|
189
|
-
|
|
193
|
+
|
|
190
194
|
Raises:
|
|
191
195
|
ConfigValidationError: If validation fails
|
|
192
196
|
"""
|
|
193
197
|
manifest_file = Path(manifest_path)
|
|
194
198
|
if not manifest_file.exists():
|
|
195
199
|
raise ConfigValidationError(f"Manifest file not found: {manifest_path}")
|
|
196
|
-
|
|
200
|
+
|
|
197
201
|
# Look for environments.yaml in same directory
|
|
198
202
|
environments_file = manifest_file.parent / "environments.yaml"
|
|
199
203
|
environments_config = validate_environments_yaml_file(str(environments_file))
|
|
200
|
-
|
|
204
|
+
|
|
201
205
|
# Validate specific environment if requested
|
|
202
206
|
if required_environment:
|
|
203
|
-
validate_environments_config(
|
|
204
|
-
|
|
205
|
-
required_environments=[required_environment]
|
|
206
|
-
)
|
|
207
|
-
|
|
207
|
+
validate_environments_config(environments_config, required_environments=[required_environment])
|
|
208
|
+
|
|
208
209
|
return manifest_path, environments_config
|
|
209
210
|
|
|
210
211
|
|
|
211
212
|
def generate_helpful_error_message(error: Exception, context: str = "") -> str:
|
|
212
213
|
"""
|
|
213
214
|
Generate helpful error message with troubleshooting tips.
|
|
214
|
-
|
|
215
|
+
|
|
215
216
|
Args:
|
|
216
217
|
error: The original exception
|
|
217
218
|
context: Additional context about where the error occurred
|
|
218
|
-
|
|
219
|
+
|
|
219
220
|
Returns:
|
|
220
221
|
Formatted error message with troubleshooting tips
|
|
221
222
|
"""
|
|
222
223
|
base_msg = str(error)
|
|
223
|
-
|
|
224
|
+
|
|
224
225
|
if context:
|
|
225
226
|
base_msg = f"{context}: {base_msg}"
|
|
226
|
-
|
|
227
|
+
|
|
227
228
|
# Add troubleshooting tips based on error type
|
|
228
229
|
if isinstance(error, FileNotFoundError):
|
|
229
230
|
if "environments.yaml" in base_msg:
|
|
@@ -246,5 +247,5 @@ def generate_helpful_error_message(error: Exception, context: str = "") -> str:
|
|
|
246
247
|
"- Include team and environment (e.g., 'team-dev-agent')\n"
|
|
247
248
|
"- Keep under 63 characters"
|
|
248
249
|
)
|
|
249
|
-
|
|
250
|
+
|
|
250
251
|
return base_msg
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: agentex-sdk
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: The official Python library for the agentex API
|
|
5
5
|
Project-URL: Homepage, https://github.com/scaleapi/scale-agentex-python
|
|
6
6
|
Project-URL: Repository, https://github.com/scaleapi/scale-agentex-python
|
|
@@ -11,7 +11,7 @@ agentex/_resource.py,sha256=S1t7wmR5WUvoDIhZjo_x-E7uoTJBynJ3d8tPJMQYdjw,1106
|
|
|
11
11
|
agentex/_response.py,sha256=Tb9zazsnemO2rTxWtBjAD5WBqlhli5ZaXGbiKgdu5DE,28794
|
|
12
12
|
agentex/_streaming.py,sha256=aOvLOte7kaclPGm-D0iNdM3uRcWrZ-T2B8t9BDNmpuA,10225
|
|
13
13
|
agentex/_types.py,sha256=00q2kgDxUPJC16dU-YIUeOFsN5MzNW0zjzVXMlBYGV0,7296
|
|
14
|
-
agentex/_version.py,sha256=
|
|
14
|
+
agentex/_version.py,sha256=N-oaYLvjQ5A1ZPup7gO50SUO8xLBkfetnHauya_5gcI,159
|
|
15
15
|
agentex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
agentex/_utils/__init__.py,sha256=7fch0GT9zpNnErbciSpUNa-SjTxxjY6kxHxKMOM4AGs,2305
|
|
17
17
|
agentex/_utils/_compat.py,sha256=D8gtAvjJQrDWt9upS0XaG9Rr5l1QhiAx_I_1utT_tt0,1195
|
|
@@ -52,7 +52,7 @@ agentex/lib/adk/utils/_modules/client.py,sha256=UYSTThuZoX3nqF8iuRmRI8uPO00NrYgC
|
|
|
52
52
|
agentex/lib/adk/utils/_modules/templating.py,sha256=tSiJGoDrF-XkMEi4MB_wVH6nyKyhSQwVZ8krN5R-86Q,3598
|
|
53
53
|
agentex/lib/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
agentex/lib/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
|
-
agentex/lib/cli/commands/agents.py,sha256
|
|
55
|
+
agentex/lib/cli/commands/agents.py,sha256=-zNA8TQnWW4UjLDjuZ6LNHxJqbdYOfGDn2-xX-4xWFM,13516
|
|
56
56
|
agentex/lib/cli/commands/init.py,sha256=CrKksw5l1w9hXSdDN6wPNgQlyE1k_kqHlA6QrOenqHM,15537
|
|
57
57
|
agentex/lib/cli/commands/main.py,sha256=QWychw-Xq3nQ00BMypgOEF4w1WauNrgQ06PDardNP_8,1042
|
|
58
58
|
agentex/lib/cli/commands/secrets.py,sha256=t4zvoyjOHmw-8qp6nsxdZCvqy43QXOl0MWXA3ooBO6Q,5640
|
|
@@ -215,10 +215,10 @@ agentex/lib/sdk/config/agent_config.py,sha256=4q1qMdE9_gBTsLB_NplY4exzUYLd8wQIyw
|
|
|
215
215
|
agentex/lib/sdk/config/agent_manifest.py,sha256=28e2o6yDe_hQMfegMUh07w-B5Kh9WZHv0z77kJvcJFk,8626
|
|
216
216
|
agentex/lib/sdk/config/build_config.py,sha256=pTgtvecHQejp4SlCvS6f6TfGnWqXFG-Ac0L8zthvyGk,1085
|
|
217
217
|
agentex/lib/sdk/config/deployment_config.py,sha256=QZ8zsYt4Uchw1hCs2y9mHJ8EPVBbbOfmBktv1SC_4K4,4028
|
|
218
|
-
agentex/lib/sdk/config/environment_config.py,sha256=
|
|
218
|
+
agentex/lib/sdk/config/environment_config.py,sha256=zI-U060RsZZf8G6AAh1Y9F0Ls2AQIy0-Jn98NQT2yP8,8904
|
|
219
219
|
agentex/lib/sdk/config/local_development_config.py,sha256=Sx7Cf3bP4oVjavdqy5rx4pvLZocyS19uJcrEj_mA5Nc,1733
|
|
220
220
|
agentex/lib/sdk/config/project_config.py,sha256=uMrg9BqEQFcnqdlqqSLYsaQkP1mMedhEZZMzPBSyCK0,3698
|
|
221
|
-
agentex/lib/sdk/config/validation.py,sha256=
|
|
221
|
+
agentex/lib/sdk/config/validation.py,sha256=yzt9n7KTwHotA-vExa_LK_D_mgq4FCDGIjHuKSgs0Ks,9319
|
|
222
222
|
agentex/lib/sdk/fastacp/__init__.py,sha256=UvAdexdnfb4z0F4a2sfXROFyh9EjH89kf3AxHPybzCM,75
|
|
223
223
|
agentex/lib/sdk/fastacp/fastacp.py,sha256=3aT74pFwF76VoTbQnGZsF6As42aLa2o_JrO6EP_XHQM,4591
|
|
224
224
|
agentex/lib/sdk/fastacp/base/base_acp_server.py,sha256=W2rMZUC-5GLvLJsLFKZHtmyG9Uhrsgffqo9qcomThsQ,17163
|
|
@@ -351,8 +351,8 @@ agentex/types/messages/batch_update_params.py,sha256=Ug5CThbD49a8j4qucg04OdmVrp_
|
|
|
351
351
|
agentex/types/messages/batch_update_response.py,sha256=TbSBe6SuPzjXXWSj-nRjT1JHGBooTshHQQDa1AixQA8,278
|
|
352
352
|
agentex/types/shared/__init__.py,sha256=IKs-Qn5Yja0kFh1G1kDqYZo43qrOu1hSoxlPdN-85dI,149
|
|
353
353
|
agentex/types/shared/delete_response.py,sha256=8qH3zvQXaOHYQSHyXi7UQxdR4miTzR7V9K4zXVsiUyk,215
|
|
354
|
-
agentex_sdk-0.8.
|
|
355
|
-
agentex_sdk-0.8.
|
|
356
|
-
agentex_sdk-0.8.
|
|
357
|
-
agentex_sdk-0.8.
|
|
358
|
-
agentex_sdk-0.8.
|
|
354
|
+
agentex_sdk-0.8.2.dist-info/METADATA,sha256=MOVWQExMpCFpUtxRwBGaOJe8dccARQtBC9NNc9nkSp8,15553
|
|
355
|
+
agentex_sdk-0.8.2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
356
|
+
agentex_sdk-0.8.2.dist-info/entry_points.txt,sha256=V7vJuMZdF0UlvgX6KiBN7XUvq_cxF5kplcYvc1QlFaQ,62
|
|
357
|
+
agentex_sdk-0.8.2.dist-info/licenses/LICENSE,sha256=Eejl902yry8m7Bl6gRYRUObLifIrC61CmV369C6-dqQ,11337
|
|
358
|
+
agentex_sdk-0.8.2.dist-info/RECORD,,
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2026 Agentex
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
File without changes
|
|
File without changes
|