naas-abi-core 1.0.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_core/__init__.py +1 -0
- naas_abi_core/apps/api/api.py +242 -0
- naas_abi_core/apps/api/api_test.py +281 -0
- naas_abi_core/apps/api/openapi_doc.py +307 -0
- naas_abi_core/apps/mcp/mcp_server.py +243 -0
- naas_abi_core/apps/mcp/mcp_server_test.py +163 -0
- naas_abi_core/apps/terminal_agent/main.py +555 -0
- naas_abi_core/apps/terminal_agent/terminal_style.py +175 -0
- naas_abi_core/cli/__init__.py +53 -0
- naas_abi_core/cli/agent.py +30 -0
- naas_abi_core/cli/chat.py +26 -0
- naas_abi_core/cli/config.py +49 -0
- naas_abi_core/cli/init.py +13 -0
- naas_abi_core/cli/module.py +28 -0
- naas_abi_core/cli/new.py +13 -0
- naas_abi_core/cli/secret.py +79 -0
- naas_abi_core/engine/Engine.py +87 -0
- naas_abi_core/engine/EngineProxy.py +109 -0
- naas_abi_core/engine/Engine_test.py +6 -0
- naas_abi_core/engine/IEngine.py +91 -0
- naas_abi_core/engine/conftest.py +45 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration.py +160 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_GenericLoader.py +49 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService.py +131 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService_test.py +26 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_SecretService.py +116 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_TripleStoreService.py +171 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_VectorStoreService.py +65 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_test.py +9 -0
- naas_abi_core/engine/engine_configuration/utils/PydanticModelValidator.py +15 -0
- naas_abi_core/engine/engine_loaders/EngineModuleLoader.py +302 -0
- naas_abi_core/engine/engine_loaders/EngineOntologyLoader.py +16 -0
- naas_abi_core/engine/engine_loaders/EngineServiceLoader.py +47 -0
- naas_abi_core/integration/__init__.py +7 -0
- naas_abi_core/integration/integration.py +28 -0
- naas_abi_core/models/Model.py +198 -0
- naas_abi_core/models/OpenRouter.py +15 -0
- naas_abi_core/models/OpenRouter_test.py +36 -0
- naas_abi_core/module/Module.py +245 -0
- naas_abi_core/module/ModuleAgentLoader.py +49 -0
- naas_abi_core/module/ModuleUtils.py +20 -0
- naas_abi_core/modules/templatablesparqlquery/README.md +196 -0
- naas_abi_core/modules/templatablesparqlquery/__init__.py +39 -0
- naas_abi_core/modules/templatablesparqlquery/ontologies/TemplatableSparqlQueryOntology.ttl +116 -0
- naas_abi_core/modules/templatablesparqlquery/workflows/GenericWorkflow.py +48 -0
- naas_abi_core/modules/templatablesparqlquery/workflows/TemplatableSparqlQueryLoader.py +192 -0
- naas_abi_core/pipeline/__init__.py +6 -0
- naas_abi_core/pipeline/pipeline.py +70 -0
- naas_abi_core/services/__init__.py +0 -0
- naas_abi_core/services/agent/Agent.py +1619 -0
- naas_abi_core/services/agent/AgentMemory_test.py +28 -0
- naas_abi_core/services/agent/Agent_test.py +214 -0
- naas_abi_core/services/agent/IntentAgent.py +1171 -0
- naas_abi_core/services/agent/IntentAgent_test.py +139 -0
- naas_abi_core/services/agent/beta/Embeddings.py +180 -0
- naas_abi_core/services/agent/beta/IntentMapper.py +119 -0
- naas_abi_core/services/agent/beta/LocalModel.py +88 -0
- naas_abi_core/services/agent/beta/VectorStore.py +89 -0
- naas_abi_core/services/agent/test_agent_memory.py +278 -0
- naas_abi_core/services/agent/test_postgres_integration.py +145 -0
- naas_abi_core/services/cache/CacheFactory.py +31 -0
- naas_abi_core/services/cache/CachePort.py +63 -0
- naas_abi_core/services/cache/CacheService.py +246 -0
- naas_abi_core/services/cache/CacheService_test.py +85 -0
- naas_abi_core/services/cache/adapters/secondary/CacheFSAdapter.py +39 -0
- naas_abi_core/services/object_storage/ObjectStorageFactory.py +57 -0
- naas_abi_core/services/object_storage/ObjectStoragePort.py +47 -0
- naas_abi_core/services/object_storage/ObjectStorageService.py +41 -0
- naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterFS.py +52 -0
- naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterNaas.py +131 -0
- naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterS3.py +171 -0
- naas_abi_core/services/ontology/OntologyPorts.py +36 -0
- naas_abi_core/services/ontology/OntologyService.py +17 -0
- naas_abi_core/services/ontology/adaptors/secondary/OntologyService_SecondaryAdaptor_NERPort.py +37 -0
- naas_abi_core/services/secret/Secret.py +138 -0
- naas_abi_core/services/secret/SecretPorts.py +40 -0
- naas_abi_core/services/secret/Secret_test.py +65 -0
- naas_abi_core/services/secret/adaptors/secondary/Base64Secret.py +57 -0
- naas_abi_core/services/secret/adaptors/secondary/Base64Secret_test.py +39 -0
- naas_abi_core/services/secret/adaptors/secondary/NaasSecret.py +81 -0
- naas_abi_core/services/secret/adaptors/secondary/NaasSecret_test.py +25 -0
- naas_abi_core/services/secret/adaptors/secondary/dotenv_secret_secondaryadaptor.py +26 -0
- naas_abi_core/services/triple_store/TripleStoreFactory.py +116 -0
- naas_abi_core/services/triple_store/TripleStorePorts.py +223 -0
- naas_abi_core/services/triple_store/TripleStoreService.py +419 -0
- naas_abi_core/services/triple_store/adaptors/secondary/AWSNeptune.py +1284 -0
- naas_abi_core/services/triple_store/adaptors/secondary/AWSNeptune_test.py +284 -0
- naas_abi_core/services/triple_store/adaptors/secondary/Oxigraph.py +597 -0
- naas_abi_core/services/triple_store/adaptors/secondary/Oxigraph_test.py +1474 -0
- naas_abi_core/services/triple_store/adaptors/secondary/TripleStoreService__SecondaryAdaptor__Filesystem.py +223 -0
- naas_abi_core/services/triple_store/adaptors/secondary/TripleStoreService__SecondaryAdaptor__ObjectStorage.py +234 -0
- naas_abi_core/services/triple_store/adaptors/secondary/base/TripleStoreService__SecondaryAdaptor__FileBase.py +18 -0
- naas_abi_core/services/vector_store/IVectorStorePort.py +101 -0
- naas_abi_core/services/vector_store/IVectorStorePort_test.py +189 -0
- naas_abi_core/services/vector_store/VectorStoreFactory.py +47 -0
- naas_abi_core/services/vector_store/VectorStoreService.py +171 -0
- naas_abi_core/services/vector_store/VectorStoreService_test.py +185 -0
- naas_abi_core/services/vector_store/__init__.py +13 -0
- naas_abi_core/services/vector_store/adapters/QdrantAdapter.py +251 -0
- naas_abi_core/services/vector_store/adapters/QdrantAdapter_test.py +57 -0
- naas_abi_core/utils/Expose.py +53 -0
- naas_abi_core/utils/Graph.py +182 -0
- naas_abi_core/utils/JSON.py +49 -0
- naas_abi_core/utils/LazyLoader.py +44 -0
- naas_abi_core/utils/Logger.py +12 -0
- naas_abi_core/utils/OntologyReasoner.py +141 -0
- naas_abi_core/utils/OntologyYaml.disabled.py +679 -0
- naas_abi_core/utils/SPARQL.py +256 -0
- naas_abi_core/utils/Storage.py +33 -0
- naas_abi_core/utils/StorageUtils.py +398 -0
- naas_abi_core/utils/String.py +52 -0
- naas_abi_core/utils/Workers.py +114 -0
- naas_abi_core/utils/__init__.py +0 -0
- naas_abi_core/utils/onto2py/README.md +0 -0
- naas_abi_core/utils/onto2py/__init__.py +10 -0
- naas_abi_core/utils/onto2py/__main__.py +29 -0
- naas_abi_core/utils/onto2py/onto2py.py +611 -0
- naas_abi_core/utils/onto2py/tests/ttl2py_test.py +271 -0
- naas_abi_core/workflow/__init__.py +5 -0
- naas_abi_core/workflow/workflow.py +48 -0
- naas_abi_core-1.0.0.dist-info/METADATA +75 -0
- naas_abi_core-1.0.0.dist-info/RECORD +124 -0
- naas_abi_core-1.0.0.dist-info/WHEEL +4 -0
- naas_abi_core-1.0.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from rich.console import Console
|
|
2
|
+
from rich.markdown import Markdown
|
|
3
|
+
from rich.panel import Panel
|
|
4
|
+
from rich.syntax import Syntax
|
|
5
|
+
from rich.text import Text
|
|
6
|
+
from rich.box import ROUNDED
|
|
7
|
+
from PIL import Image
|
|
8
|
+
import os
|
|
9
|
+
import platform
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def set_terminal_title():
|
|
16
|
+
"""Set the terminal title to 'ABI'"""
|
|
17
|
+
if platform.system() == "Windows":
|
|
18
|
+
os.system("title ABI")
|
|
19
|
+
else: # For Unix-like systems (Linux, macOS)
|
|
20
|
+
print("\33]0;ABI\a", end="", flush=True)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def print_agent_response(text, agent_label):
|
|
24
|
+
console.print() # Add a blank line before the assistant's response
|
|
25
|
+
console.print(f"[bold green]{agent_label}:[/bold green] ", end="")
|
|
26
|
+
md = Markdown(text)
|
|
27
|
+
console.print(md)
|
|
28
|
+
console.print() # Add a blank line after the assistant's response
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def print_system_message(text):
|
|
32
|
+
console.print() # Add a blank line before the system message
|
|
33
|
+
system_text = Text(text, style="yellow")
|
|
34
|
+
console.print(
|
|
35
|
+
Panel(
|
|
36
|
+
system_text,
|
|
37
|
+
border_style="yellow",
|
|
38
|
+
box=ROUNDED,
|
|
39
|
+
expand=False,
|
|
40
|
+
title="System",
|
|
41
|
+
title_align="left",
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
console.print() # Add a blank line after the system message
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def print_code(code, language="python"):
|
|
48
|
+
syntax = Syntax(code, language, theme="monokai", line_numbers=True)
|
|
49
|
+
console.print(
|
|
50
|
+
Panel(
|
|
51
|
+
syntax,
|
|
52
|
+
border_style="red",
|
|
53
|
+
box=ROUNDED,
|
|
54
|
+
expand=False,
|
|
55
|
+
title=f"Code ({language})",
|
|
56
|
+
title_align="left",
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def dict_to_equal_string(d: dict) -> str:
|
|
62
|
+
return "\n".join([f'-{key}="{value}"' for key, value in d.items()])
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def print_tool_usage(message):
|
|
66
|
+
print_message = ""
|
|
67
|
+
tool_name = message.tool_calls[0]["name"]
|
|
68
|
+
arguments = ""
|
|
69
|
+
if (
|
|
70
|
+
"args" in message.tool_calls[0]
|
|
71
|
+
and len(message.tool_calls[0]["args"].values()) > 0
|
|
72
|
+
):
|
|
73
|
+
arguments += dict_to_equal_string(message.tool_calls[0]["args"])
|
|
74
|
+
|
|
75
|
+
if tool_name.startswith("transfer_to_"):
|
|
76
|
+
tool_label = " ".join(
|
|
77
|
+
word.capitalize()
|
|
78
|
+
for word in tool_name.split("transfer_to_")[1].replace("_", " ").split()
|
|
79
|
+
)
|
|
80
|
+
print_message = f"\n🧞 [bold blue]Delegated to [/bold blue]{tool_label}"
|
|
81
|
+
else:
|
|
82
|
+
tool_label = tool_name.capitalize().replace("_", " ")
|
|
83
|
+
print_message = f"\n[bold blue]Tool Used:[/bold blue] {tool_label}\n{arguments}"
|
|
84
|
+
console.print(print_message)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def print_tool_response(response):
|
|
88
|
+
console.print(f"\n[bold blue]Response:[/bold blue] {response}")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def clear_screen():
|
|
92
|
+
console.clear()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def print_welcome_message(agent):
|
|
96
|
+
# Set terminal title
|
|
97
|
+
set_terminal_title()
|
|
98
|
+
|
|
99
|
+
# Skip the welcome - we already said hello in the CLI startup
|
|
100
|
+
# Just quietly start the conversation
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def print_divider():
|
|
105
|
+
console.print("─" * console.width, style="dim")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_user_input(agent_label):
|
|
109
|
+
try:
|
|
110
|
+
user_input = console.input(
|
|
111
|
+
"\n[bold cyan]You:[/bold cyan] "
|
|
112
|
+
) # Add a newline before the prompt
|
|
113
|
+
console.print() # Add a blank line after the user's input
|
|
114
|
+
return user_input
|
|
115
|
+
except EOFError:
|
|
116
|
+
console.print(
|
|
117
|
+
f"\n[bold red]{agent_label}:[/bold red] Conversation ended by user."
|
|
118
|
+
)
|
|
119
|
+
return "exit"
|
|
120
|
+
except KeyboardInterrupt:
|
|
121
|
+
console.print(
|
|
122
|
+
f"\n[bold red]{agent_label}:[/bold red] Conversation ended by user."
|
|
123
|
+
)
|
|
124
|
+
return "exit"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def print_image(image_path: str):
|
|
128
|
+
"""Display an image in the terminal."""
|
|
129
|
+
try:
|
|
130
|
+
console.print() # Add some spacing
|
|
131
|
+
|
|
132
|
+
# Display the file path and viewing instructions
|
|
133
|
+
message = (
|
|
134
|
+
f"[yellow]Image saved at: {image_path}[/yellow]\n\n"
|
|
135
|
+
"[dim]To view the image:[/dim]\n"
|
|
136
|
+
f"[cyan]• Local system: Open {image_path} with your image viewer[/cyan]\n"
|
|
137
|
+
"[cyan]• Remote/SSH: Download the file to your local machine to view[/cyan]"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
console.print(
|
|
141
|
+
Panel(
|
|
142
|
+
message,
|
|
143
|
+
border_style="yellow",
|
|
144
|
+
box=ROUNDED,
|
|
145
|
+
expand=False,
|
|
146
|
+
title="Graph Output",
|
|
147
|
+
title_align="left",
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Only try to show the image if we're in a GUI environment
|
|
152
|
+
if os.environ.get("DISPLAY") and platform.system() != "Windows":
|
|
153
|
+
try:
|
|
154
|
+
img = Image.open(image_path)
|
|
155
|
+
img.show()
|
|
156
|
+
except Exception:
|
|
157
|
+
pass # Silently fail if we can't display the image
|
|
158
|
+
elif platform.system() == "Windows":
|
|
159
|
+
try:
|
|
160
|
+
subprocess.run(['start', '', image_path], shell=True) # Windows-specific file opening
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
console.print() # Add some spacing after
|
|
165
|
+
except Exception as e:
|
|
166
|
+
console.print(
|
|
167
|
+
Panel(
|
|
168
|
+
f"[yellow]Unable to process image. File saved at: {image_path}[/yellow]\nError: {str(e)}",
|
|
169
|
+
border_style="yellow",
|
|
170
|
+
box=ROUNDED,
|
|
171
|
+
expand=False,
|
|
172
|
+
title="Graph Output",
|
|
173
|
+
title_align="left",
|
|
174
|
+
)
|
|
175
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .agent import agent
|
|
4
|
+
from .chat import chat
|
|
5
|
+
from .config import config
|
|
6
|
+
from .init import init
|
|
7
|
+
from .module import module
|
|
8
|
+
from .new import new
|
|
9
|
+
from .secret import secrets
|
|
10
|
+
|
|
11
|
+
# from dotenv import load_dotenv
|
|
12
|
+
|
|
13
|
+
# load_dotenv()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.group("abi")
|
|
17
|
+
def main():
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# @main.command("chat")
|
|
22
|
+
# @click.option("--module-name", type=str, required=True, default="chatgpt")
|
|
23
|
+
# @click.option("--agent-name", type=str, required=True, default="ChatGPTAgent")
|
|
24
|
+
# def chat(module_name: str, agent_name: str):
|
|
25
|
+
# from naas_abi_core.engine.Engine import Engine
|
|
26
|
+
|
|
27
|
+
# engine = Engine()
|
|
28
|
+
# engine.load(module_names=[module_name])
|
|
29
|
+
|
|
30
|
+
# from naas_abi_core.apps.terminal_agent.main import run_agent
|
|
31
|
+
|
|
32
|
+
# logger.debug(f"Module agents: {engine.modules[module_name].agents}")
|
|
33
|
+
|
|
34
|
+
# for agent_class in engine.modules[module_name].agents:
|
|
35
|
+
# logger.debug(f"Agent class: {agent_class.__name__}")
|
|
36
|
+
# if agent_class.__name__ == agent_name:
|
|
37
|
+
# run_agent(agent_class.New())
|
|
38
|
+
# break
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Add the secrets group to the main abi group
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
main.add_command(secrets)
|
|
45
|
+
main.add_command(config)
|
|
46
|
+
main.add_command(module)
|
|
47
|
+
main.add_command(agent)
|
|
48
|
+
main.add_command(chat)
|
|
49
|
+
main.add_command(new)
|
|
50
|
+
main.add_command(init)
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
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)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from naas_abi_core import logger
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command("chat")
|
|
7
|
+
@click.argument("module-name", type=str, required=True, default="naas_abi")
|
|
8
|
+
@click.argument("agent-name", type=str, required=True, default="AbiAgent")
|
|
9
|
+
def chat(module_name: str, agent_name: str):
|
|
10
|
+
from naas_abi_core.engine.Engine import Engine
|
|
11
|
+
|
|
12
|
+
engine = Engine()
|
|
13
|
+
engine.load(module_names=[module_name])
|
|
14
|
+
|
|
15
|
+
from naas_abi_core.apps.terminal_agent.main import run_agent
|
|
16
|
+
|
|
17
|
+
if module_name not in engine.modules:
|
|
18
|
+
raise ValueError(f"Module {module_name} not found")
|
|
19
|
+
|
|
20
|
+
logger.debug(f"Module agents: {engine.modules[module_name].agents}")
|
|
21
|
+
|
|
22
|
+
for agent_class in engine.modules[module_name].agents:
|
|
23
|
+
logger.debug(f"Agent class: {agent_class.__name__}")
|
|
24
|
+
if agent_class.__name__ == agent_name:
|
|
25
|
+
run_agent(agent_class.New())
|
|
26
|
+
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,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)
|
naas_abi_core/cli/new.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@click.group("new")
|
|
5
|
+
def new():
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@new.command("module")
|
|
10
|
+
@click.argument("module-name")
|
|
11
|
+
@click.argument("module-path")
|
|
12
|
+
def new_module(module_name: str, module_path: str):
|
|
13
|
+
print(f"Creating a new module: {module_name} at {module_path}")
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.group("secrets")
|
|
7
|
+
def secrets():
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@secrets.group("naas")
|
|
12
|
+
def naas():
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@naas.command("push-env-as-base64")
|
|
17
|
+
@click.option(
|
|
18
|
+
"--naas-api-key", type=str, required=True, default=os.getenv("NAAS_API_KEY")
|
|
19
|
+
)
|
|
20
|
+
@click.option("--naas-api-url", type=str, required=True, default="https://api.naas.ai")
|
|
21
|
+
@click.option("--naas-secret-name", type=str, required=True, default="abi_secrets")
|
|
22
|
+
@click.option("--env-file", type=str, required=True, default=".env.prod")
|
|
23
|
+
def push_env_to_naas(naas_api_key, naas_api_url, naas_secret_name, env_file):
|
|
24
|
+
import base64
|
|
25
|
+
|
|
26
|
+
from naas_abi_core.services.secret.adaptors.secondary.NaasSecret import NaasSecret
|
|
27
|
+
|
|
28
|
+
naas_secret = NaasSecret(naas_api_key, naas_api_url)
|
|
29
|
+
|
|
30
|
+
envfile_content = ""
|
|
31
|
+
|
|
32
|
+
with open(env_file, "r") as envfile:
|
|
33
|
+
envfile_content = envfile.read()
|
|
34
|
+
|
|
35
|
+
print(envfile_content)
|
|
36
|
+
|
|
37
|
+
base64_content = base64.b64encode(envfile_content.encode("utf-8")).decode("utf-8")
|
|
38
|
+
naas_secret.set(naas_secret_name, base64_content)
|
|
39
|
+
|
|
40
|
+
print(f"Pushed {env_file} to Naas as base64 secret {naas_secret_name}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@naas.command("list")
|
|
44
|
+
@click.option(
|
|
45
|
+
"--naas-api-key", type=str, required=True, default=os.getenv("NAAS_API_KEY")
|
|
46
|
+
)
|
|
47
|
+
@click.option("--naas-api-url", type=str, required=True, default="https://api.naas.ai")
|
|
48
|
+
def list_secrets(naas_api_key, naas_api_url):
|
|
49
|
+
from naas_abi_core.services.secret.adaptors.secondary.NaasSecret import NaasSecret
|
|
50
|
+
|
|
51
|
+
naas_secret = NaasSecret(naas_api_key, naas_api_url)
|
|
52
|
+
|
|
53
|
+
naas_secret.list()
|
|
54
|
+
|
|
55
|
+
for key, value in naas_secret.list().items():
|
|
56
|
+
print(f"{key}: {value}")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@naas.command("get-base64-env")
|
|
60
|
+
@click.option(
|
|
61
|
+
"--naas-api-key", type=str, required=True, default=os.getenv("NAAS_API_KEY")
|
|
62
|
+
)
|
|
63
|
+
@click.option("--naas-api-url", type=str, required=True, default="https://api.naas.ai")
|
|
64
|
+
@click.option("--naas-secret-name", type=str, required=True, default="abi_secrets")
|
|
65
|
+
def get_secret(naas_api_key, naas_api_url, naas_secret_name):
|
|
66
|
+
from naas_abi_core.services.secret.adaptors.secondary.Base64Secret import (
|
|
67
|
+
Base64Secret,
|
|
68
|
+
)
|
|
69
|
+
from naas_abi_core.services.secret.adaptors.secondary.NaasSecret import NaasSecret
|
|
70
|
+
|
|
71
|
+
naas_secret = NaasSecret(naas_api_key, naas_api_url)
|
|
72
|
+
base64_secret = Base64Secret(naas_secret, naas_secret_name)
|
|
73
|
+
|
|
74
|
+
for key, value in base64_secret.list().items():
|
|
75
|
+
# If value is multiline
|
|
76
|
+
if "\n" in value:
|
|
77
|
+
print(f'{key}="{value}"')
|
|
78
|
+
else:
|
|
79
|
+
print(f"{key}={value}")
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from typing import Dict, List
|
|
2
|
+
|
|
3
|
+
from naas_abi_core import logger
|
|
4
|
+
from naas_abi_core.engine.engine_configuration.EngineConfiguration import (
|
|
5
|
+
EngineConfiguration,
|
|
6
|
+
)
|
|
7
|
+
from naas_abi_core.engine.engine_loaders.EngineModuleLoader import EngineModuleLoader
|
|
8
|
+
from naas_abi_core.engine.engine_loaders.EngineOntologyLoader import (
|
|
9
|
+
EngineOntologyLoader,
|
|
10
|
+
)
|
|
11
|
+
from naas_abi_core.engine.engine_loaders.EngineServiceLoader import EngineServiceLoader
|
|
12
|
+
from naas_abi_core.engine.IEngine import IEngine
|
|
13
|
+
from naas_abi_core.module.Module import BaseModule
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Engine(IEngine):
|
|
17
|
+
__configuration: EngineConfiguration
|
|
18
|
+
__engine_module_loader: EngineModuleLoader
|
|
19
|
+
__engine_service_loader: EngineServiceLoader
|
|
20
|
+
|
|
21
|
+
__modules: Dict[
|
|
22
|
+
str, BaseModule
|
|
23
|
+
] # Must not set a default value to prevent modules to try to access modules inside constructors.
|
|
24
|
+
|
|
25
|
+
__services: IEngine.Services
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def configuration(self) -> EngineConfiguration:
|
|
29
|
+
return self.__configuration
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def modules(self) -> Dict[str, BaseModule]:
|
|
33
|
+
try:
|
|
34
|
+
return self.__modules
|
|
35
|
+
except AttributeError:
|
|
36
|
+
error_message = "You are trying to access the engine's modules before the engine is loaded. Modules are accessible when on_initialized is called. If you are in your module constructor or in the on_load method, you should not try to access self.engine yet."
|
|
37
|
+
logger.error(error_message)
|
|
38
|
+
raise RuntimeError(error_message)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def services(self) -> IEngine.Services:
|
|
42
|
+
return self.__services
|
|
43
|
+
|
|
44
|
+
def __init__(self, configuration: str | None = None):
|
|
45
|
+
# Load configuration
|
|
46
|
+
self.__configuration = EngineConfiguration.load_configuration(configuration)
|
|
47
|
+
self.__engine_module_loader = EngineModuleLoader(self.__configuration)
|
|
48
|
+
self.__engine_service_loader = EngineServiceLoader(self.__configuration)
|
|
49
|
+
|
|
50
|
+
def load(self, module_names: List[str] = []):
|
|
51
|
+
module_dependencies = self.__engine_module_loader.get_modules_dependencies(
|
|
52
|
+
module_names
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
logger.debug("Loading engine services")
|
|
56
|
+
self.__services = self.__engine_service_loader.load_services(
|
|
57
|
+
module_dependencies
|
|
58
|
+
)
|
|
59
|
+
logger.debug("Engine services loaded")
|
|
60
|
+
|
|
61
|
+
logger.debug("Loading engine modules")
|
|
62
|
+
self.__modules = self.__engine_module_loader.load_modules(self, module_names)
|
|
63
|
+
logger.debug("Engine modules loaded")
|
|
64
|
+
|
|
65
|
+
if self.__services.triple_store_available():
|
|
66
|
+
logger.debug("Loading engine ontologies")
|
|
67
|
+
EngineOntologyLoader.load_ontologies(
|
|
68
|
+
self.__services.triple_store,
|
|
69
|
+
self.__engine_module_loader.ordered_modules,
|
|
70
|
+
)
|
|
71
|
+
logger.debug("Engine ontologies loaded")
|
|
72
|
+
else:
|
|
73
|
+
logger.debug("No triple store available, skipping ontology loading")
|
|
74
|
+
|
|
75
|
+
logger.debug("Initializing engine")
|
|
76
|
+
self.on_initialized()
|
|
77
|
+
logger.debug("Engine initialized")
|
|
78
|
+
|
|
79
|
+
def on_initialized(self):
|
|
80
|
+
for module in self.__modules.values():
|
|
81
|
+
module.on_initialized()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
engine = Engine()
|
|
86
|
+
engine.load(module_names=["chatgpt"])
|
|
87
|
+
print("Engine loaded successfully")
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Dict
|
|
4
|
+
|
|
5
|
+
from naas_abi_core.engine.IEngine import IEngine
|
|
6
|
+
from naas_abi_core.services.object_storage.ObjectStorageService import (
|
|
7
|
+
ObjectStorageService,
|
|
8
|
+
)
|
|
9
|
+
from naas_abi_core.services.secret.Secret import Secret
|
|
10
|
+
from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
|
|
11
|
+
from naas_abi_core.services.vector_store.VectorStoreService import VectorStoreService
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from naas_abi_core.module.Module import BaseModule, ModuleDependencies
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ServicesProxy:
|
|
18
|
+
__engine: IEngine
|
|
19
|
+
__module_name: str
|
|
20
|
+
__module_dependencies: ModuleDependencies
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self, engine: IEngine, module_name: str, module_dependencies: ModuleDependencies
|
|
24
|
+
):
|
|
25
|
+
self.__engine = engine
|
|
26
|
+
self.__module_name = module_name
|
|
27
|
+
self.__module_dependencies = module_dependencies
|
|
28
|
+
|
|
29
|
+
# def __accessible_services(self) -> List[Any]:
|
|
30
|
+
# engine_services = {
|
|
31
|
+
# type(service): service for service in self.__engine.services.all
|
|
32
|
+
# }
|
|
33
|
+
|
|
34
|
+
# for service_type in self.__module_dependencies.services:
|
|
35
|
+
# assert service_type in engine_services, (
|
|
36
|
+
# f"Service {service_type} not found in engine services"
|
|
37
|
+
# )
|
|
38
|
+
|
|
39
|
+
# return [
|
|
40
|
+
# service
|
|
41
|
+
# for service in engine_services.values()
|
|
42
|
+
# if type(service) in self.__module_dependencies.services
|
|
43
|
+
# ]
|
|
44
|
+
|
|
45
|
+
def __ensure_access(self, service_type: type) -> None:
|
|
46
|
+
if service_type not in self.__module_dependencies.services:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"Module {self.__module_name} does not have access to {service_type}"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def object_storage(self) -> ObjectStorageService:
|
|
53
|
+
self.__ensure_access(ObjectStorageService)
|
|
54
|
+
|
|
55
|
+
return self.__engine.services.object_storage
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def triple_store(self) -> TripleStoreService:
|
|
59
|
+
self.__ensure_access(TripleStoreService)
|
|
60
|
+
|
|
61
|
+
return self.__engine.services.triple_store
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def vector_store(self) -> VectorStoreService:
|
|
65
|
+
self.__ensure_access(VectorStoreService)
|
|
66
|
+
|
|
67
|
+
return self.__engine.services.vector_store
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def secret(self) -> Secret:
|
|
71
|
+
self.__ensure_access(Secret)
|
|
72
|
+
|
|
73
|
+
return self.__engine.services.secret
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class EngineProxy:
|
|
77
|
+
__engine: IEngine
|
|
78
|
+
__module_name: str
|
|
79
|
+
__module_dependencies: ModuleDependencies
|
|
80
|
+
|
|
81
|
+
__services_proxy: ServicesProxy
|
|
82
|
+
|
|
83
|
+
def __init__(
|
|
84
|
+
self,
|
|
85
|
+
engine: IEngine,
|
|
86
|
+
module_name: str,
|
|
87
|
+
module_dependencies: ModuleDependencies,
|
|
88
|
+
):
|
|
89
|
+
self.__engine = engine
|
|
90
|
+
self.__module_name = module_name
|
|
91
|
+
self.__module_dependencies = module_dependencies
|
|
92
|
+
self.__services_proxy = ServicesProxy(engine, module_name, module_dependencies)
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def modules(self) -> Dict[str, BaseModule]:
|
|
96
|
+
_modules = {}
|
|
97
|
+
|
|
98
|
+
for module in self.__module_dependencies.modules:
|
|
99
|
+
is_soft = module.endswith("#soft")
|
|
100
|
+
module = module.replace("#soft", "")
|
|
101
|
+
if module not in self.__engine.modules and is_soft:
|
|
102
|
+
continue
|
|
103
|
+
_modules[module] = self.__engine.modules[module]
|
|
104
|
+
|
|
105
|
+
return _modules
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def services(self) -> ServicesProxy:
|
|
109
|
+
return self.__services_proxy
|