agentscope-runtime 1.0.1__py3-none-any.whl → 1.0.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.
Files changed (58) hide show
  1. agentscope_runtime/adapters/agentscope/message.py +32 -7
  2. agentscope_runtime/adapters/agentscope/stream.py +121 -91
  3. agentscope_runtime/adapters/agno/__init__.py +0 -0
  4. agentscope_runtime/adapters/agno/message.py +30 -0
  5. agentscope_runtime/adapters/agno/stream.py +122 -0
  6. agentscope_runtime/adapters/langgraph/__init__.py +12 -0
  7. agentscope_runtime/adapters/langgraph/message.py +257 -0
  8. agentscope_runtime/adapters/langgraph/stream.py +205 -0
  9. agentscope_runtime/cli/__init__.py +7 -0
  10. agentscope_runtime/cli/cli.py +63 -0
  11. agentscope_runtime/cli/commands/__init__.py +2 -0
  12. agentscope_runtime/cli/commands/chat.py +815 -0
  13. agentscope_runtime/cli/commands/deploy.py +1062 -0
  14. agentscope_runtime/cli/commands/invoke.py +58 -0
  15. agentscope_runtime/cli/commands/list_cmd.py +103 -0
  16. agentscope_runtime/cli/commands/run.py +176 -0
  17. agentscope_runtime/cli/commands/sandbox.py +128 -0
  18. agentscope_runtime/cli/commands/status.py +60 -0
  19. agentscope_runtime/cli/commands/stop.py +185 -0
  20. agentscope_runtime/cli/commands/web.py +166 -0
  21. agentscope_runtime/cli/loaders/__init__.py +6 -0
  22. agentscope_runtime/cli/loaders/agent_loader.py +295 -0
  23. agentscope_runtime/cli/state/__init__.py +10 -0
  24. agentscope_runtime/cli/utils/__init__.py +18 -0
  25. agentscope_runtime/cli/utils/console.py +378 -0
  26. agentscope_runtime/cli/utils/validators.py +118 -0
  27. agentscope_runtime/engine/app/agent_app.py +7 -4
  28. agentscope_runtime/engine/deployers/__init__.py +1 -0
  29. agentscope_runtime/engine/deployers/agentrun_deployer.py +152 -22
  30. agentscope_runtime/engine/deployers/base.py +27 -2
  31. agentscope_runtime/engine/deployers/kubernetes_deployer.py +158 -31
  32. agentscope_runtime/engine/deployers/local_deployer.py +188 -25
  33. agentscope_runtime/engine/deployers/modelstudio_deployer.py +109 -18
  34. agentscope_runtime/engine/deployers/state/__init__.py +9 -0
  35. agentscope_runtime/engine/deployers/state/manager.py +388 -0
  36. agentscope_runtime/engine/deployers/state/schema.py +96 -0
  37. agentscope_runtime/engine/deployers/utils/build_cache.py +736 -0
  38. agentscope_runtime/engine/deployers/utils/detached_app.py +105 -30
  39. agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +31 -10
  40. agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +15 -8
  41. agentscope_runtime/engine/deployers/utils/docker_image_utils/image_factory.py +30 -2
  42. agentscope_runtime/engine/deployers/utils/k8s_utils.py +241 -0
  43. agentscope_runtime/engine/deployers/utils/package.py +56 -6
  44. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +16 -2
  45. agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +155 -5
  46. agentscope_runtime/engine/deployers/utils/wheel_packager.py +107 -123
  47. agentscope_runtime/engine/runner.py +25 -6
  48. agentscope_runtime/engine/schemas/exception.py +580 -0
  49. agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +113 -39
  50. agentscope_runtime/sandbox/box/shared/routers/mcp_utils.py +20 -4
  51. agentscope_runtime/sandbox/utils.py +2 -0
  52. agentscope_runtime/version.py +1 -1
  53. {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.2.dist-info}/METADATA +24 -7
  54. {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.2.dist-info}/RECORD +58 -28
  55. {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.2.dist-info}/entry_points.txt +1 -0
  56. {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.2.dist-info}/WHEEL +0 -0
  57. {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.2.dist-info}/licenses/LICENSE +0 -0
  58. {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,58 @@
1
+ # -*- coding: utf-8 -*-
2
+ """agentscope invoke command - Invoke a deployed agent."""
3
+ # pylint: disable=no-value-for-parameter
4
+
5
+ import click
6
+
7
+ from agentscope_runtime.cli.commands.chat import chat
8
+ from agentscope_runtime.cli.utils.console import echo_info
9
+
10
+
11
+ @click.command()
12
+ @click.argument("deploy_id", required=True)
13
+ @click.option(
14
+ "--query",
15
+ "-q",
16
+ help="Single query to execute (non-interactive mode)",
17
+ default=None,
18
+ )
19
+ @click.option(
20
+ "--session-id",
21
+ help="Session ID for conversation continuity",
22
+ default=None,
23
+ )
24
+ @click.option(
25
+ "--user-id",
26
+ help="User ID for the session",
27
+ default="default_user",
28
+ )
29
+ def invoke(deploy_id: str, query: str, session_id: str, user_id: str):
30
+ """
31
+ Invoke a deployed agent (alias for 'run' with deployment ID).
32
+
33
+ This is a convenience command that is equivalent to:
34
+ $ agentscope chat <deploy_id> [options]
35
+
36
+ Examples:
37
+ \b
38
+ # Interactive mode
39
+ $ agentscope invoke local_20250101_120000_abc123
40
+
41
+ # Single query
42
+ $ agentscope invoke local_20250101_120000_abc123 --query "Hello"
43
+ """
44
+ echo_info(f"Invoking deployment: {deploy_id}")
45
+
46
+ # Delegate to run command
47
+ ctx = click.get_current_context()
48
+ ctx.invoke(
49
+ chat,
50
+ source=deploy_id,
51
+ query=query,
52
+ session_id=session_id,
53
+ user_id=user_id,
54
+ )
55
+
56
+
57
+ if __name__ == "__main__":
58
+ invoke()
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ """agentscope list command - List all deployments."""
3
+ # pylint: disable=no-value-for-parameter, too-many-branches, protected-access
4
+
5
+ import sys
6
+ from typing import Optional
7
+
8
+ import click
9
+
10
+ from agentscope_runtime.engine.deployers.state import DeploymentStateManager
11
+ from agentscope_runtime.cli.utils.console import (
12
+ echo_error,
13
+ echo_info,
14
+ format_table,
15
+ format_json,
16
+ )
17
+
18
+
19
+ @click.command(name="list")
20
+ @click.option(
21
+ "--status",
22
+ "-s",
23
+ help="Filter by status (e.g., running, stopped)",
24
+ default=None,
25
+ )
26
+ @click.option(
27
+ "--platform",
28
+ "-p",
29
+ help="Filter by platform (e.g., local, k8s, agentrun)",
30
+ default=None,
31
+ )
32
+ @click.option(
33
+ "--output-format",
34
+ "-f",
35
+ help="Output format: table or json",
36
+ type=click.Choice(["table", "json"], case_sensitive=False),
37
+ default="table",
38
+ )
39
+ def list_deployments(
40
+ status: Optional[str],
41
+ platform: Optional[str],
42
+ output_format: str,
43
+ ):
44
+ """
45
+ List all deployments.
46
+
47
+ Examples:
48
+ \b
49
+ # List all deployments
50
+ $ agentscope list
51
+
52
+ # Filter by status
53
+ $ agentscope list --status running
54
+
55
+ # Filter by platform
56
+ $ agentscope list --platform k8s
57
+
58
+ # JSON output
59
+ $ agentscope list --output-format json
60
+ """
61
+ try:
62
+ # Initialize state manager
63
+ state_manager = DeploymentStateManager()
64
+
65
+ # Get deployments
66
+ deployments = state_manager.list(status=status, platform=platform)
67
+
68
+ if not deployments:
69
+ echo_info("No deployments found")
70
+ return
71
+
72
+ if output_format == "json":
73
+ # JSON output
74
+ output = [d.to_dict() for d in deployments]
75
+ print(format_json(output))
76
+ else:
77
+ # Table output
78
+ headers = ["ID", "Platform", "Status", "Created", "URL"]
79
+ rows = []
80
+
81
+ for d in deployments:
82
+ # Truncate long IDs and URLs
83
+ deploy_id = d.id if len(d.id) <= 30 else d.id[:27] + "..."
84
+ url = d.url if len(d.url) <= 40 else d.url[:37] + "..."
85
+ created = (
86
+ d.created_at[:19]
87
+ if len(d.created_at) > 19
88
+ else d.created_at
89
+ )
90
+
91
+ rows.append([deploy_id, d.platform, d.status, created, url])
92
+
93
+ print(format_table(headers, rows))
94
+
95
+ echo_info(f"\nTotal: {len(deployments)} deployment(s)")
96
+
97
+ except Exception as e:
98
+ echo_error(f"Failed to list deployments: {e}")
99
+ sys.exit(1)
100
+
101
+
102
+ if __name__ == "__main__":
103
+ list_deployments()
@@ -0,0 +1,176 @@
1
+ # -*- coding: utf-8 -*-
2
+ """agentscope run command - Start agent service without interactive mode."""
3
+ # pylint: disable=too-many-statements, no-value-for-parameter
4
+
5
+ import logging
6
+ import os
7
+ import sys
8
+ from typing import Optional
9
+
10
+ import click
11
+
12
+ from agentscope_runtime.cli.loaders.agent_loader import (
13
+ UnifiedAgentLoader,
14
+ AgentLoadError,
15
+ )
16
+ from agentscope_runtime.cli.utils.validators import validate_agent_source
17
+ from agentscope_runtime.engine.deployers.state import DeploymentStateManager
18
+ from agentscope_runtime.cli.utils.console import (
19
+ echo_error,
20
+ echo_info,
21
+ echo_success,
22
+ echo_warning,
23
+ )
24
+
25
+
26
+ @click.command()
27
+ @click.argument("source", required=True)
28
+ @click.option(
29
+ "--host",
30
+ "-h",
31
+ help="Host address to bind to",
32
+ default="0.0.0.0",
33
+ )
34
+ @click.option(
35
+ "--port",
36
+ "-p",
37
+ help="Port number to serve the application on",
38
+ type=int,
39
+ default=8080,
40
+ )
41
+ @click.option(
42
+ "--verbose",
43
+ "-v",
44
+ is_flag=True,
45
+ help="Show verbose output including logs",
46
+ default=False,
47
+ )
48
+ @click.option(
49
+ "--entrypoint",
50
+ "-e",
51
+ help="Entrypoint file name for directory sources (e.g., 'app.py', "
52
+ "'main.py')",
53
+ default=None,
54
+ )
55
+ def run(
56
+ source: str,
57
+ host: str,
58
+ port: int,
59
+ verbose: bool,
60
+ entrypoint: Optional[str],
61
+ ):
62
+ """
63
+ Start agent service and run continuously.
64
+
65
+ SOURCE can be:
66
+ \b
67
+ - Path to Python file (e.g., agent.py)
68
+ - Path to project directory (e.g., ./my-agent)
69
+ - Deployment ID (e.g., local_20250101_120000_abc123)
70
+
71
+ The agent service will start and run continuously, allowing users to
72
+ interact with it via HTTP API endpoints. Logs will be printed based
73
+ on the verbose flag.
74
+
75
+ Examples:
76
+ \b
77
+ # Run agent service
78
+ $ agentscope run agent.py
79
+
80
+ # Run with verbose logging
81
+ $ agentscope run agent.py --verbose
82
+
83
+ # Specify custom host and port
84
+ $ agentscope run agent.py --host 127.0.0.1 --port 8090
85
+
86
+ # Use custom entrypoint for directory source
87
+ $ agentscope run ./my-project --entrypoint custom_app.py
88
+
89
+ # Run a deployed agent
90
+ $ agentscope run local_20250101_120000_abc123
91
+ """
92
+ # Configure logging and tracing based on verbose flag
93
+ if not verbose:
94
+ # Disable console tracing output (JSON logs)
95
+ os.environ["TRACE_ENABLE_LOG"] = "false"
96
+ # Set root logger to WARNING to suppress INFO logs
97
+ logging.getLogger().setLevel(logging.WARNING)
98
+ # Also suppress specific library loggers
99
+ logging.getLogger("agentscope").setLevel(logging.WARNING)
100
+ logging.getLogger("agentscope_runtime").setLevel(logging.WARNING)
101
+ else:
102
+ # Enable console tracing output for verbose mode
103
+ os.environ["TRACE_ENABLE_LOG"] = "true"
104
+ # Set root logger to DEBUG for verbose output
105
+ logging.getLogger().setLevel(logging.INFO)
106
+ # Also suppress specific library loggers
107
+ logging.getLogger("agentscope").setLevel(logging.INFO)
108
+ logging.getLogger("agentscope_runtime").setLevel(logging.INFO)
109
+
110
+ try:
111
+ # Initialize state manager
112
+ state_manager = DeploymentStateManager()
113
+
114
+ # Check if source is a deployment ID
115
+ try:
116
+ source_type, _ = validate_agent_source(source)
117
+ except Exception:
118
+ # If validation fails, treat as file/directory
119
+ source_type = None
120
+
121
+ if source_type == "deployment_id":
122
+ # Handle deployment ID
123
+
124
+ echo_error(
125
+ f"Run command not support for Deployment, query the "
126
+ f"deployment by curl or by `agentscope chat {source}` ",
127
+ )
128
+ sys.exit(1)
129
+
130
+ else:
131
+ # Handle file/directory source - load and run agent locally
132
+ echo_info(f"Loading agent from: {source}")
133
+ loader = UnifiedAgentLoader(state_manager=state_manager)
134
+
135
+ try:
136
+ agent_app = loader.load(source, entrypoint=entrypoint)
137
+ echo_success("Agent loaded successfully")
138
+ except AgentLoadError as e:
139
+ echo_error(f"Failed to load agent: {e}")
140
+ sys.exit(1)
141
+
142
+ # Start the agent service
143
+ echo_info("Starting agent service...")
144
+ echo_info(f"Host: {host}")
145
+ echo_info(f"Port: {port}")
146
+ echo_info(
147
+ "The service will run continuously. Press Ctrl+C to stop.",
148
+ )
149
+
150
+ try:
151
+ # Run the agent service
152
+ agent_app.run(host=host, port=port)
153
+ except KeyboardInterrupt:
154
+ echo_warning("\nService interrupted by user")
155
+ sys.exit(0)
156
+ except Exception as e:
157
+ echo_error(f"Service error: {e}")
158
+ import traceback
159
+
160
+ if verbose:
161
+ traceback.print_exc()
162
+ sys.exit(1)
163
+
164
+ except KeyboardInterrupt:
165
+ echo_warning("\nInterrupted by user")
166
+ sys.exit(0)
167
+ except Exception as e:
168
+ echo_error(f"Unexpected error: {e}")
169
+ import traceback
170
+
171
+ traceback.print_exc()
172
+ sys.exit(1)
173
+
174
+
175
+ if __name__ == "__main__":
176
+ run()
@@ -0,0 +1,128 @@
1
+ # -*- coding: utf-8 -*-
2
+ """agentscope sandbox command - Sandbox management commands."""
3
+
4
+ import sys
5
+
6
+ import click
7
+
8
+ from agentscope_runtime.cli.utils.console import (
9
+ echo_error,
10
+ echo_info,
11
+ )
12
+
13
+
14
+ @click.group()
15
+ def sandbox():
16
+ """
17
+ Sandbox management commands.
18
+
19
+ This consolidates existing sandbox commands under a unified CLI.
20
+
21
+ Available commands:
22
+ \b
23
+ - mcp: Start MCP server for sandbox
24
+ - server: Start sandbox manager server
25
+ - build: Build sandbox environments
26
+ """
27
+
28
+
29
+ @sandbox.command()
30
+ @click.argument("args", nargs=-1, type=click.UNPROCESSED)
31
+ def mcp(args):
32
+ """
33
+ Start MCP server for sandbox (delegates to runtime-sandbox-mcp).
34
+
35
+ Examples:
36
+ \b
37
+ $ agentscope sandbox mcp
38
+ $ agentscope sandbox mcp --help
39
+ """
40
+ try:
41
+ from agentscope_runtime.sandbox.mcp_server import main as mcp_main
42
+
43
+ # Set sys.argv to simulate command line arguments
44
+ original_argv = sys.argv
45
+ sys.argv = ["runtime-sandbox-mcp"] + list(args)
46
+
47
+ try:
48
+ mcp_main()
49
+ finally:
50
+ # Restore original sys.argv
51
+ sys.argv = original_argv
52
+ except ImportError as e:
53
+ echo_error(f"Failed to import MCP server module: {e}")
54
+ echo_info("Make sure agentscope-runtime is properly installed")
55
+ sys.exit(1)
56
+ except Exception as e:
57
+ echo_error(f"Failed to run MCP server: {e}")
58
+ sys.exit(1)
59
+
60
+
61
+ @sandbox.command()
62
+ @click.argument("args", nargs=-1, type=click.UNPROCESSED)
63
+ def server(args):
64
+ """
65
+ Start sandbox manager server (delegates to runtime-sandbox-server).
66
+
67
+ Examples:
68
+ \b
69
+ $ agentscope sandbox server
70
+ $ agentscope sandbox server --help
71
+ """
72
+ try:
73
+ from agentscope_runtime.sandbox.manager.server.app import (
74
+ main as server_main,
75
+ )
76
+
77
+ # Set sys.argv to simulate command line arguments
78
+ original_argv = sys.argv
79
+ sys.argv = ["runtime-sandbox-server"] + list(args)
80
+
81
+ try:
82
+ server_main()
83
+ finally:
84
+ # Restore original sys.argv
85
+ sys.argv = original_argv
86
+ except ImportError as e:
87
+ echo_error(f"Failed to import sandbox server module: {e}")
88
+ echo_info("Make sure agentscope-runtime is properly installed")
89
+ sys.exit(1)
90
+ except Exception as e:
91
+ echo_error(f"Failed to run sandbox server: {e}")
92
+ sys.exit(1)
93
+
94
+
95
+ @sandbox.command()
96
+ @click.argument("args", nargs=-1, type=click.UNPROCESSED)
97
+ def build(args):
98
+ """
99
+ Build sandbox environments (delegates to runtime-sandbox-builder).
100
+
101
+ Examples:
102
+ \b
103
+ $ agentscope sandbox build
104
+ $ agentscope sandbox build --help
105
+ """
106
+ try:
107
+ from agentscope_runtime.sandbox.build import main as builder_main
108
+
109
+ # Set sys.argv to simulate command line arguments
110
+ original_argv = sys.argv
111
+ sys.argv = ["runtime-sandbox-builder"] + list(args)
112
+
113
+ try:
114
+ builder_main()
115
+ finally:
116
+ # Restore original sys.argv
117
+ sys.argv = original_argv
118
+ except ImportError as e:
119
+ echo_error(f"Failed to import sandbox builder module: {e}")
120
+ echo_info("Make sure agentscope-runtime is properly installed")
121
+ sys.exit(1)
122
+ except Exception as e:
123
+ echo_error(f"Failed to run sandbox builder: {e}")
124
+ sys.exit(1)
125
+
126
+
127
+ if __name__ == "__main__":
128
+ sandbox()
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+ """agentscope status command - Show deployment status."""
3
+ # pylint: disable=no-value-for-parameter
4
+
5
+ import sys
6
+
7
+ import click
8
+
9
+ from agentscope_runtime.engine.deployers.state import DeploymentStateManager
10
+ from agentscope_runtime.cli.utils.console import (
11
+ echo_error,
12
+ format_deployment_info,
13
+ format_json,
14
+ )
15
+
16
+
17
+ @click.command()
18
+ @click.argument("deploy_id", required=True)
19
+ @click.option(
20
+ "--output-format",
21
+ "-f",
22
+ help="Output format: text or json",
23
+ type=click.Choice(["text", "json"], case_sensitive=False),
24
+ default="text",
25
+ )
26
+ def status(deploy_id: str, output_format: str):
27
+ """
28
+ Show detailed deployment status.
29
+
30
+ Examples:
31
+ \b
32
+ # Show deployment status
33
+ $ agentscope status local_20250101_120000_abc123
34
+
35
+ # JSON output
36
+ $ agentscope status local_20250101_120000_abc123 --output-format json
37
+ """
38
+ try:
39
+ # Initialize state manager
40
+ state_manager = DeploymentStateManager()
41
+
42
+ # Get deployment
43
+ deployment = state_manager.get(deploy_id)
44
+
45
+ if deployment is None:
46
+ echo_error(f"Deployment not found: {deploy_id}")
47
+ sys.exit(1)
48
+
49
+ if output_format == "json":
50
+ print(format_json(deployment.to_dict()))
51
+ else:
52
+ print(format_deployment_info(deployment.to_dict()))
53
+
54
+ except Exception as e:
55
+ echo_error(f"Failed to get deployment status: {e}")
56
+ sys.exit(1)
57
+
58
+
59
+ if __name__ == "__main__":
60
+ status()
@@ -0,0 +1,185 @@
1
+ # -*- coding: utf-8 -*-
2
+ """agentscope stop command - Stop a deployment."""
3
+ # pylint: disable=too-many-return-statements, too-many-branches
4
+ # pylint: disable=no-value-for-parameter, too-many-statements, unused-argument
5
+
6
+ import asyncio
7
+ import sys
8
+ from typing import Optional
9
+
10
+ import click
11
+
12
+ from agentscope_runtime.engine.deployers.state import DeploymentStateManager
13
+ from agentscope_runtime.cli.utils.console import (
14
+ echo_error,
15
+ echo_info,
16
+ echo_success,
17
+ echo_warning,
18
+ confirm,
19
+ )
20
+ from agentscope_runtime.engine.deployers.base import DeployManager
21
+
22
+
23
+ def _create_deployer(
24
+ platform: str,
25
+ deployment_state: dict,
26
+ ) -> Optional[DeployManager]:
27
+ """Create deployer instance for platform.
28
+
29
+ Args:
30
+ platform: Platform name (local, k8s, modelstudio, agentrun)
31
+ deployment_state: Deployment state dictionary
32
+
33
+ Returns:
34
+ DeployManager instance or None if creation fails
35
+ """
36
+ try:
37
+ if platform == "local":
38
+ from agentscope_runtime.engine.deployers import (
39
+ LocalDeployManager,
40
+ )
41
+
42
+ return LocalDeployManager()
43
+ elif platform == "k8s":
44
+ from agentscope_runtime.engine.deployers import (
45
+ KubernetesDeployManager,
46
+ K8sConfig,
47
+ )
48
+
49
+ # Create K8sConfig with default namespace
50
+ k8s_config = K8sConfig(k8s_namespace="agentscope-runtime")
51
+ return KubernetesDeployManager(kube_config=k8s_config)
52
+ elif platform == "modelstudio":
53
+ from agentscope_runtime.engine.deployers import (
54
+ ModelstudioDeployManager,
55
+ )
56
+
57
+ return ModelstudioDeployManager()
58
+ elif platform == "agentrun":
59
+ from agentscope_runtime.engine.deployers.agentrun_deployer import (
60
+ AgentRunDeployManager,
61
+ )
62
+
63
+ return AgentRunDeployManager()
64
+ else:
65
+ echo_warning(f"Unknown platform: {platform}")
66
+ return None
67
+ except ImportError as e:
68
+ echo_warning(f"Failed to import deployer for platform {platform}: {e}")
69
+ return None
70
+ except Exception as e:
71
+ echo_warning(f"Failed to create deployer for platform {platform}: {e}")
72
+ return None
73
+
74
+
75
+ @click.command()
76
+ @click.argument("deploy_id", required=True)
77
+ @click.option(
78
+ "--yes",
79
+ "-y",
80
+ is_flag=True,
81
+ help="Skip confirmation prompt",
82
+ )
83
+ def stop(deploy_id: str, yes: bool):
84
+ """
85
+ Stop a deployment and clean up resources.
86
+
87
+ This command will:
88
+ 1. Call the platform-specific stop method to clean up deployed resources
89
+ 2. Update the local deployment status to 'stopped'
90
+
91
+ Use --force to skip platform cleanup and only update local state.
92
+
93
+ Examples:
94
+ \b
95
+ # Stop deployment with confirmation
96
+ $ agentscope stop local_20250101_120000_abc123
97
+
98
+ # Skip confirmation
99
+ $ agentscope stop local_20250101_120000_abc123 --yes
100
+
101
+ """
102
+ try:
103
+ # Initialize state manager
104
+ state_manager = DeploymentStateManager()
105
+
106
+ # Check if deployment exists
107
+ deployment = state_manager.get(deploy_id)
108
+
109
+ if deployment is None:
110
+ echo_error(f"Deployment not found: {deploy_id}")
111
+ sys.exit(1)
112
+
113
+ # Check current status
114
+ if deployment.status == "stopped":
115
+ echo_warning(f"Deployment {deploy_id} is already stopped")
116
+ return
117
+
118
+ # Get deployment info
119
+ platform = getattr(deployment, "platform", "unknown")
120
+
121
+ # Confirm
122
+ if not yes:
123
+ if not confirm(
124
+ f"Stop deployment {deploy_id} (platform: {platform})?",
125
+ ):
126
+ echo_info("Cancelled")
127
+ return
128
+
129
+ # Call deployer stop (unless --force)
130
+
131
+ echo_info(f"Calling platform cleanup for {platform}...")
132
+
133
+ deployer = _create_deployer(
134
+ platform,
135
+ deployment.__dict__ if hasattr(deployment, "__dict__") else {},
136
+ )
137
+
138
+ if deployer:
139
+ try:
140
+ # Call stop method - deployer will fetch all needed info
141
+ # from state
142
+ result = asyncio.run(deployer.stop(deploy_id))
143
+
144
+ if result.get("success"):
145
+ echo_success(
146
+ f"Platform cleanup: "
147
+ f"{result.get('message', 'Success')}",
148
+ )
149
+ else:
150
+ echo_error(
151
+ f"Platform cleanup failed: "
152
+ f"{result.get('message', 'Unknown error')}",
153
+ )
154
+ echo_error(
155
+ "Cannot mark deployment as stopped - platform "
156
+ "cleanup failed",
157
+ )
158
+ sys.exit(1)
159
+ except Exception as e:
160
+ echo_error(f"Error during platform cleanup: {e}")
161
+ echo_error(
162
+ "Cannot mark deployment as stopped - platform "
163
+ "cleanup failed",
164
+ )
165
+ sys.exit(1)
166
+ else:
167
+ echo_error(
168
+ f"Could not create deployer for platform: {platform}",
169
+ )
170
+ echo_error(
171
+ "Cannot mark deployment as stopped - deployer creation "
172
+ "failed",
173
+ )
174
+ echo_info(
175
+ "\nTip: Use --force flag to skip platform cleanup and "
176
+ "only update local state",
177
+ )
178
+ sys.exit(1)
179
+ except Exception as e:
180
+ echo_error(f"Failed to stop deployment: {e}")
181
+ sys.exit(1)
182
+
183
+
184
+ if __name__ == "__main__":
185
+ stop()