naas-abi-cli 1.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- naas_abi_cli/__init__.py +0 -0
- naas_abi_cli/cli/__init__.py +65 -0
- naas_abi_cli/cli/agent.py +30 -0
- naas_abi_cli/cli/chat.py +29 -0
- naas_abi_cli/cli/config.py +49 -0
- naas_abi_cli/cli/deploy.py +212 -0
- naas_abi_cli/cli/init.py +13 -0
- naas_abi_cli/cli/module.py +28 -0
- naas_abi_cli/cli/new/__init__.py +4 -0
- naas_abi_cli/cli/new/module.py +55 -0
- naas_abi_cli/cli/new/new.py +6 -0
- naas_abi_cli/cli/new/project.py +63 -0
- naas_abi_cli/cli/new/templates/module/__init__.py +31 -0
- naas_abi_cli/cli/new/templates/module/agents/README.md +0 -0
- naas_abi_cli/cli/new/templates/module/agents/{{module_name_pascal}}Agent.py +52 -0
- naas_abi_cli/cli/new/templates/module/orchestrations/README.md +0 -0
- naas_abi_cli/cli/new/templates/module/pipelines/README.md +0 -0
- naas_abi_cli/cli/new/templates/module/workflows/README.md +0 -0
- naas_abi_cli/cli/new/templates/project/.github/workflows/release.yaml +31 -0
- naas_abi_cli/cli/new/templates/project/.gitignore +3 -0
- naas_abi_cli/cli/new/templates/project/Dockerfile +11 -0
- naas_abi_cli/cli/new/templates/project/README.md +0 -0
- naas_abi_cli/cli/new/templates/project/config.prod.yaml +70 -0
- naas_abi_cli/cli/new/templates/project/config.yaml +62 -0
- naas_abi_cli/cli/new/templates/project/pyproject.toml +21 -0
- naas_abi_cli/cli/run.py +18 -0
- naas_abi_cli/cli/secret.py +79 -0
- naas_abi_cli/cli/utils/Copier.py +84 -0
- naas_abi_cli-1.8.0.dist-info/METADATA +243 -0
- naas_abi_cli-1.8.0.dist-info/RECORD +32 -0
- naas_abi_cli-1.8.0.dist-info/WHEEL +4 -0
- naas_abi_cli-1.8.0.dist-info/entry_points.txt +2 -0
naas_abi_cli/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from .agent import agent
|
|
8
|
+
from .chat import chat
|
|
9
|
+
from .config import config
|
|
10
|
+
from .deploy import deploy
|
|
11
|
+
from .init import init
|
|
12
|
+
from .module import module
|
|
13
|
+
from .new import new
|
|
14
|
+
from .run import run
|
|
15
|
+
from .secret import secrets
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.group("abi")
|
|
19
|
+
def _main():
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_main.add_command(secrets)
|
|
24
|
+
_main.add_command(config)
|
|
25
|
+
_main.add_command(module)
|
|
26
|
+
_main.add_command(agent)
|
|
27
|
+
_main.add_command(chat)
|
|
28
|
+
_main.add_command(new)
|
|
29
|
+
_main.add_command(init)
|
|
30
|
+
_main.add_command(deploy)
|
|
31
|
+
_main.add_command(run)
|
|
32
|
+
|
|
33
|
+
ran = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main():
|
|
37
|
+
global ran
|
|
38
|
+
if ran:
|
|
39
|
+
return
|
|
40
|
+
ran = True
|
|
41
|
+
|
|
42
|
+
# Check how the project is being runned.
|
|
43
|
+
if os.getenv("LOCAL_UV_RAN") is None:
|
|
44
|
+
if "pyproject.toml" in os.listdir(os.getcwd()):
|
|
45
|
+
with open("pyproject.toml", "r") as file:
|
|
46
|
+
if "naas-abi-cli" in file.read():
|
|
47
|
+
arguments = (
|
|
48
|
+
"uv run --active python -m naas_abi_cli.cli".split(" ")
|
|
49
|
+
+ sys.argv[1:]
|
|
50
|
+
)
|
|
51
|
+
try:
|
|
52
|
+
subprocess.run(
|
|
53
|
+
arguments,
|
|
54
|
+
cwd=os.getcwd(),
|
|
55
|
+
env={**os.environ, "LOCAL_UV_RAN": "true"},
|
|
56
|
+
check=True,
|
|
57
|
+
)
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
return
|
|
62
|
+
_main()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
main()
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from rich.table import Table
|
|
4
|
+
|
|
5
|
+
from naas_abi_core.engine.Engine import Engine
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group("agent")
|
|
9
|
+
def agent():
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@agent.command("list")
|
|
14
|
+
def list():
|
|
15
|
+
engine = Engine()
|
|
16
|
+
engine.load()
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
table = Table(
|
|
20
|
+
title="Available Agents", show_header=True, header_style="bold magenta"
|
|
21
|
+
)
|
|
22
|
+
table.add_column("Module", style="cyan", no_wrap=True)
|
|
23
|
+
table.add_column("Agent", style="green")
|
|
24
|
+
|
|
25
|
+
modules = engine.modules
|
|
26
|
+
for module in modules:
|
|
27
|
+
for agent in modules[module].agents:
|
|
28
|
+
table.add_row(module, agent.__name__)
|
|
29
|
+
|
|
30
|
+
console.print(table)
|
naas_abi_cli/cli/chat.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from naas_abi_core import logger
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@click.command("chat")
|
|
6
|
+
@click.argument("module-name", type=str, default="")
|
|
7
|
+
@click.argument("agent-name", type=str, default="")
|
|
8
|
+
def chat(module_name: str = "", agent_name: str = ""):
|
|
9
|
+
from naas_abi_core.engine.Engine import Engine
|
|
10
|
+
|
|
11
|
+
engine = Engine()
|
|
12
|
+
|
|
13
|
+
if module_name == "" and agent_name == "":
|
|
14
|
+
module_name, agent_name = engine.configuration.default_agent.split(" ")
|
|
15
|
+
|
|
16
|
+
engine.load(module_names=[module_name])
|
|
17
|
+
|
|
18
|
+
from naas_abi_core.apps.terminal_agent.main import run_agent
|
|
19
|
+
|
|
20
|
+
if module_name not in engine.modules:
|
|
21
|
+
raise ValueError(f"Module {module_name} not found")
|
|
22
|
+
|
|
23
|
+
logger.debug(f"Module agents: {engine.modules[module_name].agents}")
|
|
24
|
+
|
|
25
|
+
for agent_class in engine.modules[module_name].agents:
|
|
26
|
+
logger.debug(f"Agent class: {agent_class.__name__}")
|
|
27
|
+
if agent_class.__name__ == agent_name:
|
|
28
|
+
run_agent(agent_class.New())
|
|
29
|
+
break
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import yaml
|
|
5
|
+
|
|
6
|
+
from naas_abi_core.engine.engine_configuration.EngineConfiguration import (
|
|
7
|
+
EngineConfiguration,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group("config")
|
|
12
|
+
def config():
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@config.command("validate")
|
|
17
|
+
@click.option("--configuration-file", type=str, required=False, default=None)
|
|
18
|
+
def validate(configuration_file: str | None):
|
|
19
|
+
configuration_content: str | None = None
|
|
20
|
+
|
|
21
|
+
if configuration_file is not None:
|
|
22
|
+
if not os.path.exists(configuration_file):
|
|
23
|
+
raise FileNotFoundError(
|
|
24
|
+
f"Configuration file {configuration_file} not found"
|
|
25
|
+
)
|
|
26
|
+
with open(configuration_file, "r") as file:
|
|
27
|
+
configuration_content = file.read()
|
|
28
|
+
|
|
29
|
+
EngineConfiguration.load_configuration(configuration_content)
|
|
30
|
+
print("Configuration is valid")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@config.command("render")
|
|
34
|
+
@click.option("--configuration-file", type=str, required=False, default=None)
|
|
35
|
+
def render(configuration_file: str | None):
|
|
36
|
+
configuration_content: str | None = None
|
|
37
|
+
|
|
38
|
+
if configuration_file is not None:
|
|
39
|
+
if not os.path.exists(configuration_file):
|
|
40
|
+
raise FileNotFoundError(
|
|
41
|
+
f"Configuration file {configuration_file} not found"
|
|
42
|
+
)
|
|
43
|
+
with open(configuration_file, "r") as file:
|
|
44
|
+
configuration_content = file.read()
|
|
45
|
+
|
|
46
|
+
configuration: EngineConfiguration = EngineConfiguration.load_configuration(
|
|
47
|
+
configuration_content
|
|
48
|
+
)
|
|
49
|
+
print(yaml.dump(configuration.model_dump(), indent=2))
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
import requests
|
|
7
|
+
from naas_abi_core import logger
|
|
8
|
+
from naas_abi_core.engine.engine_configuration.EngineConfiguration import (
|
|
9
|
+
EngineConfiguration,
|
|
10
|
+
)
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.markdown import Markdown
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.group("deploy")
|
|
17
|
+
def deploy():
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Container(BaseModel):
|
|
22
|
+
name: str
|
|
23
|
+
image: str
|
|
24
|
+
port: int
|
|
25
|
+
cpu: str
|
|
26
|
+
memory: str
|
|
27
|
+
env: dict
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Space(BaseModel):
|
|
31
|
+
name: str
|
|
32
|
+
containers: list[Container]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NaasAPIClient:
|
|
36
|
+
naas_api_key: str
|
|
37
|
+
base_url: str
|
|
38
|
+
|
|
39
|
+
def __init__(self, naas_api_key: str):
|
|
40
|
+
self.naas_api_key = naas_api_key
|
|
41
|
+
self.base_url = "https://api.naas.ai"
|
|
42
|
+
|
|
43
|
+
def create_registry(self, name: str):
|
|
44
|
+
response = requests.post(
|
|
45
|
+
f"{self.base_url}/registry/",
|
|
46
|
+
headers={"Authorization": f"Bearer {self.naas_api_key}"},
|
|
47
|
+
json={"name": name},
|
|
48
|
+
)
|
|
49
|
+
if response.status_code == 409:
|
|
50
|
+
return self.get_registry(name)
|
|
51
|
+
response.raise_for_status()
|
|
52
|
+
return response.json()
|
|
53
|
+
|
|
54
|
+
def get_registry(self, name: str):
|
|
55
|
+
response = requests.get(
|
|
56
|
+
f"{self.base_url}/registry/{name}",
|
|
57
|
+
headers={"Authorization": f"Bearer {self.naas_api_key}"},
|
|
58
|
+
)
|
|
59
|
+
response.raise_for_status()
|
|
60
|
+
return response.json()
|
|
61
|
+
|
|
62
|
+
def get_registry_credentials(self, name: str):
|
|
63
|
+
response = requests.get(
|
|
64
|
+
f"{self.base_url}/registry/{name}/credentials",
|
|
65
|
+
headers={"Authorization": f"Bearer {self.naas_api_key}"},
|
|
66
|
+
)
|
|
67
|
+
response.raise_for_status()
|
|
68
|
+
return response.json()
|
|
69
|
+
|
|
70
|
+
def update_space(self, space: Space) -> dict:
|
|
71
|
+
response = requests.put(
|
|
72
|
+
f"{self.base_url}/space/{space.name}",
|
|
73
|
+
headers={"Authorization": f"Bearer {self.naas_api_key}"},
|
|
74
|
+
json=space.model_dump(),
|
|
75
|
+
)
|
|
76
|
+
response.raise_for_status()
|
|
77
|
+
return response.json()
|
|
78
|
+
|
|
79
|
+
def create_space(self, space: Space) -> dict:
|
|
80
|
+
response = requests.post(
|
|
81
|
+
f"{self.base_url}/space/",
|
|
82
|
+
headers={"Authorization": f"Bearer {self.naas_api_key}"},
|
|
83
|
+
json=space.model_dump(),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if response.status_code == 409:
|
|
87
|
+
return self.update_space(space)
|
|
88
|
+
elif response.status_code == 402:
|
|
89
|
+
raise click.ClickException(
|
|
90
|
+
"You must have an active subscription to create a space on naas.ai."
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
return response.json()
|
|
95
|
+
|
|
96
|
+
def get_space(self, name: str) -> dict:
|
|
97
|
+
response = requests.get(
|
|
98
|
+
f"{self.base_url}/space/{name}",
|
|
99
|
+
headers={"Authorization": f"Bearer {self.naas_api_key}"},
|
|
100
|
+
)
|
|
101
|
+
response.raise_for_status()
|
|
102
|
+
return response.json()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class NaasDeployer:
|
|
106
|
+
image_name: str
|
|
107
|
+
|
|
108
|
+
naas_api_client: NaasAPIClient
|
|
109
|
+
|
|
110
|
+
def __init__(self, configuration: EngineConfiguration):
|
|
111
|
+
self.configuration = configuration
|
|
112
|
+
self.image_name = str(uuid4())
|
|
113
|
+
if configuration.deploy is None:
|
|
114
|
+
# Fail fast with a clear, user-facing error instead of an assertion.
|
|
115
|
+
raise click.ClickException(
|
|
116
|
+
"Deploy configuration is missing; please add a deploy section before running this command."
|
|
117
|
+
)
|
|
118
|
+
self.naas_api_client = NaasAPIClient(configuration.deploy.naas_api_key)
|
|
119
|
+
|
|
120
|
+
def docker_build(self, image_name: str):
|
|
121
|
+
subprocess.run(
|
|
122
|
+
f"docker build -t {image_name} . --platform linux/amd64", shell=True
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def deploy(self):
|
|
126
|
+
assert self.configuration.deploy is not None
|
|
127
|
+
registry = self.naas_api_client.create_registry(
|
|
128
|
+
self.configuration.deploy.space_name
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
uid = str(uuid4())
|
|
132
|
+
|
|
133
|
+
image_name = f"{registry['registry']['uri']}:{uid}"
|
|
134
|
+
self.docker_build(image_name)
|
|
135
|
+
credentials = self.naas_api_client.get_registry_credentials(
|
|
136
|
+
self.configuration.deploy.space_name
|
|
137
|
+
)
|
|
138
|
+
docker_login_command = f"docker login -u {credentials['credentials']['username']} -p {credentials['credentials']['password']} {registry['registry']['uri']}"
|
|
139
|
+
subprocess.run(docker_login_command, shell=True)
|
|
140
|
+
subprocess.run(f"docker push {image_name}", shell=True)
|
|
141
|
+
|
|
142
|
+
image_sha = (
|
|
143
|
+
subprocess.run(
|
|
144
|
+
"docker inspect --format='{{index .RepoDigests 0}}' "
|
|
145
|
+
+ image_name
|
|
146
|
+
+ " | cut -d'@' -f2",
|
|
147
|
+
shell=True,
|
|
148
|
+
capture_output=True,
|
|
149
|
+
)
|
|
150
|
+
.stdout.strip()
|
|
151
|
+
.decode("utf-8")
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if image_sha is None or image_sha == "":
|
|
155
|
+
raise click.ClickException(
|
|
156
|
+
"Failed to get image SHA. Please check if the image is correctly built and pushed to the registry."
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
image_name_with_sha = f"{image_name.replace(':' + uid, '')}@{image_sha}"
|
|
160
|
+
|
|
161
|
+
self.naas_api_client.create_space(
|
|
162
|
+
Space(
|
|
163
|
+
name=self.configuration.deploy.space_name,
|
|
164
|
+
containers=[
|
|
165
|
+
Container(
|
|
166
|
+
name="api",
|
|
167
|
+
image=image_name_with_sha,
|
|
168
|
+
port=9879,
|
|
169
|
+
cpu="1",
|
|
170
|
+
memory="1Gi",
|
|
171
|
+
env=self.configuration.deploy.env,
|
|
172
|
+
)
|
|
173
|
+
],
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
self.naas_api_client.get_space(self.configuration.deploy.space_name)
|
|
178
|
+
|
|
179
|
+
Console().print(
|
|
180
|
+
Markdown(f"""
|
|
181
|
+
# Deployment successful
|
|
182
|
+
|
|
183
|
+
- Space: {self.configuration.deploy.space_name}
|
|
184
|
+
- Image: {image_name_with_sha}
|
|
185
|
+
- URL: https://{self.configuration.deploy.space_name}.default.space.naas.ai
|
|
186
|
+
|
|
187
|
+
""")
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@deploy.command("naas")
|
|
192
|
+
@click.option(
|
|
193
|
+
"-e",
|
|
194
|
+
"--env",
|
|
195
|
+
type=str,
|
|
196
|
+
default="prod",
|
|
197
|
+
help="Environment to use (default: prod). This is used to know which configuration file to load. (config.prod.yaml, config.yaml, ...)",
|
|
198
|
+
)
|
|
199
|
+
def naas(env: str):
|
|
200
|
+
# Set the ENV environment variable for the EngineConfiguration.load_configuration() to load the correct configuration file.
|
|
201
|
+
os.environ["ENV"] = env
|
|
202
|
+
|
|
203
|
+
configuration: EngineConfiguration = EngineConfiguration.load_configuration()
|
|
204
|
+
|
|
205
|
+
if configuration.deploy is None:
|
|
206
|
+
logger.error(
|
|
207
|
+
"Deploy configuration not found in the yaml configuration file. Please add a deploy section to the configuration file."
|
|
208
|
+
)
|
|
209
|
+
raise click.ClickException("Missing deploy configuration; aborting.")
|
|
210
|
+
|
|
211
|
+
deployer = NaasDeployer(configuration)
|
|
212
|
+
deployer.deploy()
|
naas_abi_cli/cli/init.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from naas_abi_core.engine.engine_configuration.EngineConfiguration import (
|
|
3
|
+
EngineConfiguration,
|
|
4
|
+
)
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group("module")
|
|
10
|
+
def module():
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@module.command("list")
|
|
15
|
+
def list() -> None:
|
|
16
|
+
configuration: EngineConfiguration = EngineConfiguration.load_configuration()
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
table = Table(
|
|
20
|
+
title="Available Modules", show_header=True, header_style="bold magenta"
|
|
21
|
+
)
|
|
22
|
+
table.add_column("Module", style="cyan", no_wrap=True)
|
|
23
|
+
table.add_column("Enabled", style="green")
|
|
24
|
+
|
|
25
|
+
for module in configuration.modules:
|
|
26
|
+
table.add_row(module.module, str(module.enabled))
|
|
27
|
+
|
|
28
|
+
console.print(table)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import naas_abi_cli
|
|
5
|
+
from naas_abi_cli.cli.utils.Copier import Copier
|
|
6
|
+
|
|
7
|
+
from .new import new
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def sanitize_module_name(module_name: str) -> str:
|
|
11
|
+
return module_name.replace("-", "_").replace(" ", "_").lower()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@new.command("module")
|
|
15
|
+
@click.argument("module_name", required=True)
|
|
16
|
+
@click.argument("module_path", required=False, default=".")
|
|
17
|
+
def _new_module(module_name: str, module_path: str = "."):
|
|
18
|
+
new_module(module_name, module_path)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def new_module(module_name: str, module_path: str = ".", quiet: bool = False):
|
|
22
|
+
module_name = sanitize_module_name(module_name)
|
|
23
|
+
|
|
24
|
+
if module_path == ".":
|
|
25
|
+
module_path = os.path.join(os.getcwd(), module_name)
|
|
26
|
+
else:
|
|
27
|
+
module_path = os.path.join(module_path, module_name)
|
|
28
|
+
|
|
29
|
+
if not os.path.exists(module_path):
|
|
30
|
+
os.makedirs(module_path, exist_ok=True)
|
|
31
|
+
elif len(os.listdir(module_path)) > 0:
|
|
32
|
+
print(f"Folder {module_path} already exists and is not empty.")
|
|
33
|
+
exit(1)
|
|
34
|
+
|
|
35
|
+
copier = Copier(
|
|
36
|
+
templates_path=os.path.join(
|
|
37
|
+
os.path.dirname(naas_abi_cli.__file__), "cli/new/templates/module"
|
|
38
|
+
),
|
|
39
|
+
destination_path=module_path,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
copier.copy(
|
|
43
|
+
values={
|
|
44
|
+
"module_name": module_name,
|
|
45
|
+
"module_name_snake": module_name.replace("-", "_"),
|
|
46
|
+
"module_name_pascal": module_name.replace("-", "").capitalize(),
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if not quiet:
|
|
51
|
+
print(f"\nModule '{module_name}' has been created at:\n {module_path}\n")
|
|
52
|
+
print("To enable this module, add the following to your config.yaml:\n")
|
|
53
|
+
print("modules:")
|
|
54
|
+
print(f" - path: {module_path}")
|
|
55
|
+
print(" enabled: true\n")
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
import naas_abi_cli
|
|
6
|
+
from naas_abi_cli.cli.utils.Copier import Copier
|
|
7
|
+
|
|
8
|
+
from .module import new_module
|
|
9
|
+
from .new import new
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@new.command("project")
|
|
13
|
+
@click.argument("project-name", required=False, default=None)
|
|
14
|
+
@click.argument("project-path", required=False, default=None)
|
|
15
|
+
def new_project(project_name: str | None, project_path: str | None):
|
|
16
|
+
# Defaults must be evaluated at runtime so they reflect the caller's CWD.
|
|
17
|
+
if project_name is None:
|
|
18
|
+
project_name = os.path.basename(os.getcwd())
|
|
19
|
+
if project_path is None:
|
|
20
|
+
project_path = os.getcwd()
|
|
21
|
+
# Resolve relative segments (., ..) and user home (~) to a normalized absolute path.
|
|
22
|
+
project_path = os.path.abspath(os.path.expanduser(project_path))
|
|
23
|
+
|
|
24
|
+
# Ensure the last path component matches the project name, not just the suffix.
|
|
25
|
+
if os.path.basename(os.path.normpath(project_path)) != project_name:
|
|
26
|
+
project_path = os.path.join(project_path, project_name)
|
|
27
|
+
|
|
28
|
+
if not os.path.exists(project_path):
|
|
29
|
+
os.makedirs(project_path, exist_ok=True)
|
|
30
|
+
elif len(os.listdir(project_path)) > 0:
|
|
31
|
+
print(f"Folder {project_path} already exists and is not empty.")
|
|
32
|
+
exit(1)
|
|
33
|
+
|
|
34
|
+
copier = Copier(
|
|
35
|
+
templates_path=os.path.join(
|
|
36
|
+
os.path.dirname(naas_abi_cli.__file__), "cli/new/templates/project"
|
|
37
|
+
),
|
|
38
|
+
destination_path=project_path,
|
|
39
|
+
)
|
|
40
|
+
copier.copy(
|
|
41
|
+
values={
|
|
42
|
+
"project_name": project_name,
|
|
43
|
+
"project_name_snake": project_name.replace("-", "_"),
|
|
44
|
+
"project_name_pascal": project_name.replace("-", "").capitalize(),
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Calling new_module to create the module in the src folder
|
|
49
|
+
new_module(project_name, os.path.join(project_path, "src"), quiet=True)
|
|
50
|
+
|
|
51
|
+
# Run dependency install without shell to avoid quoting issues on paths with spaces.
|
|
52
|
+
subprocess.run(
|
|
53
|
+
[
|
|
54
|
+
"uv",
|
|
55
|
+
"add",
|
|
56
|
+
"naas-abi-core[all]",
|
|
57
|
+
"naas-abi-marketplace[ai-chatgpt]",
|
|
58
|
+
"naas-abi",
|
|
59
|
+
"naas-abi-cli",
|
|
60
|
+
],
|
|
61
|
+
cwd=project_path,
|
|
62
|
+
check=True,
|
|
63
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from naas_abi_core.module.Module import (
|
|
2
|
+
BaseModule,
|
|
3
|
+
ModuleConfiguration,
|
|
4
|
+
ModuleDependencies,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
# from naas_abi_core.services.object_storage.ObjectStorageService import ObjectStorageService
|
|
8
|
+
# from naas_abi_core.services.secret.Secret import Secret
|
|
9
|
+
# from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
|
|
10
|
+
# from naas_abi_core.services.vector_store.VectorStoreService import VectorStoreService
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ABIModule(BaseModule):
|
|
14
|
+
dependencies: ModuleDependencies = ModuleDependencies(
|
|
15
|
+
modules=[
|
|
16
|
+
"naas_abi_marketplace.ai.chatgpt",
|
|
17
|
+
],
|
|
18
|
+
services=[
|
|
19
|
+
# Secret,
|
|
20
|
+
# TripleStoreService,
|
|
21
|
+
# ObjectStorageService,
|
|
22
|
+
# VectorStoreService
|
|
23
|
+
],
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
class Configuration(ModuleConfiguration):
|
|
27
|
+
pass
|
|
28
|
+
# example: str
|
|
29
|
+
|
|
30
|
+
def on_initialized(self):
|
|
31
|
+
super().on_initialized()
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from naas_abi_core.services.agent.Agent import (
|
|
4
|
+
Agent,
|
|
5
|
+
AgentConfiguration,
|
|
6
|
+
AgentSharedState,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
NAME = "{{module_name_snake}} Agent"
|
|
10
|
+
DESCRIPTION = "An helpful agent that can help you with your tasks."
|
|
11
|
+
SYSTEM_PROMPT = """
|
|
12
|
+
You are {{module_name_snake}} Agent.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_agent(
|
|
17
|
+
agent_shared_state: Optional[AgentSharedState] = None,
|
|
18
|
+
agent_configuration: Optional[AgentConfiguration] = None,
|
|
19
|
+
) -> Optional[Agent]:
|
|
20
|
+
#from {{module_name_snake}} import ABIModule
|
|
21
|
+
|
|
22
|
+
# Set model
|
|
23
|
+
from naas_abi_marketplace.ai.chatgpt.models.gpt_5 import model as chatgpt_model
|
|
24
|
+
|
|
25
|
+
model = chatgpt_model.model
|
|
26
|
+
|
|
27
|
+
# Use provided configuration or create default one
|
|
28
|
+
if agent_configuration is None:
|
|
29
|
+
agent_configuration = AgentConfiguration(system_prompt=SYSTEM_PROMPT)
|
|
30
|
+
|
|
31
|
+
# Use provided shared state or create new one
|
|
32
|
+
if agent_shared_state is None:
|
|
33
|
+
agent_shared_state = AgentSharedState()
|
|
34
|
+
|
|
35
|
+
tools: list = []
|
|
36
|
+
|
|
37
|
+
agents: list = []
|
|
38
|
+
|
|
39
|
+
return {{module_name_pascal}}Agent(
|
|
40
|
+
name=NAME,
|
|
41
|
+
description=DESCRIPTION,
|
|
42
|
+
chat_model=model,
|
|
43
|
+
tools=tools,
|
|
44
|
+
agents=agents,
|
|
45
|
+
memory=None,
|
|
46
|
+
state=agent_shared_state,
|
|
47
|
+
configuration=agent_configuration,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class {{module_name_pascal}}Agent(Agent):
|
|
52
|
+
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
deploy:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout repository
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.11"
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install uv
|
|
24
|
+
|
|
25
|
+
- name: Deploy
|
|
26
|
+
env:
|
|
27
|
+
NAAS_API_KEY: ${{ '{{ secrets.NAAS_API_KEY }}' }}
|
|
28
|
+
ENV: prod
|
|
29
|
+
run: |
|
|
30
|
+
uv sync --no-dev
|
|
31
|
+
uv run python -m naas_abi_cli.cli deploy naas
|