Repository: i-am-bee/beeai-labs
Pull request #431: feature: add first working OpenAI agent
Author: login: planetf1
Labels: name: enhancement
description: New feature or request
name: feature
description: New feature
Created: 2025-04-17T09:44:16Z | Merged: 2025-04-23T16:28:33Z

* Adds support for Open AI Agents
* Moves emoji support into Agent (discussed with @akihikokuroda )
* Enables use of Ollama via openAI agent sdk

This is a continuation of/supercedes #414 (no permission to push to branch cc: @maximilien )

Partially Implements: #432 


Diff:
diff --git a/maestro/pyproject.toml b/maestro/pyproject.toml
index f12372c5..bfc10cfe 100644
--- a/maestro/pyproject.toml
+++ b/maestro/pyproject.toml
@@ -23,8 +23,9 @@ streamlit = "^1.44.0"
 streamlit-mermaid = "^0.3.0"
 psutil = "^7.0.0"
 openapi = "^2.0.0"
-crewai = "^0.114.0"
+openai-agents = "^0.0.11"
 pycron = "^3.1.2"
+crewai = "^0.114.0"
 
 [tool.poetry.group.dev.dependencies]
 black = "^24.10.0"
@@ -41,4 +42,4 @@ build-backend = "poetry.core.masonry.api"
 addopts = "-v -s --ignore=framework"
 
 [tool.poetry.scripts]
-"maestro" = "cli.maestro:__run_cli"
\ No newline at end of file
+"maestro" = "cli.maestro:__run_cli"
diff --git a/maestro/src/agents/agent.py b/maestro/src/agents/agent.py
index 73aec03b..68089cf6 100755
--- a/maestro/src/agents/agent.py
+++ b/maestro/src/agents/agent.py
@@ -4,7 +4,8 @@
 from abc import abstractmethod
 import os
 import pickle
-import asyncio
+from typing import Dict, Final
+
 
 class Agent:
     """
@@ -17,22 +18,36 @@ def __init__(self, agent:dict) -> None:
             agent_name (str): The name of the agent.
         """
         # TODO: Review which attributes belong in base class vs subclasses
-        self.agent_name = agent["metadata"]["name"]
-        self.agent_framework = agent["spec"]["framework"]
-        self.agent_model = agent["spec"]["model"]
-
-        self.agent_desc = agent["spec"]["description"]
-        self.agent_instr = agent["spec"]["instructions"]
-        self.agent_input = agent["spec"].get("input")
-        self.agent_output = agent["spec"].get("output")
-        self.instructions = f"{self.agent_instr} Input is expected in format: {self.agent_input}" if self.agent_input else self.agent_instr
-        self.instructions = f"{self.instructions} Output must be in format: {self.agent_output}" if self.agent_output else self.instructions
-
+        self.agent_name = agent['metadata']['name']
+        self.agent_framework = agent['spec']['framework']
+        self.agent_model = agent['spec']['model']
+
+        self.agent_tools = agent['spec'].get('tools', [])
+
+        self.agent_desc = agent['spec']['description']
+        self.agent_instr = agent['spec']['instructions']
+
+        self.agent_input = agent['spec'].get('input')
+        self.agent_output = agent['spec'].get('output')
+
+        self.instructions = f'{self.agent_instr} Input is expected in format: {self.agent_input}' if self.agent_input else self.agent_instr
+        self.instructions = f'{self.instructions} Output must be in format: {self.agent_output}' if self.agent_output else self.instructions
+
+    EMOJIS: Final[Dict[str, str]] = {
+        'beeai': '🐝',
+        'crewai': '👥',
+        'openai': '🔓',
+        'mock': '🤖',
+        'remote': '💸',
+        # Not yet supported
+        # 'langflow': '⛓',
+    }
     def emoji(self) -> str:
-        return AgentFactory.EMOJIS[AgentFramework.MOCK]
+        '''Provides an Emoji for agent type'''
+        return self.EMOJIS.get(self.agent_framework, "⚙️")
 
     def print(self, message) -> str:
-        return f"{self.emoji()} {message}"
+        return f'{self.emoji()} {message}'
 
     @abstractmethod
     async def run(self, prompt: str) -> str:
diff --git a/maestro/src/agents/agent_factory.py b/maestro/src/agents/agent_factory.py
index c3795080..2bf3dde2 100644
--- a/maestro/src/agents/agent_factory.py
+++ b/maestro/src/agents/agent_factory.py
@@ -8,17 +8,6 @@
 from .remote_agent import RemoteAgent
 from .mock_agent import MockAgent
 
-EMOJIS = {
-    'beeai': '🐝',
-    'crewai': '👥',
-    'openai': '🔓',
-    'mock': '🤖',
-    'remote': '💸',
-
-    # # Not yet supported
-    # 'langflow': '⛓',
-}
-
 class AgentFramework(StrEnum):
     """Enumeration of supported frameworks"""
     BEEAI = "beeai"
diff --git a/maestro/src/agents/openai_agent.py b/maestro/src/agents/openai_agent.py
index 4e8e81bc..b69a0282 100644
--- a/maestro/src/agents/openai_agent.py
+++ b/maestro/src/agents/openai_agent.py
@@ -12,11 +12,60 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from .agent import Agent
+import os
+# TODO Only agent *needs* aliasing
+from agents import (
+    Agent as OAIAgent,
+    Runner as OAIRunner,
+    AsyncOpenAI as OAIAsyncOpenAI,
+    set_default_openai_api,
+    set_default_openai_client,
+    set_tracing_disabled,
+)
+from src.agents.agent import Agent
 
 class OpenAIAgent(Agent):
+    """
+    OpenAI extends the Agent class to load and run a agent using OpenAI.
+    """
     def __init__(self, agent: dict) -> None:
-        super.__init__(agent)
+        """
+        Initializes the workflow for the specified OpenAI agent.
+
+        Args:
+            agent_name (str): The name of the agent.
+        """
+        super().__init__(agent)
+        
+        # TODO: Add tools (std and MCP)
+
+        # TODO : for now we use environment variables - set to http://localhost:11434/v1 for Ollama
+        base_url = os.getenv("OPENAI_BASE_URL","https://api.openai.com/v1")
+        api_key = os.getenv("OPENAI_API_KEY")
+        spec_dict = agent.get('spec', {})
+        model_name: str = spec_dict.get('model', "gpt-4o-mini")
+
+        # TODO: Proper debug
+        print(f"DEBUG [OpenAIAgent {self.agent_name}]: Using Base URL: {base_url}")
+        print(f"DEBUG [OpenAIAgent {self.agent_name}]: Using Model: {model_name}")
+        
+        client = OAIAsyncOpenAI(
+            base_url=base_url,
+            api_key=api_key,
+        )
+        # Update the parms for the endpoint. Tracing uses OpenAI backend, so disable tracing too
+        set_default_openai_client(client=client, use_for_tracing=False)
+        # For now, use the chat completions api, even for OpenAI
+        set_default_openai_api("chat_completions")
+        set_tracing_disabled(disabled=True)
+        
+        self.openai_agent = OAIAgent(
+            name=self.agent_name,
+            instructions=self.instructions,
+            model=model_name
+            )
+
+        self.agent_id=self.agent_name
     
     async def run(self, prompt: str) -> str:
         """
@@ -24,15 +73,15 @@ async def run(self, prompt: str) -> str:
         Args:
             prompt (str): The prompt to run the agent with.
         """
-        self.print(f"Running {self.agent_name}...")
-        answer = f"answer for {prompt}" 
-        self.print(f"Response from {self.agent_name}: {answer}")
-        return answer
+        print(f"Running {self.agent_name}...")
+        result = await OAIRunner.run(self.openai_agent, prompt)        
+        print(f"Response from {self.agent_name}: {result.final_output}")
+        return result.final_output
 
     async def run_streaming(self, prompt: str) -> str:
         """
         Runs the agent in streaming mode with the given prompt.
         Args:
             prompt (str): The prompt to run the agent with.
-        """
-        return self.run(prompt)
\ No newline at end of file
+        """        
+        return await self.run(prompt)
\ No newline at end of file
diff --git a/maestro/tests/agents/openai_agent/agents.yaml b/maestro/tests/agents/openai_agent/agents.yaml
index fa9f86c0..1130f51d 100644
--- a/maestro/tests/agents/openai_agent/agents.yaml
+++ b/maestro/tests/agents/openai_agent/agents.yaml
@@ -5,7 +5,10 @@ metadata:
   labels:
     app: testapp
 spec:
-  model: "gpt-4o"
+  model: "gpt-4o-mini"
   description: test
   instructions: echo your prompt
   framework: openai
+  mode: local
+  tools:
+    - web_search
diff --git a/maestro/tests/agents/openai_agent/agents_ollama.yaml b/maestro/tests/agents/openai_agent/agents_ollama.yaml
new file mode 100644
index 00000000..ed646d04
--- /dev/null
+++ b/maestro/tests/agents/openai_agent/agents_ollama.yaml
@@ -0,0 +1,14 @@
+apiVersion: maestro/v1alpha1
+kind: Agent
+metadata:
+  name: openai_test_ollama
+  labels:
+    app: testapp_ollama
+spec:
+  model: "granite3.3:8b"
+  description: test
+  instructions: echo your prompt
+  framework: openai
+  mode: local
+  tools:
+    - web_search
diff --git a/maestro/tests/agents/openai_agent/workflow.yaml b/maestro/tests/agents/openai_agent/workflow.yaml
index 50d756dc..9e76dc7d 100644
--- a/maestro/tests/agents/openai_agent/workflow.yaml
+++ b/maestro/tests/agents/openai_agent/workflow.yaml
@@ -15,5 +15,3 @@ spec:
     steps:
       - name: begin
         agent: openai_test
-      - name: end
-        agent: openai_test
diff --git a/maestro/tests/agents/openai_agent/workflow_ollama.yaml b/maestro/tests/agents/openai_agent/workflow_ollama.yaml
new file mode 100644
index 00000000..8a336461
--- /dev/null
+++ b/maestro/tests/agents/openai_agent/workflow_ollama.yaml
@@ -0,0 +1,17 @@
+apiVersion: maestro/v1alpha1
+kind: Workflow
+metadata:
+  name: openai_test_ollama
+  labels:
+    app: testapp_ollama
+spec:
+  template:
+    metadata:
+      labels:
+        app: testapp_ollama
+    agents:
+      - openai_test_ollama
+    prompt: Welcome OpenAI to the AI Agent OSS party, now with Ollama
+    steps:
+      - name: begin
+        agent: openai_test_ollama
diff --git a/maestro/tests/agents/test_agent.py b/maestro/tests/agents/test_agent.py
new file mode 100755
index 00000000..308d10e5
--- /dev/null
+++ b/maestro/tests/agents/test_agent.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+
+# Copyright © 2025 IBM
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+from src.agents.agent import Agent
+
+class TestAgentEmojis(unittest.TestCase):
+
+    def _create_agent(self, framework: str) -> Agent:
+        agent_dict = {
+            'metadata': {'name': f'{framework}_test_agent'},
+            'spec': {
+                'framework': framework,
+                'model': 'test_model',          # Placeholder value
+                'description': 'test desc',     # Placeholder value
+                'instructions': 'test instr',   # Placeholder value
+            }
+        }
+        return Agent(agent_dict)
+
+    def test_emoji_outputs(self):
+        test_cases = {
+            # Known frameworks from Agent.EMOJIS
+            'beeai': '🐝',
+            'crewai': '👥',
+            'openai': '🔓',
+            'mock': '🤖',
+            'remote': '💸',
+            # Unknown framework should return the default
+            'some_new_framework': '⚙️',
+            'another_unknown': '⚙️',
+            # Edge case: empty string framework name
+            '': '⚙️',
+        }
+
+        for framework, expected_emoji in test_cases.items():
+            with self.subTest(framework=framework):
+                agent = self._create_agent(framework)
+                actual_emoji = agent.emoji()
+
+                self.assertEqual(actual_emoji, expected_emoji,
+                                f"Emoji for framework '{framework}' should be '{expected_emoji}' but got '{actual_emoji}'")
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/maestro/tests/agents/test_agent_factory.py b/maestro/tests/agents/test_agent_factory.py
index 7ad8e83e..f5de2ad9 100755
--- a/maestro/tests/agents/test_agent_factory.py
+++ b/maestro/tests/agents/test_agent_factory.py
@@ -20,7 +20,7 @@
 
 from unittest import TestCase
 
-from src.agents.agent_factory import AgentFramework, AgentFactory, EMOJIS
+from src.agents.agent_factory import AgentFramework, AgentFactory
 
 class TestAgentFramework(TestCase):    
     def test_frameworks(self):        
@@ -30,12 +30,6 @@ def test_frameworks(self):
         self.assertTrue(AgentFramework.MOCK is not None)
         self.assertTrue(AgentFramework.REMOTE is not None)
 
-    def test_EMOJIS(self):
-        self.assertTrue(EMOJIS['beeai'] == '🐝')
-        self.assertTrue(EMOJIS['crewai'] == '👥')
-        self.assertTrue(EMOJIS['openai'] == '🔓')
-        self.assertTrue(EMOJIS['mock'] == '🤖')
-        self.assertTrue(EMOJIS['remote'] == '💸')
 
 class TestAgentFactory(TestCase):    
     def test_create_agents(self):


Reviews:
user: login: maximilien
body: Nice work @planetf1 and will test this some more tomorrow to approve. Just want to try it and today is insane. But overall looks great. Thank you 🙏
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T17:27:45Z
user: login: maximilien
body: OK @planetf1 first issue:

```bash
(maestro-py3.12) ➜  maestro git:(main) maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
Error: Unable to run workflow: descriptor '__init__' requires a 'super' object but received a 'dict'
Error: executing command: 1
```

I did run `poetry update`

Running with `--verbose` you can see stack trace => [431-stack-trace.txt](https://github.com/user-attachments/files/19798890/431-stack-trace.txt)
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T18:09:02Z
user: login: akihikokuroda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T14:32:32Z
user: login: planetf1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T15:18:11Z
user: login: akihikokuroda
body: Is there any way to add tests for this?
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T15:47:12Z
user: login: akihikokuroda
body: LGTM.  Please add tests in CI in the next PR.  Thanks!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-23T16:21:57Z
user: login: maximilien
body: Various issues. Happy with progress but careful to commit clean code and follow the current code conventions as much as possible. Happy to reconsider some as a team but don't introduce new ones until consensus. Will proper review when back.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T11:19:31Z

Review comments:
diff_hunk: @@ -17,22 +18,36 @@ def __init__(self, agent:dict) -> None:
             agent_name (str): The name of the agent.
         """
         # TODO: Review which attributes belong in base class vs subclasses
-        self.agent_name = agent["metadata"]["name"]
-        self.agent_framework = agent["spec"]["framework"]
-        self.agent_model = agent["spec"]["model"]
-
-        self.agent_desc = agent["spec"]["description"]
-        self.agent_instr = agent["spec"]["instructions"]
-        self.agent_input = agent["spec"].get("input")
-        self.agent_output = agent["spec"].get("output")
-        self.instructions = f"{self.agent_instr} Input is expected in format: {self.agent_input}" if self.agent_input else self.agent_instr
-        self.instructions = f"{self.instructions} Output must be in format: {self.agent_output}" if self.agent_output else self.instructions
-
+        self.agent_name = agent['metadata']['name']
path: maestro/src/agents/agent.py
user: login: akihikokuroda
body: Let's open an new issue that makes consistent these to the schema.
created_at: 2025-04-23T14:32:32Z
author_association: MEMBER
diff_hunk: @@ -17,22 +18,36 @@ def __init__(self, agent:dict) -> None:
             agent_name (str): The name of the agent.
         """
         # TODO: Review which attributes belong in base class vs subclasses
-        self.agent_name = agent["metadata"]["name"]
-        self.agent_framework = agent["spec"]["framework"]
-        self.agent_model = agent["spec"]["model"]
-
-        self.agent_desc = agent["spec"]["description"]
-        self.agent_instr = agent["spec"]["instructions"]
-        self.agent_input = agent["spec"].get("input")
-        self.agent_output = agent["spec"].get("output")
-        self.instructions = f"{self.agent_instr} Input is expected in format: {self.agent_input}" if self.agent_input else self.agent_instr
-        self.instructions = f"{self.instructions} Output must be in format: {self.agent_output}" if self.agent_output else self.instructions
-
+        self.agent_name = agent['metadata']['name']
path: maestro/src/agents/agent.py
user: login: planetf1
body: This was @maximilien original commit 5240be732e19892940fecfa4ab475e3d974ab078 - are you ok to open an issue for the followon activity?
created_at: 2025-04-23T15:18:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,22 +18,36 @@ def __init__(self, agent:dict) -> None:
             agent_name (str): The name of the agent.
         """
         # TODO: Review which attributes belong in base class vs subclasses
path: maestro/src/agents/agent.py
user: login: maximilien
body: Let's make sure to associate TODOs with issues. Want to avoid endless ToDOs or comments in code that are never done :)
created_at: 2025-04-25T11:11:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,22 +18,36 @@ def __init__(self, agent:dict) -> None:
             agent_name (str): The name of the agent.
         """
         # TODO: Review which attributes belong in base class vs subclasses
-        self.agent_name = agent["metadata"]["name"]
-        self.agent_framework = agent["spec"]["framework"]
-        self.agent_model = agent["spec"]["model"]
-
-        self.agent_desc = agent["spec"]["description"]
-        self.agent_instr = agent["spec"]["instructions"]
-        self.agent_input = agent["spec"].get("input")
-        self.agent_output = agent["spec"].get("output")
-        self.instructions = f"{self.agent_instr} Input is expected in format: {self.agent_input}" if self.agent_input else self.agent_instr
-        self.instructions = f"{self.instructions} Output must be in format: {self.agent_output}" if self.agent_output else self.instructions
-
+        self.agent_name = agent['metadata']['name']
path: maestro/src/agents/agent.py
user: login: maximilien
body: I believe only @akihikokuroda and I have merge privileges... as others make more contributions we will revisit and grant. Thank you.
created_at: 2025-04-25T11:13:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,22 +18,36 @@ def __init__(self, agent:dict) -> None:
             agent_name (str): The name of the agent.
         """
         # TODO: Review which attributes belong in base class vs subclasses
-        self.agent_name = agent["metadata"]["name"]
-        self.agent_framework = agent["spec"]["framework"]
-        self.agent_model = agent["spec"]["model"]
-
-        self.agent_desc = agent["spec"]["description"]
-        self.agent_instr = agent["spec"]["instructions"]
-        self.agent_input = agent["spec"].get("input")
-        self.agent_output = agent["spec"].get("output")
-        self.instructions = f"{self.agent_instr} Input is expected in format: {self.agent_input}" if self.agent_input else self.agent_instr
-        self.instructions = f"{self.instructions} Output must be in format: {self.agent_output}" if self.agent_output else self.instructions
-
+        self.agent_name = agent['metadata']['name']
+        self.agent_framework = agent['spec']['framework']
+        self.agent_model = agent['spec']['model']
+
+        self.agent_tools = agent['spec'].get('tools', [])
+
+        self.agent_desc = agent['spec']['description']
+        self.agent_instr = agent['spec']['instructions']
+
+        self.agent_input = agent['spec'].get('input')
+        self.agent_output = agent['spec'].get('output')
+
+        self.instructions = f'{self.agent_instr} Input is expected in format: {self.agent_input}' if self.agent_input else self.agent_instr
+        self.instructions = f'{self.instructions} Output must be in format: {self.agent_output}' if self.agent_output else self.instructions
+
+    EMOJIS: Final[Dict[str, str]] = {
+        'beeai': '🐝',
+        'crewai': '👥',
+        'openai': '🔓',
+        'mock': '🤖',
+        'remote': '💸',
+        # Not yet supported
+        # 'langflow': '⛓',
+    }
     def emoji(self) -> str:
-        return AgentFactory.EMOJIS[AgentFramework.MOCK]
+        '''Provides an Emoji for agent type'''
+        return self.EMOJIS.get(self.agent_framework, "⚙️")
 
     def print(self, message) -> str:
-        return f"{self.emoji()} {message}"
+        return f'{self.emoji()} {message}'
path: maestro/src/agents/agent.py
user: login: maximilien
body: What's this change for? Double quotes is what we have used for `f...` strings. Let's not use single quotes in these cases please. For simple strings totally agree with single quotes
created_at: 2025-04-25T11:15:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,27 +12,76 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from .agent import Agent
+import os
+# TODO Only agent *needs* aliasing
+from agents import (
+    Agent as OAIAgent,
+    Runner as OAIRunner,
+    AsyncOpenAI as OAIAsyncOpenAI,
+    set_default_openai_api,
+    set_default_openai_client,
+    set_tracing_disabled,
+)
+from src.agents.agent import Agent
 
 class OpenAIAgent(Agent):
+    """
+    OpenAI extends the Agent class to load and run a agent using OpenAI.
+    """
     def __init__(self, agent: dict) -> None:
-        super.__init__(agent)
+        """
+        Initializes the workflow for the specified OpenAI agent.
+
+        Args:
+            agent_name (str): The name of the agent.
+        """
+        super().__init__(agent)
+        
+        # TODO: Add tools (std and MCP)
+
+        # TODO : for now we use environment variables - set to http://localhost:11434/v1 for Ollama
+        base_url = os.getenv("OPENAI_BASE_URL","https://api.openai.com/v1")
+        api_key = os.getenv("OPENAI_API_KEY")
+        spec_dict = agent.get('spec', {})
+        model_name: str = spec_dict.get('model', "gpt-4o-mini")
+
+        # TODO: Proper debug
path: maestro/src/agents/openai_agent.py
user: login: maximilien
body: Please no debug in committed code please. And same point about todo
created_at: 2025-04-25T11:16:03Z
author_association: CONTRIBUTOR

PR comments:
user: login: planetf1
created_at: 2025-04-17T09:46:50Z
body: Resolved conflicts with naming (we can update the aliasing to team preferences)
Agent creation successful:
```
((.venv) ) ➜  maestro git:(issue384_openai) maestro create tests/agents/openai_agent/agents.yaml
2025-04-17 10:46:28.562 WARNING streamlit.runtime.scriptrunner_utils.script_run_context: Thread 'MainThread': missing ScriptRunContext! This warning can be ignored when running in bare mode.
```
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-17T16:23:38Z
body: ```
((.venv) ) ➜  maestro git:(issue384_openai) maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
2025-04-17 17:23:17.871 WARNING streamlit.runtime.scriptrunner_utils.script_run_context: Thread 'MainThread': missing ScriptRunContext! This warning can be ignored when running in bare mode.
Running openai_test...
Response from openai_test: Thank you for the warm welcome! What's happening at the AI Agent OSS party?
```
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-17T16:46:01Z
body: To run the sample test agent against a real openAI backend, set `OPENAI_API_KEY` to a valid OpenAI API key, then directly with
```
maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
```

This could be scripted as an integration test
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-17T17:17:08Z
body: To test using ollama, ensure you have 'granite-3.3:8b' installed:
```
((.venv) ) ➜  maestro git:(issue384_openai) ✗ maestro run tests/agents/openai_agent/agents_ollama.yaml tests/agents/openai_agent/workflow_ollama.yaml
2025-04-17 18:15:20.467 WARNING streamlit.runtime.scriptrunner_utils.script_run_context: Thread 'MainThread': missing ScriptRunContext! This warning can be ignored when running in bare mode.
DEBUG [OpenAIAgent openai_test_ollama]: Using Base URL: http://localhost:11434/v1
DEBUG [OpenAIAgent openai_test_ollama]: Using Model: granite3.3:8b
Running openai_test_ollama...
Response from openai_test_ollama: Sure, I'm here to assist you. It looks like you're introducing a new development involving an AI agent in an open-source software project named "Ollama". Is there a specific question or information about this development that you'd like me to help explore or clarify?
```
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-17T17:20:02Z
body: > Resolved conflicts with naming (we can update the aliasing to team preferences) Agent creation successful:
> 
> ```
> ((.venv) ) ➜  maestro git:(issue384_openai) maestro create tests/agents/openai_agent/agents.yaml
> 2025-04-17 10:46:28.562 WARNING streamlit.runtime.scriptrunner_utils.script_run_context: Thread 'MainThread': missing ScriptRunContext! This warning can be ignored when running in bare mode.
> ```

We have an issue for this *annoying* #373. If it annoys as much as me and want to solve please see the discussions and closed PRs that have attempted to solve it but failed. Thx
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-17T17:31:56Z
body: > To run the sample test agent against a real openAI backend, set `OPENAI_API_KEY` to a valid OpenAI API key, then directly with
> 
> ```
> maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
> ```
> 
> This could be scripted as an integration test

As we discussed for integration tests let's just skip them in CI for now. And for local dev then run optionally when .env has the keys present. Or something like that.
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-17T17:33:12Z
body: Also @planetf1 you need to sign your commits: `git ci -s -m "commit message" --amend` should help you sign and you will see the "Unverified" removed from commit list.
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-17T18:21:02Z
body: @maximilien works for me:
```shell
((.venv) ) ➜  maestro git:(issue384_openai) poetry lock && poetry sync                                                               
Resolving dependencies... (0.4s)
Installing dependencies from lock file

No dependencies to install or update

Installing the current project: maestro (0.1.0)
((.venv) ) ➜  maestro git:(issue384_openai) maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
2025-04-17 19:18:14.608 WARNING streamlit.runtime.scriptrunner_utils.script_run_context: Thread 'MainThread': missing ScriptRunContext! This warning can be ignored when running in bare mode.
DEBUG [OpenAIAgent openai_test]: Using Base URL: https://api.openai.com/v1
DEBUG [OpenAIAgent openai_test]: Using Model: gpt-4o-mini
Running openai_test...
Response from openai_test: Thank you! I'm excited to be part of the AI Agent open-source software (OSS) community. It's a great space for collaboration, innovation, and sharing knowledge. How can I assist you at this party?
```

`poetry update` may update dependencies. Can you check the above to sync with the current definitions? - 

Also the exception looks like an issue I before making changes. Are you at the right code level?
```
05d193a (HEAD -> issue384_openai, origin/issue384_openai) OpenAI support - support Ollama
```

Will look at adding signing key 
Tried a number of options with streamlit - not addressed yet.
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-17T18:22:19Z
body: Definitely the wrong code - I have some (hardcoded for now) debug statements in the current version. I don't see them in your output
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-17T18:51:46Z
body: Updated signing. commits now verified.
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-17T21:06:23Z
body: > Definitely the wrong code - I have some (hardcoded for now) debug statements in the current version. I don't see them in your output

Ok tested quickly since got so many things today. Will try again tomorrow from scratch
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-18T14:40:12Z
body: OK nice. Worked. You still have it as draft so I assume you have more to complete. Like for instance streaming run. I'd be happy to split what's left into a separate PR ... 
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-18T15:36:19Z
body: Feel free to move out of draft and merge if it helps you to build on top. I think my next target is mcp tool usage particularly via sse
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-22T10:30:50Z
body: @maximilien rebased - would you rereview? I'll make the next batch of changes in a new branch(which will depend on these commits)
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-22T10:54:50Z
body: @akihikokuroda After merging with the latest updates from main, the agent no longer works:
```
((.venv) ) ➜  openai_agent git:(issue384_openai) ✗ maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
Traceback (most recent call last):
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/.venv/bin/maestro", line 3, in <module>
    from cli.maestro import __run_cli
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/cli/maestro.py", line 59, in <module>
    from commands import CLI
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/cli/../cli/commands.py", line 24, in <module>
    from src.deploy import Deploy
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/src/__init__.py", line 19, in <module>
    from .workflow import Workflow
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/src/workflow.py", line 22, in <module>
    from src.agents.agent_factory import AgentFramework, AgentFactory
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/src/agents/agent_factory.py", line 5, in <module>
    from .beeai_agent import BeeAIAgent, BeeAILocalAgent
  File "/Users/jonesn/AI/bee/beeai-labs/maestro/src/agents/beeai_agent.py", line 16, in <module>
    from beeai_framework.adapters.ollama import OllamaChatModel
ModuleNotFoundError: No module named 'beeai_framework'
```
I noticed the beeai agent framework dependency was removed and a few other dependencies changed? (#434 and #438)

The AgentFactory still imports BeeAILocalAgent which still depends on the beeai_framework module.
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-22T11:04:35Z
body: Agent execution broken: https://github.com/i-am-bee/beeai-labs/issues/440
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-22T16:50:26Z
body: Yeah. LMK when we have stable version and passing tests. Also tag @akihikokuroda to review in case we are not ready by EOD today 
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-23T09:24:34Z
body: This is now rebased with main (if the approach to dependency clash is merged first, I'll rebase/merge)

This is again running ok:
```
((.venv) ) ➜  maestro git:(issue384_openai) maestro run tests/agents/openai_agent/agents.yaml tests/agents/openai_agent/workflow.yaml
2025-04-23 10:24:19.278 WARNING streamlit.runtime.scriptrunner_utils.script_run_context: Thread 'MainThread': missing ScriptRunContext! This warning can be ignored when running in bare mode.
DEBUG [OpenAIAgent openai_test]: Using Base URL: https://api.openai.com/v1
DEBUG [OpenAIAgent openai_test]: Using Model: gpt-4o-mini
Running openai_test...
Response from openai_test: Thank you! I'm excited to be part of the AI Agent OSS community. Open-source software contributes to collaboration and innovation, and I'm here to help with any questions or ideas you want to discuss. What do you have in mind for the party?
```
author_association: CONTRIBUTOR
user: login: maximilien
created_at: 2025-04-23T13:23:23Z
body: Please tag @akihikokuroda and @george-lhj to review for you while I am on vacation. Thx
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-23T16:13:43Z
body: Currently there are maestro tests, but they need a openAI (with api key) or ollama back-end running
We could do one/both of
 - use mocking to avoid accessing the back-end
 - use something like liteLLM proxy started up within the github action to give simple responses to the llm calls
 
 Since I have 2 further PRs based on this I would prefer we track this via a new Issue/PR?
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-23T16:18:00Z
body: Opened https://github.com/i-am-bee/beeai-labs/issues/449 to track additional tests
author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-23T16:24:08Z
body: @akihikokuroda there's a backlog of stacked PRs which tackle different aspects (streaming, then base MCP)..

author_association: CONTRIBUTOR
user: login: planetf1
created_at: 2025-04-23T16:24:49Z
body: @akihikokuroda @george-lhj I don't have permissions to merge on this repo. Can you oblige then I'll rebase the next one for review
author_association: CONTRIBUTOR