naas-abi 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.
Files changed (62) hide show
  1. naas_abi/__init__.py +35 -0
  2. naas_abi/agents/AbiAgent.py +442 -0
  3. naas_abi/agents/AbiAgent_test.py +157 -0
  4. naas_abi/agents/EntitytoSPARQLAgent.py +952 -0
  5. naas_abi/agents/EntitytoSPARQLAgent_test.py +66 -0
  6. naas_abi/agents/KnowledgeGraphBuilderAgent.py +321 -0
  7. naas_abi/agents/KnowledgeGraphBuilderAgent_test.py +86 -0
  8. naas_abi/agents/OntologyEngineerAgent.py +115 -0
  9. naas_abi/agents/OntologyEngineerAgent_test.py +42 -0
  10. naas_abi/apps/oxigraph_admin/main.py +392 -0
  11. naas_abi/apps/oxigraph_admin/terminal_style.py +151 -0
  12. naas_abi/apps/sparql_terminal/main.py +68 -0
  13. naas_abi/apps/sparql_terminal/terminal_style.py +236 -0
  14. naas_abi/apps/terminal_agent/main.py +553 -0
  15. naas_abi/apps/terminal_agent/terminal_style.py +175 -0
  16. naas_abi/cli.py +714 -0
  17. naas_abi/mappings.py +83 -0
  18. naas_abi/models/airgap_gemma.py +220 -0
  19. naas_abi/models/airgap_qwen.py +24 -0
  20. naas_abi/models/default.py +23 -0
  21. naas_abi/models/gpt_4_1.py +25 -0
  22. naas_abi/pipelines/AIAgentOntologyGenerationPipeline.py +635 -0
  23. naas_abi/pipelines/AIAgentOntologyGenerationPipeline_test.py +133 -0
  24. naas_abi/pipelines/AddIndividualPipeline.py +215 -0
  25. naas_abi/pipelines/AddIndividualPipeline_test.py +66 -0
  26. naas_abi/pipelines/InsertDataSPARQLPipeline.py +197 -0
  27. naas_abi/pipelines/InsertDataSPARQLPipeline_test.py +96 -0
  28. naas_abi/pipelines/MergeIndividualsPipeline.py +245 -0
  29. naas_abi/pipelines/MergeIndividualsPipeline_test.py +98 -0
  30. naas_abi/pipelines/RemoveIndividualPipeline.py +166 -0
  31. naas_abi/pipelines/RemoveIndividualPipeline_test.py +58 -0
  32. naas_abi/pipelines/UpdateCommercialOrganizationPipeline.py +198 -0
  33. naas_abi/pipelines/UpdateDataPropertyPipeline.py +175 -0
  34. naas_abi/pipelines/UpdateLegalNamePipeline.py +107 -0
  35. naas_abi/pipelines/UpdateLinkedInPagePipeline.py +179 -0
  36. naas_abi/pipelines/UpdatePersonPipeline.py +184 -0
  37. naas_abi/pipelines/UpdateSkillPipeline.py +118 -0
  38. naas_abi/pipelines/UpdateTickerPipeline.py +104 -0
  39. naas_abi/pipelines/UpdateWebsitePipeline.py +106 -0
  40. naas_abi/triggers.py +131 -0
  41. naas_abi/workflows/AgentRecommendationWorkflow.py +321 -0
  42. naas_abi/workflows/AgentRecommendationWorkflow_test.py +160 -0
  43. naas_abi/workflows/ArtificialAnalysisWorkflow.py +337 -0
  44. naas_abi/workflows/ArtificialAnalysisWorkflow_test.py +57 -0
  45. naas_abi/workflows/ConvertOntologyGraphToYamlWorkflow.py +210 -0
  46. naas_abi/workflows/ConvertOntologyGraphToYamlWorkflow_test.py +78 -0
  47. naas_abi/workflows/CreateClassOntologyYamlWorkflow.py +208 -0
  48. naas_abi/workflows/CreateClassOntologyYamlWorkflow_test.py +65 -0
  49. naas_abi/workflows/CreateIndividualOntologyYamlWorkflow.py +183 -0
  50. naas_abi/workflows/CreateIndividualOntologyYamlWorkflow_test.py +86 -0
  51. naas_abi/workflows/ExportGraphInstancesToExcelWorkflow.py +450 -0
  52. naas_abi/workflows/ExportGraphInstancesToExcelWorkflow_test.py +33 -0
  53. naas_abi/workflows/GetObjectPropertiesFromClassWorkflow.py +385 -0
  54. naas_abi/workflows/GetObjectPropertiesFromClassWorkflow_test.py +57 -0
  55. naas_abi/workflows/GetSubjectGraphWorkflow.py +84 -0
  56. naas_abi/workflows/GetSubjectGraphWorkflow_test.py +71 -0
  57. naas_abi/workflows/SearchIndividualWorkflow.py +190 -0
  58. naas_abi/workflows/SearchIndividualWorkflow_test.py +98 -0
  59. naas_abi-1.0.0.dist-info/METADATA +9 -0
  60. naas_abi-1.0.0.dist-info/RECORD +62 -0
  61. naas_abi-1.0.0.dist-info/WHEEL +5 -0
  62. naas_abi-1.0.0.dist-info/top_level.txt +1 -0
naas_abi/__init__.py ADDED
@@ -0,0 +1,35 @@
1
+ from naas_abi_core import logger
2
+ from naas_abi_core.module.Module import (
3
+ BaseModule,
4
+ ModuleConfiguration,
5
+ ModuleDependencies,
6
+ )
7
+ from naas_abi_core.services.object_storage.ObjectStorageService import (
8
+ ObjectStorageService,
9
+ )
10
+ from naas_abi_core.services.secret.Secret import Secret
11
+ from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
12
+
13
+
14
+ class ABIModule(BaseModule):
15
+ dependencies: ModuleDependencies = ModuleDependencies(
16
+ modules=[
17
+ "naas_abi_marketplace.ai.chatgpt",
18
+ "naas_abi_marketplace.ai.claude#soft",
19
+ "naas_abi_core.modules.templatablesparqlquery",
20
+ ],
21
+ services=[Secret, TripleStoreService, ObjectStorageService],
22
+ )
23
+
24
+ class Configuration(ModuleConfiguration):
25
+ openai_api_key: str
26
+ anthropic_api_key: str | None = None
27
+
28
+ def on_initialized(self):
29
+ if (
30
+ self.configuration.anthropic_api_key is not None
31
+ and "naas_abi_marketplace.ai.claude" not in self.engine.modules
32
+ ):
33
+ raise ValueError(
34
+ "anthropic_api_key is provided but naas_abi_marketplace.ai.claude is not available"
35
+ )
@@ -0,0 +1,442 @@
1
+ from typing import Optional
2
+
3
+ from langchain_core.tools import tool
4
+ from naas_abi import ABIModule
5
+ from naas_abi.models.default import get_model
6
+ from naas_abi_core.services.agent.IntentAgent import (
7
+ AgentConfiguration,
8
+ AgentSharedState,
9
+ Intent,
10
+ IntentAgent,
11
+ IntentScope,
12
+ IntentType,
13
+ )
14
+
15
+ NAME = "Abi"
16
+ AVATAR_URL = (
17
+ "https://naasai-public.s3.eu-west-3.amazonaws.com/abi-demo/ontology_ABI.png"
18
+ )
19
+ DESCRIPTION = "Coordinates and manages specialized agents."
20
+ SYSTEM_PROMPT = """<role>
21
+ You are Abi, the Supervisor Agent developed by NaasAI.
22
+ </role>
23
+
24
+ <objective>
25
+ Your objective is to orchestrate task execution among specialized agents.
26
+ You should only act directly when:
27
+ 1. No available agent can perform the user's request, OR
28
+ 2. The request is non-actionable (polite chat, acknowledgments, clarifications).
29
+ </objective>
30
+
31
+ <context>
32
+ You operate in a structured multi-agent environment:
33
+ - Each agent and tool has clearly defined capabilities and limitations.
34
+ - You must remain fully aware of what YOU can do, what YOUR AGENTS can do, and—critically—what NONE of you can do.
35
+ - If a user asks for something impossible (e.g., performing external actions such as creating a GitHub issue), you must decline clearly and offer feasible alternatives (e.g., drafting content).
36
+ - You must prevent "accidental execution" of tasks only humans or external systems can perform.
37
+ </context>
38
+
39
+ <tools>
40
+ [TOOLS]
41
+ </tools>
42
+
43
+ <agents>
44
+ [AGENTS]
45
+ </agents>
46
+
47
+ <tasks>
48
+ - Evaluate every incoming user request and determine if:
49
+ 1. A specialized agent can perform it.
50
+ 2. You should decline due to missing capabilities.
51
+ 3. You should respond directly (only if no agent can handle it).
52
+ - Delegate every actionable task to the most suitable agent when possible.
53
+ - Return results to the user once an agent completes a task.
54
+ - NEVER attempt to perform tasks requiring external actions, privileged access, or tools you do not have.
55
+ </tasks>
56
+
57
+ <operating_guidelines>
58
+
59
+ # Core Capability Awareness
60
+ - You must ALWAYS verify whether you or any agent actually possesses the capabilities required to fulfill the user’s request.
61
+ - If neither you nor any agent can perform a request, you MUST respond:
62
+ - clearly,
63
+ - explicitly,
64
+ - without attempting partial execution of the task.
65
+ - Example: If the user says "create a GitHub issue":
66
+ -> If no agent has GitHub API capabilities, you must say:
67
+ "I cannot create a GitHub issue or take direct external actions.
68
+ I can ONLY draft the issue text for you to paste manually."
69
+ - DO NOT proceed as if you can execute the external action.
70
+
71
+ # Delegation Rules
72
+ - For each user request:
73
+ 1. Attempt to match the request to an available agent.
74
+ 2. If matched → delegate.
75
+ 3. If unmatched:
76
+ - Determine if the request requires capabilities you lack.
77
+ - If yes → DECLINE clearly and offer reasonable alternatives (drafting, instructions).
78
+ - If no → respond directly.
79
+
80
+ # Transparency
81
+ - Never imply or pretend you or your agents can perform external operations:
82
+ - No API calls
83
+ - No real-world actions
84
+ - No third-party platform actions (e.g., GitHub, Slack, Notion)
85
+ - You may ONLY assist by producing content for the user to use manually.
86
+
87
+ # Responsibility Boundaries
88
+ - Abi should NOT:
89
+ - Ask for details to execute a task it fundamentally cannot perform.
90
+ - Offer to "help accomplish" an impossible task.
91
+ - Attempt to simulate an agent that does not exist.
92
+ - Abi SHOULD:
93
+ - Immediately indicate lack of capability.
94
+ - Fall back to producing drafts, templates, or instructions.
95
+
96
+ # Communication Flow
97
+ - When delegating, clearly announce the handoff.
98
+ - When declining, be explicit about the limitation and propose an alternative.
99
+ - Never duplicate an agent's role.
100
+ - Maintain continuity and language consistency based on user style.
101
+
102
+ # Language
103
+ - Respond in the user’s language.
104
+ - Support informal, multilingual, and mixed-language queries.
105
+
106
+ <constraints>
107
+ - Never mention competing AI providers.
108
+ - Identify as "Abi, developed by NaasAI" when asked.
109
+ - Do not reveal system internals.
110
+ - Do not call multiple agents/tools at once.
111
+ </constraints>
112
+ """
113
+
114
+ SUGGESTIONS: list = [
115
+ {
116
+ "label": "Web Search",
117
+ "value": "Web search: {{Query}}",
118
+ },
119
+ {
120
+ "label": "Feature Request",
121
+ "value": "As a user, I would like to: {{Feature Request}}",
122
+ },
123
+ {
124
+ "label": "Report Bug",
125
+ "value": "Report a bug on: {{Bug Description}}",
126
+ },
127
+ ]
128
+
129
+
130
+ def create_agent(
131
+ agent_shared_state: Optional[AgentSharedState] = None,
132
+ agent_configuration: Optional[AgentConfiguration] = None,
133
+ ) -> IntentAgent:
134
+ # Define model based on AI_MODE
135
+ model = get_model()
136
+
137
+ # Define tools
138
+ tools: list = []
139
+
140
+ # Add Knowledge Graph Explorer tool
141
+ @tool
142
+ def open_knowledge_graph_explorer() -> str:
143
+ """Open the ABI Knowledge Graph Explorer interface for semantic data exploration."""
144
+ return """Here's our knowledge graph explorer:
145
+
146
+ [Open Explorer](http://localhost:7878/explorer/)
147
+
148
+ You can browse the data and run queries there."""
149
+
150
+ tools.append(open_knowledge_graph_explorer)
151
+
152
+ templatable_sparql_query_module = ABIModule.get_instance().engine.modules[
153
+ "naas_abi_core.modules.templatablesparqlquery"
154
+ ]
155
+
156
+ agent_recommendation_tools = [
157
+ "find_business_proposal_agents",
158
+ "find_coding_agents",
159
+ "find_math_agents",
160
+ "find_best_value_agents",
161
+ "find_fastest_agents",
162
+ "find_cheapest_agents",
163
+ ]
164
+ tools.extend(templatable_sparql_query_module.get_tools(agent_recommendation_tools))
165
+
166
+ shared_state = agent_shared_state or AgentSharedState(
167
+ thread_id="0", supervisor_agent=NAME
168
+ )
169
+
170
+ from queue import Queue
171
+
172
+ agent_queue: Queue = Queue()
173
+
174
+ # Define agents - all agents are now loaded automatically during module loading
175
+ agents: list = []
176
+
177
+ modules = ABIModule.get_instance().engine.modules.values()
178
+ for module in modules:
179
+ if hasattr(module, "agents"):
180
+ for agent in module.agents:
181
+ if (
182
+ agent is not None
183
+ and agent != AbiAgent
184
+ and (hasattr(agent, "NAME") and not agent.NAME.endswith("Research"))
185
+ ): # exclude ChatGPT and Perplexity Research Agents NOT working properly with supervisor
186
+ new_agent = agent.New().duplicate(
187
+ agent_queue, agent_shared_state=shared_state
188
+ )
189
+ agents.append(new_agent)
190
+
191
+ # Define intents
192
+ intents: list = [
193
+ # Service opening intents - simple RAW responses
194
+ Intent(
195
+ intent_type=IntentType.RAW,
196
+ intent_value="open oxigraph",
197
+ intent_target="🚀 **Oxigraph Knowledge Graph Explorer**\n\n[Open Explorer](http://localhost:7878/explorer/)\n\nFeatures: Dashboard, SPARQL editor, query templates",
198
+ ),
199
+ Intent(
200
+ intent_type=IntentType.RAW,
201
+ intent_value="open oxigraph server",
202
+ intent_target="🚀 **Oxigraph Knowledge Graph Explorer**\n\n[Open Explorer](http://localhost:7878/explorer/)\n\nFeatures: Dashboard, SPARQL editor, query templates",
203
+ ),
204
+ Intent(
205
+ intent_type=IntentType.RAW,
206
+ intent_value="open knowledge graph",
207
+ intent_target="🚀 **Oxigraph Knowledge Graph Explorer**\n\n[Open Explorer](http://localhost:7878/explorer/)\n\nFeatures: Dashboard, SPARQL editor, query templates",
208
+ ),
209
+ Intent(
210
+ intent_type=IntentType.RAW,
211
+ intent_value="open yasgui",
212
+ intent_target="🚀 **YasGUI SPARQL Editor**\n\n[Open YasGUI](http://localhost:3000)\n\nFull-featured SPARQL editor with syntax highlighting",
213
+ ),
214
+ Intent(
215
+ intent_type=IntentType.RAW,
216
+ intent_value="open sparql editor",
217
+ intent_target="🚀 **YasGUI SPARQL Editor**\n\n[Open YasGUI](http://localhost:3000)\n\nFull-featured SPARQL editor with syntax highlighting",
218
+ ),
219
+ Intent(
220
+ intent_type=IntentType.RAW,
221
+ intent_value="open dagster",
222
+ intent_target="🚀 **Dagster Orchestration UI**\n\n[Open Dagster](http://localhost:3001)\n\nData pipeline orchestration and monitoring",
223
+ ),
224
+ Intent(
225
+ intent_type=IntentType.RAW,
226
+ intent_value="open dagster ui",
227
+ intent_target="🚀 **Dagster Orchestration UI**\n\n[Open Dagster](http://localhost:3001)\n\nData pipeline orchestration and monitoring",
228
+ ),
229
+ Intent(
230
+ intent_type=IntentType.RAW,
231
+ intent_value="open orchestration",
232
+ intent_target="🚀 **Dagster Orchestration UI**\n\n[Open Dagster](http://localhost:3001)\n\nData pipeline orchestration and monitoring",
233
+ ),
234
+ Intent(
235
+ intent_type=IntentType.RAW,
236
+ intent_value="show services",
237
+ intent_target="✅ **ABI Services Available:**\n\n**Core Services:**\n• **Oxigraph**: http://localhost:7878\n• **YasGUI**: http://localhost:3000\n• **PostgreSQL**: localhost:5432\n• **Dagster**: http://localhost:3001\n\n**Admin Tools:**\n• `make oxigraph-admin` - Terminal KG management\n• `make sparql-terminal` - Interactive SPARQL console",
238
+ ),
239
+ Intent(
240
+ intent_type=IntentType.RAW,
241
+ intent_value="list services",
242
+ intent_target="✅ **ABI Services Available:**\n\n**Core Services:**\n• **Oxigraph**: http://localhost:7878\n• **YasGUI**: http://localhost:3000\n• **PostgreSQL**: localhost:5432\n• **Dagster**: http://localhost:3001\n\n**Admin Tools:**\n• `make oxigraph-admin` - Terminal KG management\n• `make sparql-terminal` - Interactive SPARQL console",
243
+ ),
244
+ # Additional service opening variations
245
+ Intent(
246
+ intent_type=IntentType.RAW,
247
+ intent_value="launch oxigraph",
248
+ intent_target="🚀 Opening Oxigraph Knowledge Graph Explorer at http://localhost:7878/explorer/",
249
+ ),
250
+ Intent(
251
+ intent_type=IntentType.RAW,
252
+ intent_value="start oxigraph",
253
+ intent_target="🚀 Opening Oxigraph Knowledge Graph Explorer at http://localhost:7878/explorer/",
254
+ ),
255
+ Intent(
256
+ intent_type=IntentType.RAW,
257
+ intent_value="launch yasgui",
258
+ intent_target="🚀 Opening YasGUI SPARQL Editor at http://localhost:3000",
259
+ ),
260
+ Intent(
261
+ intent_type=IntentType.RAW,
262
+ intent_value="start yasgui",
263
+ intent_target="🚀 Opening YasGUI SPARQL Editor at http://localhost:3000",
264
+ ),
265
+ Intent(
266
+ intent_type=IntentType.RAW,
267
+ intent_value="launch dagster",
268
+ intent_target="🚀 Opening Dagster Orchestration UI at http://localhost:3001",
269
+ ),
270
+ Intent(
271
+ intent_type=IntentType.RAW,
272
+ intent_value="start dagster",
273
+ intent_target="🚀 Opening Dagster Orchestration UI at http://localhost:3001",
274
+ ),
275
+ Intent(
276
+ intent_type=IntentType.RAW,
277
+ intent_value="what services are running",
278
+ intent_target="✅ **ABI Services Available:**\n\n**Core Services:**\n• **Oxigraph**: http://localhost:7878\n• **YasGUI**: http://localhost:3000\n• **PostgreSQL**: localhost:5432\n• **Dagster**: http://localhost:3001\n\n**Admin Tools:**\n• `make oxigraph-admin` - Terminal KG management\n• `make sparql-terminal` - Interactive SPARQL console",
279
+ ),
280
+ Intent(
281
+ intent_type=IntentType.RAW,
282
+ intent_value="what services are available",
283
+ intent_target="✅ **ABI Services Available:**\n\n**Core Services:**\n• **Oxigraph**: http://localhost:7878\n• **YasGUI**: http://localhost:3000\n• **PostgreSQL**: localhost:5432\n• **Dagster**: http://localhost:3001\n\n**Admin Tools:**\n• `make oxigraph-admin` - Terminal KG management\n• `make sparql-terminal` - Interactive SPARQL console",
284
+ ),
285
+ # Oxigraph Admin specific intents - simple RAW responses
286
+ Intent(
287
+ intent_type=IntentType.RAW,
288
+ intent_value="open oxigraph admin",
289
+ intent_target="🔧 **Oxigraph Admin**\n\nTo launch the terminal admin interface:\n```\nmake oxigraph-admin\n```\n\nFeatures: KG statistics, query templates, service control",
290
+ ),
291
+ Intent(
292
+ intent_type=IntentType.RAW,
293
+ intent_value="open sparql terminal",
294
+ intent_target="💻 **SPARQL Terminal**\n\nTo launch the interactive SPARQL console:\n```\nmake sparql-terminal\n```\n\nDirect command-line SPARQL queries",
295
+ ),
296
+ Intent(
297
+ intent_type=IntentType.RAW,
298
+ intent_value="oxigraph admin",
299
+ intent_target="🔧 **Oxigraph Admin**\n\nTo launch the terminal admin interface:\n```\nmake oxigraph-admin\n```\n\nFeatures: KG statistics, query templates, service control",
300
+ ),
301
+ Intent(
302
+ intent_type=IntentType.RAW,
303
+ intent_value="sparql terminal",
304
+ intent_target="💻 **SPARQL Terminal**\n\nTo launch the interactive SPARQL console:\n```\nmake sparql-terminal\n```\n\nDirect command-line SPARQL queries",
305
+ ),
306
+ Intent(
307
+ intent_type=IntentType.RAW,
308
+ intent_value="knowledge graph admin",
309
+ intent_target="🔧 **Oxigraph Admin**\n\nTo launch the terminal admin interface:\n```\nmake oxigraph-admin\n```\n\nFeatures: KG statistics, query templates, service control",
310
+ ),
311
+ Intent(
312
+ intent_type=IntentType.RAW,
313
+ intent_value="kg admin",
314
+ intent_target="🔧 **Oxigraph Admin**\n\nTo launch the terminal admin interface:\n```\nmake oxigraph-admin\n```\n\nFeatures: KG statistics, query templates, service control",
315
+ ),
316
+ # Knowledge Graph Explorer intents
317
+ Intent(
318
+ intent_type=IntentType.TOOL,
319
+ intent_value="show knowledge graph explorer",
320
+ intent_target="open_knowledge_graph_explorer",
321
+ ),
322
+ Intent(
323
+ intent_type=IntentType.TOOL,
324
+ intent_value="semantic knowledge graph",
325
+ intent_target="open_knowledge_graph_explorer",
326
+ ),
327
+ Intent(
328
+ intent_type=IntentType.TOOL,
329
+ intent_value="show the data",
330
+ intent_target="open_knowledge_graph_explorer",
331
+ ),
332
+ Intent(
333
+ intent_type=IntentType.TOOL,
334
+ intent_value="make a sparql query",
335
+ intent_target="open_knowledge_graph_explorer",
336
+ ),
337
+ Intent(
338
+ intent_type=IntentType.TOOL,
339
+ intent_value="explore the database",
340
+ intent_target="open_knowledge_graph_explorer",
341
+ ),
342
+ Intent(
343
+ intent_type=IntentType.TOOL,
344
+ intent_value="knowledge graph",
345
+ intent_target="open_knowledge_graph_explorer",
346
+ ),
347
+ Intent(
348
+ intent_type=IntentType.TOOL,
349
+ intent_value="sparql",
350
+ intent_target="open_knowledge_graph_explorer",
351
+ ),
352
+ Intent(
353
+ intent_type=IntentType.TOOL,
354
+ intent_value="explore ontology",
355
+ intent_target="open_knowledge_graph_explorer",
356
+ ),
357
+ Intent(
358
+ intent_type=IntentType.TOOL,
359
+ intent_value="browse entities",
360
+ intent_target="open_knowledge_graph_explorer",
361
+ ),
362
+ Intent(
363
+ intent_type=IntentType.TOOL,
364
+ intent_value="voir ton kg",
365
+ intent_target="open_knowledge_graph_explorer",
366
+ ),
367
+ Intent(
368
+ intent_type=IntentType.TOOL,
369
+ intent_value="voir le graphe",
370
+ intent_target="open_knowledge_graph_explorer",
371
+ ),
372
+ Intent(
373
+ intent_type=IntentType.TOOL,
374
+ intent_value="explorer les données",
375
+ intent_target="open_knowledge_graph_explorer",
376
+ ),
377
+ Intent(
378
+ intent_type=IntentType.TOOL,
379
+ intent_value="base de données sémantique",
380
+ intent_target="open_knowledge_graph_explorer",
381
+ ),
382
+ # Time tool
383
+ Intent(
384
+ intent_type=IntentType.TOOL,
385
+ intent_value="what time is it",
386
+ intent_target="get_time",
387
+ ),
388
+ ]
389
+
390
+ # Set configuration
391
+ agents_string = "\n".join(
392
+ [f"- {agent.name}: {agent.description}" for agent in agents]
393
+ )
394
+ tools_string = "\n".join([f"- {tool.name}: {tool.description}" for tool in tools])
395
+ if agent_configuration is None:
396
+ agent_configuration = AgentConfiguration(
397
+ system_prompt=SYSTEM_PROMPT.replace("[AGENTS]", agents_string).replace(
398
+ "[TOOLS]", tools_string
399
+ ),
400
+ )
401
+
402
+ # Add intents for each agent (using agent names directly to avoid recursion)
403
+ for agent in agents:
404
+ # Add default intents to chat with any agent
405
+ intents.append(
406
+ Intent(
407
+ intent_type=IntentType.AGENT,
408
+ intent_value=f"Chat with {agent.name} Agent",
409
+ intent_target=agent.name,
410
+ intent_scope=IntentScope.DIRECT,
411
+ )
412
+ )
413
+
414
+ if hasattr(agent, "intents"):
415
+ for intent in agent.intents:
416
+ if (
417
+ intent.intent_scope is not None
418
+ and intent.intent_scope == IntentScope.DIRECT
419
+ ):
420
+ continue
421
+ # Create new intent with target set to agent name
422
+ new_intent = Intent(
423
+ intent_type=IntentType.AGENT,
424
+ intent_value=intent.intent_value,
425
+ intent_target=agent.name,
426
+ )
427
+ intents.append(new_intent)
428
+
429
+ return AbiAgent(
430
+ name=NAME,
431
+ description=DESCRIPTION,
432
+ chat_model=model,
433
+ tools=tools,
434
+ agents=agents,
435
+ intents=intents,
436
+ state=shared_state,
437
+ configuration=agent_configuration,
438
+ )
439
+
440
+
441
+ class AbiAgent(IntentAgent):
442
+ pass
@@ -0,0 +1,157 @@
1
+ import pytest
2
+ from naas_abi.agents.AbiAgent import create_agent as create_abi_agent
3
+
4
+
5
+ @pytest.fixture
6
+ def agent():
7
+ return create_abi_agent()
8
+
9
+
10
+ # ------------------------------------------------------------
11
+ # DIRECT INTENTS
12
+ # ------------------------------------------------------------
13
+
14
+
15
+ def test_hello(agent):
16
+ """Test RAW intent mapping for name question -> RAW intent"""
17
+ result = agent.invoke("hello")
18
+
19
+ # Abi: Hello, what can I do for you?
20
+
21
+ assert result is not None, result
22
+ assert "Hello, what can I do for you?" in result, result
23
+
24
+
25
+ def test_capabilities(agent):
26
+ """Test capabilities of the agent"""
27
+ result = agent.invoke("what can you do")
28
+
29
+ # Abi: I’m Abi, developed by NaasAI. Here’s what I can do for you:
30
+
31
+ # 1. Agent Orchestration: I route your requests to the best specialized AI agents for the task—whether it’s coding, research, business strategy, creative work, or data
32
+ # analysis. 2. Strategic Advisory: I provide high-level consulting on business, technical, and strategic matters, synthesizing insights from multiple sources. 3. Knowledge
33
+ # Integration: I combine information from various agents and data sources to deliver clear, actionable answers. 4. Context Preservation: I keep track of our conversation, so
34
+ # you don’t have to repeat yourself, even when switching between different agents or topics. 5. Task Automation: I can help automate workflows, manage resources, and interact
35
+ # with platforms like GitHub or Naas. 6. Custom Recommendations: I suggest the best AI agent or tool for your specific needs—whether you want speed, cost-efficiency,
36
+ # intelligence, or a particular capability. 7. Multimodal Support: I handle text, images, PDFs, and more, and can generate or analyze content in multiple formats.
37
+
38
+ # If you have a specific task or question, just let me know!
39
+
40
+ assert result is not None, result
41
+ # Check that at least 80% (4 out of 5) of the key capabilities are present
42
+ key_capabilities: list[str] = [
43
+ "orchestration",
44
+ "strategic",
45
+ "advisory",
46
+ "knowledge",
47
+ "integration",
48
+ "coordination",
49
+ "multi-agent",
50
+ "routing",
51
+ "naasai",
52
+ ]
53
+ found_capabilities = sum(1 for cap in key_capabilities if cap in result.lower())
54
+ min_required = int(len(key_capabilities) * 0.7)
55
+ assert found_capabilities >= min_required, (
56
+ f"Only found {found_capabilities} capabilities in response: {result}"
57
+ )
58
+
59
+
60
+ # def test_search_web(agent):
61
+ # """Test search web capability"""
62
+ # from datetime import datetime
63
+ # result = agent.invoke("Ask ChatGPT Agent, what are the news about France today? Start by: 'As of today the date is YYYY-MM-DD.")
64
+
65
+ # assert result is not None, result
66
+ # assert datetime.now().strftime("%Y-%m-%d") in result, result
67
+ # assert "sources" in result.lower(), result
68
+
69
+
70
+ def test_thank_you(agent):
71
+ """Test thank you intent -> RAW intent"""
72
+ result = agent.invoke("thank you")
73
+
74
+ # Abi: You're welcome, can I help you with anything else?
75
+
76
+ assert result is not None, result
77
+ assert "You're welcome, can I help you with anything else?" in result, result
78
+
79
+
80
+ # ------------------------------------------------------------
81
+ # AGENTS CAPABILITIES
82
+ # ------------------------------------------------------------
83
+
84
+
85
+ def test_search_web_intent(agent):
86
+ """Test search web intent -> AGENT intent"""
87
+ result = agent.invoke("search news about ai")
88
+
89
+ # Abi: I found multiple intents that could handle your request:
90
+
91
+ # 1 ChatGPT (confidence: 89.7%) Intent: search news about
92
+ # 2 Grok (confidence: 89.7%) Intent: search news about
93
+
94
+ # Please choose an intent by number (e.g., '1' or '2')
95
+
96
+ assert result is not None, result
97
+ assert "I found multiple intents that could handle your request" in result, result
98
+ assert "chatgpt" in result.lower() or "grok" in result.lower(), result
99
+
100
+
101
+ def test_image_generation_intent(agent):
102
+ """Test AGENT intent mapping for image generation"""
103
+ result = agent.invoke("generate image")
104
+
105
+ # Gemini: What kind of image would you like to generate? Please describe it in detail.
106
+
107
+ assert result is not None, result
108
+ # The agent should route to Gemini for image generation
109
+ assert (
110
+ "describe" in result.lower()
111
+ or "image" in result.lower()
112
+ or "generate" in result.lower()
113
+ ), result
114
+
115
+ result = agent.invoke("a cat in a box")
116
+ assert "generate" in result.lower(), result
117
+
118
+
119
+ def test_multimodal_analysis_intent(agent):
120
+ """Test AGENT intent mapping for multimodal analysis"""
121
+ result = agent.invoke("analyze image")
122
+
123
+ assert result is not None, result
124
+ # The agent should route to Gemini for image analysis
125
+ assert (
126
+ "gemini" in result.lower()
127
+ or "analyze" in result.lower()
128
+ or "image" in result.lower()
129
+ ), result
130
+
131
+
132
+ # ------------------------------------------------------------
133
+ # AGENTS ROUTING
134
+ # ------------------------------------------------------------
135
+
136
+
137
+ def test_chatgpt_intent(agent):
138
+ """Test AGENT intent mapping for chatgpt"""
139
+ result = agent.invoke("@Knowledge_Graph_Builder hello")
140
+
141
+ # Knowledge_Graph_Builder: Hello, what can I do for you?
142
+
143
+ assert result is not None, result
144
+ assert "Hello, what can I do for you?" in result, result
145
+
146
+ result = agent.invoke("search news about ai") # testing routing to other agents
147
+
148
+ # Knowledge_Graph_Builder: I found multiple intents that could handle your request:
149
+
150
+ # 1 ChatGPT (confidence: 89.7%) Intent: search news about
151
+ # 2 Grok (confidence: 89.7%) Intent: search news about
152
+
153
+ # Please choose an intent by number (e.g., '1' or '2')
154
+
155
+ assert result is not None, result
156
+ assert "I found multiple intents that could handle your request" in result, result
157
+ assert "chatgpt" in result.lower() or "grok" in result.lower(), result