Repository: sonnhfit/SonAgent (language: python)

Issue:
update env



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e69de29..f16b24c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,171 @@
+name: SonAgent CI
+
+on:
+  push:
+    branches:
+      - main
+      - dev
+      - ci/*
+    tags:
+  release:
+    types: [published]
+  pull_request:
+  schedule:
+    - cron:  '0 3 * * 4'
+
+concurrency:
+  group: "${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}"
+  cancel-in-progress: true
+permissions:
+  repository-projects: read
+jobs:
+  build-linux:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ubuntu-22.04]
+        python-version: ["3.11"]
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Set up Python
+      uses: actions/setup-python@v5
+      with:
+        python-version: ${{ matrix.python-version }}
+
+    - name: Cache_dependencies
+      uses: actions/cache@v4
+      id: cache
+      with:
+        path: ~/dependencies/
+        key: ${{ runner.os }}-dependencies
+
+    - name: pip cache (linux)
+      uses: actions/cache@v4
+      with:
+        path: ~/.cache/pip
+        key: test-${{ matrix.os }}-${{ matrix.python-version }}-pip
+
+
+    - name: Installation - *nix
+      run: |
+        python -m pip install --upgrade pip wheel
+        pip install -r requirements-dev.txt
+        pip install -e .
+
+    - name: Tests
+      run: |
+        pytest --random-order --cov=sonagent --cov-config=.coveragerc
+
+    - name: Check for repository changes
+      run: |
+        if [ -n "$(git status --porcelain)" ]; then
+          echo "Repository is dirty, changes detected:"
+          git status
+          git diff
+          exit 1
+        else
+          echo "Repository is clean, no changes detected."
+        fi
+
+    - name: Sort imports (isort)
+      run: |
+        isort --check .
+
+    - name: Run Ruff
+      run: |
+        ruff check --output-format=github .
+
+    - name: Discord notification
+      uses: rjstone/discord-webhook-notify@v1
+      if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
+      with:
+          severity: error
+          details: SonAgent CI failed on ${{ matrix.os }}
+          webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
+
+  # Notify only once - when CI completes (and after deploy) in case it's successfull
+  notify-complete:
+    needs: [
+      build-linux
+    ]
+    runs-on: ubuntu-22.04
+    # Discord notification can't handle schedule events
+    if: github.event_name != 'schedule' && github.repository == 'sonnhfit/SonAgent'
+    permissions:
+      repository-projects: read
+    steps:
+
+    - name: Check user permission
+      id: check
+      uses: scherermichael-oss/action-has-permission@1.0.6
+      with:
+        required-permission: write
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+    - name: Discord notification
+      uses: rjstone/discord-webhook-notify@v1
+      if: always() && steps.check.outputs.has-permission && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
+      with:
+          severity: info
+          details: Test Completed!
+          webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
+
+  build:
+    name: "Build"
+    needs: [build-linux]
+    runs-on: ubuntu-22.04
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Set up Python
+      uses: actions/setup-python@v5
+      with:
+        python-version: "3.11"
+
+    - name: Build distribution
+      run: |
+        pip install -U build
+        python -m build --sdist --wheel
+
+    - name: Upload artifacts 📦
+      uses: actions/upload-artifact@v4
+      with:
+        name: sonagent-build
+        path: |
+          dist
+        retention-days: 10
+
+  deploy-pypi:
+    name: "Deploy to PyPI"
+    needs: [ build ]
+    runs-on: ubuntu-22.04
+    if: (github.event_name == 'release')
+    environment:
+      name: release
+      url: https://pypi.org/p/sonagent
+    permissions:
+      id-token: write
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Download artifact  📦
+      uses: actions/download-artifact@v4
+      with:
+        pattern: sonagent*-build
+        path: dist
+        merge-multiple: true
+
+
+    - name: Publish to PyPI (Test)
+      uses: pypa/gh-action-pypi-publish@v1.8.14
+      with:
+        password: ${{ secrets.PYPI_API_TOKEN }}
+        repository-url: https://test.pypi.org/legacy/
+
+    - name: Publish to PyPI
+      uses: pypa/gh-action-pypi-publish@v1.8.14
diff --git a/docs/source/conf.py b/docs/source/conf.py
index ed686b0..a2782d7 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -13,6 +13,7 @@
 #
 import os
 import sys
+
 sys.path.insert(0, os.path.abspath('../..'))
 sys.path.append(os.path.abspath(
     os.path.join(__file__, "../../sonagent")
diff --git a/docs/source/dev.md b/docs/source/dev.md
new file mode 100644
index 0000000..807cb3d
--- /dev/null
+++ b/docs/source/dev.md
@@ -0,0 +1,5 @@
+Dev 
+- fix coding convention
+```
+ruff check --fix .
+```
\ No newline at end of file
diff --git a/sonagent/core_prompt/__init__.py b/examples/.gitkeep
similarity index 100%
rename from sonagent/core_prompt/__init__.py
rename to examples/.gitkeep
diff --git a/examples/planning_agent.py b/examples/planning_agent.py
deleted file mode 100644
index 472a53e..0000000
--- a/examples/planning_agent.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import asyncio
-import semantic_kernel as sk
-from sonagent.planning.planner import SonAgentPlanner
-from semantic_kernel.planning.basic_planner import BasicPlanner
-
-
-async def main():
-    kernel = sk.Kernel()
-    planner = BasicPlanner()
-    ask = "If my investment of 2130.23 dollars increased by 23%, how much would I have after I spent $5 on a latte?"
-    # plan =  await planner.create_plan_async(ask, kernel)
-    print("ok")
-
-asyncio.run(main())
\ No newline at end of file
diff --git a/examples/planning_sonagent.ipynb b/examples/planning_sonagent.ipynb
deleted file mode 100644
index fb1685d..0000000
--- a/examples/planning_sonagent.ipynb
+++ /dev/null
@@ -1,135 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "The asyncio module is not an IPython extension.\n"
-     ]
-    }
-   ],
-   "source": [
-    "%load_ext asyncio\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
-    "\n",
-    "deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "\n",
-    "kernel = sk.Kernel()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 20,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "<semantic_kernel.kernel.Kernel at 0x116dcb590>"
-      ]
-     },
-     "execution_count": 20,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "kernel.add_chat_service(\"chat_completion\", AzureChatCompletion(deployment, endpoint, api_key))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 21,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import semantic_kernel as sk\n",
-    "from sonagent.planning.planner import SonAgentPlanner"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 29,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "async def main():\n",
-    "    # kernel = sk.Kernel()\n",
-    "    planner = SonAgentPlanner()\n",
-    "    ask = \"create AI company?\"\n",
-    "    plan =  await planner.create_plan_async(ask, kernel)\n",
-    "    print(plan.generated_plan)\n",
-    "    print(\"ok\")\n",
-    "\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 30,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "{\n",
-      "    \"input\": \"AI company\",\n",
-      "    \"subtasks\": [\n",
-      "        {\"function\": \"_GLOBAL_FUNCTIONS_.f_16bed5c1_906f_4208_a39b_038ee3a6d187\", \"args\": {\"available_functions\": [list of available functions], \"goal\": \"develop company mission and values\"}},\n",
-      "        {\"function\": \"_GLOBAL_FUNCTIONS_.f_11164a1f_46d9_4f51_a95a_7bb37c6fba13\", \"args\": {\"available_functions\": [list of available functions], \"goal\": \"create a business plan\"}},\n",
-      "        {\"function\": \"_GLOBAL_FUNCTIONS_.f_2826534a_1d37_492b_a2e0_0b8d41098b14\", \"args\": {\"available_functions\": [list of available functions], \"goal\": \"raise capital\"}},\n",
-      "        {\"function\": \"_GLOBAL_FUNCTIONS_.f_943906c7_e357_4e43_adf4_fbabeadd59ce\", \"args\": {\"available_functions\": [list of available functions], \"goal\": \"build and launch product\"}}\n",
-      "    ]\n",
-      "}\n",
-      "ok\n"
-     ]
-    }
-   ],
-   "source": [
-    "await main()"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "sonagent",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.12.0"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/requirements-dev.txt b/requirements-dev.txt
new file mode 100644
index 0000000..374d05e
--- /dev/null
+++ b/requirements-dev.txt
@@ -0,0 +1,23 @@
+coveralls==3.3.1
+ruff==0.3.5
+mypy==1.9.0
+pre-commit==3.7.0
+pytest==8.1.1
+pytest-asyncio==0.23.6
+pytest-cov==5.0.0
+pytest-mock==3.14.0
+pytest-random-order==1.1.1
+pytest-xdist==3.5.0
+isort==5.13.2
+# For datetime mocking
+time-machine==2.14.1
+
+# Convert jupyter notebooks to markdown documents
+nbconvert==7.16.3
+
+# mypy types
+types-cachetools==5.3.0.7
+types-filelock==3.2.7
+types-requests==2.31.0.20240311
+types-tabulate==0.9.0.20240106
+types-python-dateutil==2.9.0.20240316
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 014ba26..f3d9036 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,8 +18,7 @@ psutil==5.9.7
 
 python-rapidjson==1.14
 orjson==3.9.10
-# semantic-kernel==0.3.12.dev0
-semantic-kernel==0.4.5.dev0
+
 # Notify systemd
 sdnotify==0.3.2
 GitPython==3.1.42
diff --git a/setup.py b/setup.py
index d4530ea..c124d3a 100644
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,11 @@
 #!/usr/bin/env python3
 
-# import os
-from setuptools import setup, find_packages
-from sonagent.version import __version__
 from pathlib import Path
 
+from setuptools import find_packages, setup
+
+from sonagent.version import __version__
+
 this_directory = Path(__file__).parent
 long_description = """
 ### Autonomous Agent for Digital Consciousness Backup Using Large Language Models (LLM) 
@@ -43,7 +44,6 @@
     'psutil==5.9.7',
     'python-rapidjson==1.14',
     'orjson==3.9.10',
-    'semantic-kernel==0.4.5.dev0',
     'sdnotify==0.3.2',
     'GitPython==3.1.42',
     'pyautogen==0.2.15',
@@ -80,9 +80,7 @@
         ]
     },
     classifiers=[
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
         "Programming Language :: Python :: 3.12",
     ],
     keywords="agent ai ml language-model autonomus-robots large-language-models llm chatgpt llama2",
diff --git a/sonagent/__init__.py b/sonagent/__init__.py
index 58f3ace..5c0cf28 100644
--- a/sonagent/__init__.py
+++ b/sonagent/__init__.py
@@ -1,1 +1,1 @@
-from .version import __version__
+from .version import __version__  # noqa: F401
diff --git a/sonagent/__main__.py b/sonagent/__main__.py
index 5b6958a..6998333 100644
--- a/sonagent/__main__.py
+++ b/sonagent/__main__.py
@@ -8,6 +8,5 @@
 
 from sonagent import main
 
-
 if __name__ == '__main__':
     main.main()
diff --git a/sonagent/agent.py b/sonagent/agent.py
index 89d4d7f..ab02fea 100644
--- a/sonagent/agent.py
+++ b/sonagent/agent.py
@@ -1,29 +1,18 @@
-import os
-import logging
 import json
-import yaml
-from sonagent.persistence import Belief, Plan, ScheduleJob
-
-from sonagent.memory.memory import SonMemory
-from sonagent.memory.short_memory import ShortTermMemory
-from sonagent.planning.planner import SonAgentPlanner, SonAgentSequentialPlanner
-import semantic_kernel as sk
-from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, OpenAIChatCompletion
-import semantic_kernel.connectors.ai.open_ai as sk_oai
-from semantic_kernel.planning.sequential_planner.sequential_planner_parser import (
-    SequentialPlanParser,
-)
-
-from sonagent.planning.prompt import PROMPT_PLAN, SEQUENCE_PLAN, CLEAN_BELIEF_PROMPT
-from sonagent.core_prompt.me import ASK_ABOUT_ME_PROMP
-from sonagent.coding.gencode import SonCodeAgent
-from sonagent.tools import GitManager, LocalCodeManager
-from openai import OpenAI
-from sonagent.llm.oai_llm import auto_create_schedule_json_llm
+import logging
+import os
 from datetime import datetime
+
+import yaml
 from croniter import croniter
-from sonagent.utils.datetime_helpers import dt_now
+from openai import OpenAI
 
+from sonagent.nerve_system import Brain
+from sonagent.nerve_system.memory_area import ShortTermMemory, SonMemory
+from sonagent.nerve_system.stimulus import Stimulus
+from sonagent.persistence import Belief, Environment, Plan, ScheduleJob
+from sonagent.tools import GitManager, LocalCodeManager
+from sonagent.utils.datetime_helpers import dt_now
 
 logger = logging.getLogger(__name__)
 
@@ -31,13 +20,25 @@
 class Agent:
     def __init__(self, memory_path, skills, config: dict) -> None:
         # memory
-        logger.debug(f"init memory with path {memory_path}.")
-        self.memory = SonMemory(default_memory_path=memory_path)
 
         self.config = config
 
-        # planner
-        self.planner = SonAgentPlanner()
+        logger.debug(f"Init memory with path {memory_path}.")
+
+        # get memory config
+        memory_config = self.config.get("vector_memory")
+        self.memory = SonMemory(
+            collection_name=memory_config.get("collection", "son_memory"),
+            memory_type=memory_config.get("type", "file"),
+            embedding_type=memory_config.get("embedding_type", "openai"),
+            default_memory_path=memory_path,
+            host=memory_config.get("host", "localhost"),
+            port=memory_config.get("port", 8000),
+        )
+        
+        llm_config = self.config.get('llm')
+        self.brain = Brain(llm_config=llm_config)
+
         # self.sync_beliefs()
 
         self.skills = skills
@@ -47,77 +48,47 @@ def __init__(self, memory_path, skills, config: dict) -> None:
         self.skills_dict = {}
         logger.info("--------- Start Done.---------")
 
-
-        openai = self.config.get('openai')
-        if openai.get('api_type', None) == 'openai':
-            self.chat_service = OpenAIChatCompletion(
-                ai_model_id="gpt-4-0125-preview", api_key=os.environ["OPENAI_API_KEY"]
-            )
-        elif openai.get('api_type', None) == 'azure':
-            deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
-            self.chat_service = AzureChatCompletion(
-                deployment_name=deployment, endpoint=endpoint, api_key=api_key
-            )
-
         self.short_term_memory = ShortTermMemory(
             collection_name="short_term_memory", default_memory_path=memory_path
         )
 
-        # print(deployment, api_key, endpoint)
-        self.kernel = sk.Kernel()
-        
-        self.kernel.add_chat_service(
-            "chat_completion",
-            self.chat_service
-        )
-
         # git manager
-        github = self.config.get('github')
-        if github.get('enabled'):
+        github = self.config.get("github")
+        if github.get("enabled"):
             self.git_manager = GitManager(
-                username=github.get('username'),
-                repo_name=github.get('repo_name'),
-                token=github.get('token'),
-                local_repo_path=github.get('local_repo_path')
+                username=github.get("username"),
+                repo_name=github.get("repo_name"),
+                token=github.get("token"),
+                local_repo_path=github.get("local_repo_path"),
             )
         else:
-            self.git_manager = LocalCodeManager(local_repo_path=self.config.get('user_data_dir'))
-        
-        if self.git_manager is not None:
-            user_data_dir = self.config.get('user_data_dir')
-            self.codeagent = SonCodeAgent(
-                git_manager=self.git_manager, user_data_dir=user_data_dir
+            self.git_manager = LocalCodeManager(
+                local_repo_path=self.config.get("user_data_dir")
             )
-        else:
-            self.codeagent = SonCodeAgent()
 
-        # load skill dict 
+        # load skill dict
         self.init_skills_dict()
 
     def remove_skill(self, skill_name):
-        # remove skill_name from yaml 
+        # remove skill_name from yaml
 
         skill_file_path = f"{self.git_manager.local_repo_path}/skills/skills.yaml"
 
-        with open(skill_file_path, 'r') as file:
+        with open(skill_file_path, "r") as file:
             skills_register = yaml.safe_load(file)
         try:
-            skills_register['skills'].remove(skill_name)
+            skills_register["skills"].remove(skill_name)
         except Exception as e:
             return f"skill doesn't exist: {e}"
 
-        with open(skill_file_path, 'w') as file:
+        with open(skill_file_path, "w") as file:
             yaml.dump(skills_register, file)
-    
 
         # reload skill
         self.reload_skills()
 
         return f"Remove skill {skill_name} successfully."
 
-    def save_function_to_memory(self, function_name: str) -> None:
-        pass
-
     def init_skills_dict(self) -> None:
         for skill in self.skills.get_all_skills():
             self.skills_dict[str(skill.__class__.__name__)] = skill
@@ -142,51 +113,6 @@ def reload_skills(self) -> str:
         self._reload_skills()
         return self.show_skills()
 
-    async def run(self, input) -> None:
-        # get belief -> thinking, planning -> acting
-
-        belief = self.memory.brain_area_search(
-            area_collection_name="belief_base", query=input
-        )
-        belief_ids = belief["ids"][0]
-        result_list = self.get_beliefs_for_planner(belief_ids)
-        belief_text = ""
-        for item in result_list:
-            belief_text += item.text
-
-        deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
-        # print(deployment, api_key, endpoint)
-        kernel = sk.Kernel()
-        kernel.add_chat_service(
-            "chat_completion",
-            AzureChatCompletion(
-                deployment_name=deployment, endpoint=endpoint, api_key=api_key
-            ),
-        )
-
-        # planner = SonAgentPlanner()
-        ask = "train a neural network for classify 0 -> 9?"
-        # plan = await planner.create_plan_async(ask, kernel)
-        # print(plan.generated_plan)
-
-        variables = sk.ContextVariables()
-
-        variables["believe"] = belief_text
-        variables["goal"] = ask
-
-        semantic_function = kernel.create_semantic_function(PROMPT_PLAN)
-        result = await kernel.run_async(
-            semantic_function,
-            input_vars=variables,
-        )
-        print(result)
-        print(type(result))
-        print("plan: ", result.json())
-
-        print("skill: ", result.skills)
-
-        # self._create_belief("my name is Son", "this is my name")
-
     def sync_beliefs(self) -> None:
         logger.debug("Start syncing beliefs to memory.")
         list_belief = Belief.get_all_belief()
@@ -196,7 +122,7 @@ def sync_beliefs(self) -> None:
                 belief.text,
                 {"description": belief.description},
                 str(belief.id),
-                area_collection_name="belief_base",
+                collection_name="belief_base",
             )
         logger.info("Finish syncing beliefs to memory.")
 
@@ -228,31 +154,52 @@ def delete_everything(self) -> bool:
 
     def get_tools(self) -> list:
         return []
+    
+    async def show_env(self) -> list:
+        env_list = Environment.get_all_environment()
+        result = []
+        for env in env_list:
+            result.append([env.key, env.value[:10], env.description[:10]])
+        return result
 
-    async def excute_plan_task(self, task: dict) -> str: 
-        task_intance = str(task['function']).split('.')
+    async def remove_env(self, key: str) -> str:
+        env = Environment.session.query(Environment).filter_by(key=key).first()
+        if env is None:
+            return f"Key {key} not found."
+        Environment.session.delete(env)
+        Environment.session.commit()
+        return f"Key {key} removed successfully."
+    
+    async def add_env(self, key: str, value: str, description: str) -> str:
+        env = Environment(key=key, value=value, description=description)
+        Environment.session.add(env)
+        Environment.session.commit()
+        return f"Key {key} added successfully."
+    
+    async def excute_plan_task(self, task: dict) -> str:
+        task_intance = str(task["function"]).split(".")
         if len(task_intance) < 2:
             return "Error: function name is not valid."
         class_name = task_intance[0]
         function_name = task_intance[1]
         task_func = getattr(self.skills_dict[class_name], function_name)
         logger.info(f"task_func: {task}")
-        if 'args' in task.keys():
-            result = task_func(**task['args'])
+        if "args" in task.keys():
+            result = task_func(**task["args"])
         else:
             result = task_func()
         return result
 
-    def excute_subtask(self, task: dict) -> str: 
-        task_intance = str(task['function']).split('.')
+    def excute_subtask(self, task: dict) -> str:
+        task_intance = str(task["function"]).split(".")
         if len(task_intance) < 2:
             return "Error: function name is not valid."
         class_name = task_intance[0]
         function_name = task_intance[1]
         task_func = getattr(self.skills_dict[class_name], function_name)
         logger.info(f"task_func: {task}")
-        if 'args' in task.keys():
-            result = task_func(**task['args'])
+        if "args" in task.keys():
+            result = task_func(**task["args"])
         else:
             result = task_func()
         return result
@@ -290,30 +237,41 @@ async def create_schedule_for_task_or_plan(self, goal_plan: str) -> str:
         plan_json = plan_json.replace("```json", "").replace("```", "")
         plan_json = json.loads(plan_json)
         logger.info(f"sk planner schedule json: {plan_json}")
+        json_data_schedule = self.brain.language_brain.process(
+            stimulus=Stimulus.SCHEDULING,
+            goal=goal_plan
+        )
 
-        json_data_schedule = auto_create_schedule_json_llm(goal=goal_plan)
-        json_data_schedule = json_data_schedule.replace("```json", "").replace("```", "")
+        json_data_schedule = json_data_schedule.replace("```json", "").replace(
+            "```", ""
+        )
         schedule_plan_json = json.loads(json_data_schedule)
         logger.info(f"plan schedule json: {schedule_plan_json}")
         try:
             schedule_start_at = None
             schedule_end_at = None
-            if len(schedule_plan_json['schedule_start_at']) > 1:
-                schedule_start_at = datetime.strptime(schedule_plan_json['schedule_start_at'], "%Y-%m-%d %H:%M:%S")
-            
-            if len(schedule_plan_json['schedule_end_at']) > 1:
-                schedule_end_at = datetime.strptime(schedule_plan_json['schedule_end_at'], "%Y-%m-%d %H:%M:%S")
+            if len(schedule_plan_json["schedule_start_at"]) > 1:
+                schedule_start_at = datetime.strptime(
+                    schedule_plan_json["schedule_start_at"], "%Y-%m-%d %H:%M:%S"
+                )
+
+            if len(schedule_plan_json["schedule_end_at"]) > 1:
+                schedule_end_at = datetime.strptime(
+                    schedule_plan_json["schedule_end_at"], "%Y-%m-%d %H:%M:%S"
+                )
             timenow = dt_now()
 
-            cron = croniter(schedule_plan_json['schedule_interval'], timenow)
+            cron = croniter(schedule_plan_json["schedule_interval"], timenow)
             next_run_at = cron.get_next(datetime)
-            logger.info(f"Create schedule with next run is: {next_run_at} and timenow: {timenow}")
+            logger.info(
+                f"Create schedule with next run is: {next_run_at} and timenow: {timenow}"
+            )
 
             schedule_job = ScheduleJob(
-                name=schedule_plan_json['name'],
-                description=schedule_plan_json['description'],
-                is_recurring=schedule_plan_json['is_recurring'],
-                schedule_interval=schedule_plan_json['schedule_interval'],
+                name=schedule_plan_json["name"],
+                description=schedule_plan_json["description"],
+                is_recurring=schedule_plan_json["is_recurring"],
+                schedule_interval=schedule_plan_json["schedule_interval"],
                 schedule_start_at=schedule_start_at,
                 schedule_end_at=schedule_end_at,
                 next_run_at=next_run_at,
@@ -325,15 +283,12 @@ async def create_schedule_for_task_or_plan(self, goal_plan: str) -> str:
         except Exception as e:
             logger.error(f"Error create schedule job: {e}")
             return str(e)
-        
-        return "Schedule job created successfully."
 
+        return "Schedule job created successfully."
 
     async def chat(self, input: str) -> str:
 
-        belief = self.memory.brain_area_search(
-            area_collection_name="belief_base", query=input
-        )
+        belief = self.memory.search(collection_name="belief_base", query=input)
 
         belief_ids = belief["ids"][0]
 
@@ -346,44 +301,47 @@ async def chat(self, input: str) -> str:
         belief_text = ""
         for item in result_list:
             belief_text += str("-" + item.text + "\n")
-        
+
         logger.info(f"Belief_text: \n{belief_text}")
         if len(self.short_term_memory.get_chat_dialog()) == 0:
             self.short_term_memory.add_chat_item(
-                {"role": "system", "content": f"You are a virtual assistant with the ability to create plans for executing tasks using the create_plan_with_skills function if user need you do something. If the user's question falls outside the scope of the provided data."}
+                {
+                    "role": "system",
+                    "content": "You are a virtual assistant with the ability to create plans for executing tasks using the create_plan_with_skills function if user need you do something. If the user's question falls outside the scope of the provided data.",
+                }
             )
             logger.info(self.short_term_memory.get_chat_dialog())
-        
+
         self.short_term_memory.add_chat_item({"role": "user", "content": input})
         message_text = self.short_term_memory.get_chat_dialog()
 
         custom_functions = [
             {
-                'name': 'create_plan_with_skills',
-                'description': 'run plan and compile code to done the task or requirement',
-                'parameters': {
-                    'type': 'object',
-                    'properties': {
-                        'dialog_summary': {
-                            'type': 'string',
-                            'description': 'summary of the dialog keep that clear about how it works or steps to done the task'
+                "name": "create_plan_with_skills",
+                "description": "run plan and compile code to done the task or requirement",
+                "parameters": {
+                    "type": "object",
+                    "properties": {
+                        "dialog_summary": {
+                            "type": "string",
+                            "description": "summary of the dialog keep that clear about how it works or steps to done the task",
                         }
-                    }
-                }
+                    },
+                },
             },
             {
-                'name': 'create_schedule_for_task_or_plan',
-                'description': 'When a user needs to schedule a recurring task or an event, plan for a future time, they require a system that allows them to do so efficiently. This system should have the capability to set up recurring events if necessary and provide reminders if requested by the user',
-                'parameters': {
-                    'type': 'object',
-                    'properties': {
-                        'dialog_summary': {
-                            'type': 'string',
-                            'description': 'summary of the dialog keep that clear about schedule a recurring task or an event, time, provide reminders if requested by the user'
+                "name": "create_schedule_for_task_or_plan",
+                "description": "When a user needs to schedule a recurring task or an event, plan for a future time, they require a system that allows them to do so efficiently. This system should have the capability to set up recurring events if necessary and provide reminders if requested by the user",
+                "parameters": {
+                    "type": "object",
+                    "properties": {
+                        "dialog_summary": {
+                            "type": "string",
+                            "description": "summary of the dialog keep that clear about schedule a recurring task or an event, time, provide reminders if requested by the user",
                         }
-                    }
-                }
-            }
+                    },
+                },
+            },
         ]
 
         client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
@@ -391,7 +349,7 @@ async def chat(self, input: str) -> str:
             model="gpt-3.5-turbo",
             messages=message_text,
             functions=custom_functions,
-            function_call='auto',
+            function_call="auto",
             temperature=1,
             max_tokens=4096,
             top_p=1,
@@ -404,19 +362,31 @@ async def chat(self, input: str) -> str:
             name = function_call_chat.name
 
             if name == "create_plan_with_skills":
-                logger.info(f"***response.choices[0].message chat: {str(response.choices[0].message)}")
-                json_response = json.loads(response.choices[0].message.function_call.arguments)
-                r_str = await self.create_plan_and_running(goal_plan=json_response.get("dialog_summary"))
+                logger.info(
+                    f"***response.choices[0].message chat: {str(response.choices[0].message)}"
+                )
+                json_response = json.loads(
+                    response.choices[0].message.function_call.arguments
+                )
+                r_str = await self.create_plan_and_running(
+                    goal_plan=json_response.get("dialog_summary")
+                )
             elif name == "create_schedule_for_task_or_plan":
 
                 logger.info("run function create_schedule_for_task_or_plan")
 
-                json_response = json.loads(response.choices[0].message.function_call.arguments)
-                r_str = await self.create_schedule_for_task_or_plan(goal_plan=json_response.get("dialog_summary"))
-        
+                json_response = json.loads(
+                    response.choices[0].message.function_call.arguments
+                )
+                r_str = await self.create_schedule_for_task_or_plan(
+                    goal_plan=json_response.get("dialog_summary")
+                )
+
         response = str(r_str)
-        
-        self.short_term_memory.add_chat_item({"role":"assistant","content":str(response)})
+
+        self.short_term_memory.add_chat_item(
+            {"role": "assistant", "content": str(response)}
+        )
         logger.info(f"Finish chat: {str(response)}")
 
         return str(response)
@@ -424,7 +394,10 @@ async def chat(self, input: str) -> str:
     async def chat_code(self, input: str) -> str:
         if len(self.short_term_memory.get_chat_dialog()) == 0:
             self.short_term_memory.add_chat_item(
-                {"role": "system", "content": "you are a sennior software engineer, expert in python, Every time you generate code, plan, or the way to done task, ask the user if he wants to compile this code"}
+                {
+                    "role": "system",
+                    "content": "you are a sennior software engineer, expert in python, Every time you generate code, plan, or the way to done task, ask the user if he wants to compile this code",
+                }
             )
 
         self.short_term_memory.add_chat_item({"role": "user", "content": input})
@@ -433,58 +406,57 @@ async def chat_code(self, input: str) -> str:
         logger.info(f"Start chat: {message_text}")
         custom_functions = [
             {
-                'name': 'run_plan_and_compile_code',
-                'description': 'run plan and compile code to done the task or requirement',
-                'parameters': {
-                    'type': 'object',
-                    'properties': {
-                        'summary_plan_or_requirement': {
-                            'type': 'string',
-                            'description': 'summary of the plan or requirement keep that clear about how it works or steps to done the task'
+                "name": "run_plan_and_compile_code",
+                "description": "run plan and compile code to done the task or requirement",
+                "parameters": {
+                    "type": "object",
+                    "properties": {
+                        "summary_plan_or_requirement": {
+                            "type": "string",
+                            "description": "summary of the plan or requirement keep that clear about how it works or steps to done the task",
                         }
-                    }
-                }
+                    },
+                },
             }
         ]
 
-        client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-        response = client.chat.completions.create(
-            model="gpt-4-0125-preview",
+        r_str, response = self.brain.language_brain.process(
+            stimulus=Stimulus.CHAT_CODE,
             messages=message_text,
-            functions=custom_functions,
-            function_call='auto',
-            temperature=1,
-            max_tokens=4096,
-            top_p=1,
-            frequency_penalty=0,
-            presence_penalty=0,
+            custom_functions=custom_functions,
         )
-        r_str = str(response.choices[0].message.content)
-        if r_str == "None":
+
+        if str(r_str) == "None":
 
             r_str = "I send requirment to compile code agent. Please wait for a moment."
             function_call_chat = response.choices[0].message.function_call
             name = function_call_chat.name
-            json_response = json.loads(response.choices[0].message.function_call.arguments)
+            json_response = json.loads(
+                response.choices[0].message.function_call.arguments
+            )
             print("---------------------------")
             print(json_response)
 
             if name == "run_plan_and_compile_code":
-                summary_plan_or_requirement = json_response.get("summary_plan_or_requirement")
-                self.codeagent.gen_code(message=summary_plan_or_requirement, is_create_pull_request=True)
-
-        print(response.choices[0].message.function_call)
-        self.short_term_memory.add_chat_item(
-            {"role":"assistant", "content": r_str}
-        )
-        logger.info(f"Finish chat: {str(response)}")
-
+                summary_plan_or_requirement = json_response.get(
+                    "summary_plan_or_requirement"
+                )
+
+                self.brain.language_brain.process(
+                    stimulus=Stimulus.CODING,
+                    git_manager=self.git_manager,
+                    user_data_dir=self.config.get("user_data_dir", None),
+                    summary_plan_or_requirement=summary_plan_or_requirement
+                )
+
+        self.short_term_memory.add_chat_item({"role": "assistant", "content": r_str})
+        logger.info(f"Finish with chat return: {r_str}")
         return r_str
-    
+
     async def clear_short_term_memory(self) -> str:
         self.short_term_memory.clear_chat_dialog()
         return "Clear short term memory successfully."
-    
+
     async def ibelieve(self, input: str) -> bool:
         # maybe that gen by LLM + your input
         try:
@@ -499,9 +471,7 @@ async def askme(self, question: str) -> str:
         # get belief
         logger.debug(f"Start asking: Q: {question}")
 
-        belief = self.memory.brain_area_search(
-            area_collection_name="belief_base", query=question
-        )
+        belief = self.memory.search(collection_name="belief_base", query=question)
 
         belief_ids = belief["ids"][0]
 
@@ -517,20 +487,10 @@ async def askme(self, question: str) -> str:
 
         logger.info(f"Belief_text: \n{belief_text}")
 
-        # answer by belief
-        semantic_function = self.kernel.create_semantic_function(
-            ASK_ABOUT_ME_PROMP, max_tokens=2500, temperature=0.7, top_p=0.8
+        result = self.brain.language_brain.process(
+            stimulus=Stimulus.ASKING, believe=belief_text, question=question
         )
 
-        variables = sk.ContextVariables()
-
-        variables["believe"] = belief_text
-        variables["question"] = question
-
-        result = await self.kernel.run_async(
-            semantic_function,
-            input_vars=variables,
-        )
         logger.debug("Finish asking.")
         return str(result)
 
@@ -542,9 +502,7 @@ async def reincarnate(self) -> str:
 
     async def planning(self, goal: str) -> str:
 
-        belief = self.memory.brain_area_search(
-            area_collection_name="belief_base", query=goal
-        )
+        belief = self.memory.search(collection_name="belief_base", query=goal)
         belief_ids = belief["ids"][0]
         result_list = self.get_beliefs_for_planner(belief_ids)
 
@@ -553,39 +511,27 @@ async def planning(self, goal: str) -> str:
             belief_text += str("-" + item.text + "\n")
 
         # clean belief
-        
-        clean_belief_semantic_function = self.kernel.create_semantic_function(CLEAN_BELIEF_PROMPT)
-        clean_variables = sk.ContextVariables()
-        clean_variables["believe"] = belief_text
-        clean_variables["goal"] = goal
-        clean_result = await self.kernel.run_async(
-            clean_belief_semantic_function,
-            input_vars=clean_variables
+        clean_result = self.brain.language_brain.process(
+            stimulus=Stimulus.CLEAN_BELIEF, believe=belief_text, goal=goal
         )
-        belief_text = clean_result.result.strip()
 
-        relevant_function_manual = self.skills.get_available_function_skills(goal, self.memory)
+        belief_text = clean_result.strip()
 
-        variables = sk.ContextVariables()
-
-        variables["available_functions"] = relevant_function_manual
-        variables["believe"] = belief_text
-        variables["goal"] = goal
+        relevant_function_manual = self.skills.get_available_function_skills(
+            goal, self.memory
+        )
 
         logger.info(f"available_functions {relevant_function_manual}")
 
-        semantic_function = self.kernel.create_semantic_function(PROMPT_PLAN)
-
-        
-
-        result = await self.kernel.run_async(
-            semantic_function,
-            input_vars=variables,
+        result = self.brain.language_brain.process(
+            stimulus=Stimulus.PLANNING,
+            believe=belief_text,
+            goal=goal,
+            available_functions=relevant_function_manual
         )
+        plan_result_string = result.strip()
 
-        plan_result_string = result.result.strip()
-
-        # save to database   
+        # save to database
         plan = Plan(goal=goal, subtask=plan_result_string)
         Plan.session.add(plan)
         Plan.session.commit()
diff --git a/sonagent/cell/__init__.py b/sonagent/cell/__init__.py
new file mode 100644
index 0000000..f01736a
--- /dev/null
+++ b/sonagent/cell/__init__.py
@@ -0,0 +1,1 @@
+from sonagent.cell.cell import BaseCell  # noqa
diff --git a/sonagent/cell/cell.py b/sonagent/cell/cell.py
new file mode 100644
index 0000000..5760014
--- /dev/null
+++ b/sonagent/cell/cell.py
@@ -0,0 +1,19 @@
+import logging
+import threading
+import time
+
+logger = logging.getLogger(__name__)
+
+
+class BaseCell(threading.Thread):
+    def __init__(self, thread_name):
+        super().__init__()
+        self.thread_name = thread_name
+
+    def run(self):
+        print(f"{self.thread_name} start.")
+        # simulate some work
+        for i in range(5):
+            print(f"{self.thread_name}: job {i}")
+            time.sleep(1)
+        print(f"{self.thread_name} done.")
diff --git a/sonagent/coding/__init__.py b/sonagent/coding/__init__.py
deleted file mode 100644
index b0ee6cc..0000000
--- a/sonagent/coding/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from sonagent.coding.gencode import SonCodeAgent
diff --git a/sonagent/commands/__init__.py b/sonagent/commands/__init__.py
index f3c02aa..b591c8e 100644
--- a/sonagent/commands/__init__.py
+++ b/sonagent/commands/__init__.py
@@ -1,3 +1,3 @@
-from sonagent.commands.arguments import Arguments
-from sonagent.commands.run_commands import start_sonagent, create_user_data_dir
-
+from sonagent.commands.arguments import Arguments  # noqa: F401
+from sonagent.commands.run_commands import create_user_data_dir  # noqa: F401
+from sonagent.commands.run_commands import start_sonagent  # noqa: F401
diff --git a/sonagent/commands/arguments.py b/sonagent/commands/arguments.py
index 264deea..b934ee9 100644
--- a/sonagent/commands/arguments.py
+++ b/sonagent/commands/arguments.py
@@ -1,12 +1,10 @@
 import argparse
-from functools import partial
 from pathlib import Path
 from typing import Any, Dict, List, Optional
 
 from sonagent.commands.cli_options import AVAILABLE_CLI_OPTIONS
 from sonagent.constants import DEFAULT_CONFIG
 
-
 ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "agentdb", "memory-url", "user_data_dir"]
 ARGS_BUILD_CONFIG = ["config"]
 ARGS_RUN = ["sd_notify"]
@@ -89,7 +87,7 @@ def _build_subcommands(self) -> None:
         self.parser = argparse.ArgumentParser(description='sonagent')
         self._build_args(optionlist=['version'], parser=self.parser)
 
-        from sonagent.commands import (start_sonagent, create_user_data_dir)
+        from sonagent.commands import create_user_data_dir, start_sonagent
 
         subparsers = self.parser.add_subparsers(dest='command',
                                         # Use custom message when no subhandler is added
diff --git a/sonagent/commands/cli_options.py b/sonagent/commands/cli_options.py
index 1e3e244..fb7463b 100644
--- a/sonagent/commands/cli_options.py
+++ b/sonagent/commands/cli_options.py
@@ -1,6 +1,6 @@
-from argparse import SUPPRESS, ArgumentTypeError
-from sonagent import __version__
-from sonagent import constants
+from argparse import ArgumentTypeError
+
+from sonagent import __version__, constants
 
 
 def check_int_positive(value: str) -> int:
@@ -88,14 +88,4 @@ def __init__(self, *args, **kwargs):
         help='Agent database url.',
         metavar='PATH',
     ),
-    "freqaimodel": Arg(
-        '--freqaimodel',
-        help='Specify a custom freqaimodels.',
-        metavar='NAME',
-    ),
-    "freqaimodel_path": Arg(
-        '--freqaimodel-path',
-        help='Specify additional lookup path for freqaimodels.',
-        metavar='PATH',
-    ),
 }
\ No newline at end of file
diff --git a/sonagent/commands/run_commands.py b/sonagent/commands/run_commands.py
index 473a1b5..9f0d12c 100644
--- a/sonagent/commands/run_commands.py
+++ b/sonagent/commands/run_commands.py
@@ -1,7 +1,8 @@
-import os
 import logging
+import os
 import signal
 from typing import Any, Dict
+
 from sonagent.configuration import load_config_file
 from sonagent.exceptions import OperationalException
 
@@ -47,9 +48,7 @@ def term_handler(signum, frame):
             config = config
             raise OperationalException("Error loading config file: " + str(e))
         # config['user_data_dir'] = args['user_data_dir']
-        print(config)
 
-        print(args)
         config["user_data_dir"] = args["user_data_dir"]
         worker = Worker(args, config=config)
         worker.run()
@@ -73,7 +72,7 @@ def create_user_data_dir(args: Dict[str, Any]) -> None:
     # print("user_data_dir: ", args)
     current_path = str(os.getcwd())
     user_data_dir = args["user_data_dir"]
-    if user_data_dir == None:
+    if user_data_dir is None:
         print(current_path)
         user_data_dir = "user_data"
         if not os.path.exists(current_path + "/" + user_data_dir):
@@ -88,6 +87,7 @@ def create_user_data_dir(args: Dict[str, Any]) -> None:
 
         # create config.json file with string
         config_exampe = """
+
 {
     "initial_state": "running",
     "api_server": {
@@ -110,10 +110,29 @@ def create_user_data_dir(args: Dict[str, Any]) -> None:
         "token": "",
         "chat_id": ""
     },
-    "openai": {
+    "llm": {
         "enabled": true,
         "api_type": "openai",
-        "api_key": ""
+        "api_key": "",
+        "params": {
+            "model": "gpt-3.5-turbo",
+            "temperature": 0.5,
+            "max_tokens": 100,
+            "top_p": 1,
+            "frequency_penalty": 0,
+            "presence_penalty": 0
+        }
+    },
+    "vector_memory": {
+        "type": "file",
+        "path": "memory",
+        "collection": "memory",
+        "host": "localhost",
+        "port": 8000,
+        "embedding":  "openai"
+    },
+    "skills": {
+        "path": "skills/skills.yaml"
     },
     "skills_file_path": "skills/skills.yaml",
     "github": {
@@ -131,6 +150,7 @@ def create_user_data_dir(args: Dict[str, Any]) -> None:
         }
     }
 }
+
         """
         with open(current_path + f"/{user_data_dir}/config.json", "w") as file:
             file.write(config_exampe)
diff --git a/sonagent/configuration/__init__.py b/sonagent/configuration/__init__.py
index 5a7ea87..c92d05f 100644
--- a/sonagent/configuration/__init__.py
+++ b/sonagent/configuration/__init__.py
@@ -1,2 +1,3 @@
-from sonagent.configuration.detect_environment import running_in_docker
-from sonagent.configuration.load_config import load_config_file
+from sonagent.configuration.detect_environment import \
+    running_in_docker  # noqa: F401
+from sonagent.configuration.load_config import load_config_file  # noqa: F401
diff --git a/sonagent/configuration/load_config.py b/sonagent/configuration/load_config.py
index d9b983f..a98a3bf 100644
--- a/sonagent/configuration/load_config.py
+++ b/sonagent/configuration/load_config.py
@@ -1,13 +1,11 @@
-import logging
 import re
 import sys
-from copy import deepcopy
 from pathlib import Path
-from typing import Any, Dict, List, Optional
+from typing import Any, Dict
 
 import rapidjson
-from sonagent.exceptions import OperationalException
 
+from sonagent.exceptions import OperationalException
 
 CONFIG_PARSE_MODE = rapidjson.PM_COMMENTS | rapidjson.PM_TRAILING_COMMAS
 
diff --git a/sonagent/core_prompt/me.py b/sonagent/core_prompt/me.py
deleted file mode 100644
index 54246ef..0000000
--- a/sonagent/core_prompt/me.py
+++ /dev/null
@@ -1,26 +0,0 @@
-ASK_ABOUT_ME_PROMP = """
-This is what I believe is true. Please rely on it to answer the following question.
-answer in the language of the person asking the question
-If belief is not relevant to the question. Please answer "I don't know"
-
-[believe]
-- i like eating apples
-- i think apple is good for health
-
-Q: do you want to drink apple juice?
-A: yes maybe i will try that
-
-
-[believe]
-- i like go shopping with my friends
-- i want to go a big shopping mall
-
-Q: do you want to learn english?
-A: yes i want to learn english
-
-[believe]
-{{$believe}}
-
-Q: {{$question}}
-A:
-"""
diff --git a/sonagent/enums/__init__.py b/sonagent/enums/__init__.py
index baa773d..21d4c66 100644
--- a/sonagent/enums/__init__.py
+++ b/sonagent/enums/__init__.py
@@ -1,1 +1,1 @@
-from sonagent.enums.rpcmessagetype import RPCMessageType
+from sonagent.enums.rpcmessagetype import RPCMessageType  # noqa: F401
diff --git a/sonagent/llm/__init__.py b/sonagent/immune/__init__.py
similarity index 100%
rename from sonagent/llm/__init__.py
rename to sonagent/immune/__init__.py
diff --git a/sonagent/immune/immune.py b/sonagent/immune/immune.py
new file mode 100644
index 0000000..1d93fd3
--- /dev/null
+++ b/sonagent/immune/immune.py
@@ -0,0 +1,81 @@
+import logging
+from datetime import datetime
+from typing import Any, Dict, Optional
+
+from sonagent.cell import BaseCell
+from sonagent.loggers import bufferHandler
+from sonagent.nerve_system.nerve import Nerve
+from sonagent.utils.datetime_helpers import format_date
+
+logger = logging.getLogger(__name__)
+
+
+class ImmuneSystem:
+    """
+    Class for Self Immune System that allows self-monitoring and self-recovery of the system.
+    """
+    error_logs = []
+
+    def __init__(self) -> None:
+        self.nerve = Nerve()
+
+    @staticmethod
+    def get_logs(limit: Optional[int]) -> Dict[str, Any]:
+        """Returns the last X logs"""
+        if limit:
+            buffer = bufferHandler.buffer[-limit:]
+        else:
+            buffer = bufferHandler.buffer
+        records = [[format_date(datetime.fromtimestamp(r.created)),
+                   r.created * 1000, r.name, r.levelname,
+                   r.message + ('\n' + r.exc_text if r.exc_text else '')]
+                   for r in buffer]
+        return {'log_count': len(records), 'logs': records}
+    
+    def immune_scan(self) -> None:
+        """
+        Scan the system for any anomalies.
+        """
+        logs = ImmuneSystem.get_logs(5)
+
+        # Check for any errors in the logs
+        errors = [log for log in logs['logs'] if log[3] == 'ERROR']
+        
+        errors_detected = []
+        for error in errors:
+            if error not in ImmuneSystem.error_logs:
+                ImmuneSystem.error_logs.append(error)
+                errors_detected.append(error)
+
+        if len(errors_detected) > 0:
+            logger.info(f"Errors detected: {errors_detected}")
+            # send alert to Nerve System
+            self.nerve.stimulation(errors_detected)
+            
+        else:
+            logger.debug("No errors detected.")
+
+    def immune_recover(self) -> None:
+        """
+        Recover the system from any anomalies.
+        """
+        if ImmuneSystem.error_logs:
+            print(f"Recovering from errors: {ImmuneSystem.error_logs}")
+            logger.info(f"Recovering from errors: {ImmuneSystem.error_logs}")
+            ImmuneSystem.error_logs = []
+        else:
+            print("No errors detected.")
+            logger.info("No errors detected.")
+
+
+class ImmuneCell(BaseCell):
+    def __init__(self) -> None:
+        super().__init__()
+        self.immune = ImmuneSystem()
+    
+    def scan(self) -> None:
+        self.immune.immune_scan()
+
+    def recover(self) -> None:
+        self.immune.immune_recover()
+
diff --git a/sonagent/immune/killer_t.py b/sonagent/immune/killer_t.py
new file mode 100644
index 0000000..f4e0fbf
--- /dev/null
+++ b/sonagent/immune/killer_t.py
@@ -0,0 +1,36 @@
+import os
+
+import yaml
+
+from sonagent.immune.immune import ImmuneCell
+
+
+class KillerT(ImmuneCell):
+    def __init__(self):
+        super().__init__()
+        self.name = "Killer T cell"
+        self.target = None
+        self.skills_path = os.path.join(os.path.dirname(__file__), "skills.yaml")
+
+    def attack(self, target):
+        self.target = target
+        print(f"{self.name} is attacking {self.target.name}")
+        self.kill()
+
+    def kill(self):
+        
+        with open(self.self.skills_path, 'r') as file:
+            skills_list = yaml.safe_load(file)
+
+        # remove skill target from skills list
+        skills_list.remove(self.target)
+
+        # save again the skills list
+        with open(self.skills_path, 'w') as file:
+            yaml.dump(skills_list, file)
+    
+        if self.target is not None:
+            print(f"{self.name} killed {self.target}")
+            self.target = None
+        else:
+            print(f"{self.name} has no target to kill")
diff --git a/sonagent/llm/oai_llm.py b/sonagent/llm/oai_llm.py
deleted file mode 100644
index 83c10f2..0000000
--- a/sonagent/llm/oai_llm.py
+++ /dev/null
@@ -1,187 +0,0 @@
-import os
-from openai import OpenAI
-from langchain.prompts import PromptTemplate
-import re
-import logging
-from sonagent.llm.prompt import (
-    summary_doc, create_git_pull_request_param, 
-    GITHUB_PULL_REQUEST_PROMPT, rewrite_code_with_docstring
-)
-from sonagent.llm.prompt_auto_docs import (
-    auto_skill_docs
-)
-from sonagent.llm.prompt_create_schedule import (
-    create_schedule_llm
-)
-
-
-logger = logging.getLogger(__name__)
-
-
-def text_summary(docs):
-    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-    sum_prompt = summary_doc(docs)
-    response = client.chat.completions.create(
-        model="gpt-3.5-turbo",
-        messages=[
-            {
-                "role": "system",
-                "content": "play as interactive role, tell user if there is anything else you should take into consideration with the piece of text user trying to learn about. ",
-            },
-            {"role": "user", "content": sum_prompt},
-        ],
-        temperature=1,
-        max_tokens=256,
-        top_p=1,
-        frequency_penalty=0,
-        presence_penalty=0,
-    )
-
-    return response.choices[0].message.content
-
-
-def create_pull_request_info(docs):
-    # prompt = create_git_pull_request_param(docs)
-    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-
-    prompt_temp = PromptTemplate(
-        template=GITHUB_PULL_REQUEST_PROMPT,
-        input_variables=["sumary_text"],
-    )
-    prompt = prompt_temp.format(sumary_text=docs)
-    
-    response = client.chat.completions.create(
-        model="gpt-3.5-turbo",
-        messages=[
-            {
-                "role": "system",
-                "content": "you are a sennior software engineer and you are creating a pull request for the following changes. Your results will be used in another software.",
-            },
-            {"role": "user", "content": prompt},
-        ],
-        temperature=1,
-        max_tokens=1024,
-        top_p=1,
-        frequency_penalty=0,
-        presence_penalty=0,
-    )
-
-    return response.choices[0].message.content
-
-
-def create_chat_with_function(docs):
-    # prompt = create_git_pull_request_param(docs)
-    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-
-    prompt_temp = PromptTemplate(
-        template=GITHUB_PULL_REQUEST_PROMPT,
-        input_variables=["sumary_text"],
-    )
-    prompt = prompt_temp.format(sumary_text=docs)
-    
-    response = client.chat.completions.create(
-        model="gpt-4-turbo-preview",
-        messages=[
-            {
-                "role": "system",
-                "content": "you are a sennior software engineer and you are creating a pull request for the following changes. Your results will be used in another software.",
-            },
-            {"role": "user", "content": prompt},
-        ],
-        temperature=1,
-        max_tokens=1024,
-        top_p=1,
-        frequency_penalty=0,
-        presence_penalty=0,
-    )
-
-    return response.choices[0].message.content
-
-
-def rewrite_python_code_docs_string(code: str):
-    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-
-    prompt = rewrite_code_with_docstring(input_code=code)
-    logger.info(f"Prompt: {prompt}")    
-    
-    response = client.chat.completions.create(
-        model="gpt-3.5-turbo",
-        messages=[
-            {
-                "role": "system",
-                "content": "You are a python expert capable of adding doc strings and comments to user code. Please describe carefully without forgetting the keywords and try to make the description friendly to search engines",
-            },
-            {"role": "user", "content": prompt},
-        ],
-        temperature=1,
-        max_tokens=2048,
-        top_p=1,
-        frequency_penalty=0,
-        presence_penalty=0,
-    )
-    code = str(response.choices[0].message.content)
-    logger.info(f"---------------")
-    logging.info(f"Rewrite Python Code: {code}")
-    logger.info(f"---------------")
-
-    # get ```python ``` block
-    try:
-        # Biểu thức chính quy để tìm đoạn mã Python trong chuỗi
-        pattern = r'```python(.*?)```'
-        # Tìm tất cả các kết quả phù hợp
-        matches = re.findall(pattern, code, re.DOTALL)
-        # Lặp qua các kết quả và in ra màn hình
-        string_a = ""
-        for match in matches:
-            string_a = match.strip()
-        python_code = string_a
-
-    except Exception as e:
-        logger.error(f"--- Error: {e}")
-        python_code = code
-    return python_code
-
-
-def auto_create_skill_docs(skill_code: str):
-    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-
-    system_prompt, user_prompt = auto_skill_docs(skill_code)
-    response = client.chat.completions.create(
-        model="gpt-3.5-turbo",
-        messages=[
-            {
-                "role": "system",
-                "content": system_prompt,
-            },
-            {"role": "user", "content": user_prompt},
-        ],
-        temperature=1,
-        max_tokens=1000,
-        top_p=1,
-        frequency_penalty=0,
-        presence_penalty=0,
-    )
-    return response.choices[0].message.content
-
-
-def auto_create_schedule_json_llm(goal: str):
-    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
-
-    system_prompt, user_prompt = create_schedule_llm(goal)
-    response = client.chat.completions.create(
-        model="gpt-3.5-turbo",
-        messages=[
-            {
-                "role": "system",
-                "content": system_prompt,
-            },
-            {"role": "user", "content": user_prompt},
-        ],
-        temperature=1,
-        max_tokens=1000,
-        top_p=1,
-        frequency_penalty=0,
-        presence_penalty=0,
-    )
-    return response.choices[0].message.content
-
diff --git a/sonagent/llm/prompt_auto_docs.py b/sonagent/llm/prompt_auto_docs.py
deleted file mode 100644
index 4dfa4ff..0000000
--- a/sonagent/llm/prompt_auto_docs.py
+++ /dev/null
@@ -1,71 +0,0 @@
-def auto_skill_docs(code: str) -> str:
-    SYSTEM_PROMP = (
-        "You are a software engineer with the ability to write " +
-        "Python software documentation. "
-        "You receive an INPUT and document that code in OUTPUT."
-    )
-
-    AUTO_DOCS_PROMP = """
-
-        document  INPUT code with document template like example
-        Example 1:
-        
-[INPUT]
-```python
-import sys
-from typing import TYPE_CHECKING, List, Optional
-
-if sys.version_info >= (3, 9):
-    from typing import Annotated
-else:
-    from typing_extensions import Annotated
-
-from semantic_kernel.functions.kernel_function_decorator import kernel_function
-
-if TYPE_CHECKING:
-    from semantic_kernel.connectors.search_engine.connector import ConnectorBase
-
-
-class WebSearchEnginePlugin:
-
-    _connector: "ConnectorBase"
-
-    def __init__(self, connector: "ConnectorBase") -> None:
-        self._connector = connector
-
-    @kernel_function(description="Performs a web search for a given query")
-    async def search(
-        self,
-        query: Annotated[str, "The search query"],
-        num_results: Annotated[Optional[int], "The number of search results to return"] = 1,
-        offset: Annotated[Optional[int], "The number of search results to skip"] = 0,
-    ) -> List[str]:
-        return await self._connector.search(query, num_results, offset)
-```
-[OUTPUT]
-Description: A plugin that provides web search engine functionality
-
-Usage:
-    connector = BingConnector(bing_search_api_key)
-    kernel.import_plugin_from_object(WebSearchEnginePlugin(connector), plugin_name="WebSearch")
-
-Examples:
-    {{WebSearch.search "What is semantic kernel?"}}
-    =>  Returns the first `num_results` number of results for the given search query
-        and ignores the first `offset` number of results.
-
-Method:
-    - `search(query: str, num_results: Optional[int] = 1, offset: Optional[int] = 0) -> List[str]`:
-        Performs a web search for a given query and returns a list of search results.
-
-    - `__init__(connector: ConnectorBase)`:
-        Initializes the plugin with the specified connector.
-
-
-[INTPUT]
-```python
-{code}
-```
-[OUTPUT]
-"""
-    return SYSTEM_PROMP, AUTO_DOCS_PROMP.format(code=code)
diff --git a/sonagent/loggers/__init__.py b/sonagent/loggers/__init__.py
index 1fd96cf..6f74bd7 100644
--- a/sonagent/loggers/__init__.py
+++ b/sonagent/loggers/__init__.py
@@ -4,10 +4,10 @@
 
 from sonagent.exceptions import OperationalException
 from sonagent.loggers.buffering_handler import FTBufferingHandler
+from sonagent.loggers.logging_mixin import LoggingMixin  # noqa: F401
 from sonagent.loggers.set_log_levels import set_loggers
 from sonagent.loggers.std_err_stream_handler import FTStdErrStreamHandler
 
-
 logger = logging.getLogger(__name__)
 LOGFORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
 
diff --git a/sonagent/mixins/logging_mixin.py b/sonagent/loggers/logging_mixin.py
similarity index 100%
rename from sonagent/mixins/logging_mixin.py
rename to sonagent/loggers/logging_mixin.py
diff --git a/sonagent/loggers/set_log_levels.py b/sonagent/loggers/set_log_levels.py
index c7981b8..73cee17 100644
--- a/sonagent/loggers/set_log_levels.py
+++ b/sonagent/loggers/set_log_levels.py
@@ -1,7 +1,6 @@
 
 import logging
 
-
 logger = logging.getLogger(__name__)
 
 
diff --git a/sonagent/main.py b/sonagent/main.py
index dee81c0..4bec425 100644
--- a/sonagent/main.py
+++ b/sonagent/main.py
@@ -2,18 +2,15 @@
 import sys
 from typing import Any, List, Optional
 
-
 # check min. python version
 if sys.version_info < (3, 9):  # pragma: no cover
     sys.exit("SonAgent requires Python version >= 3.9")
 
 from sonagent import __version__
-
-from sonagent.exceptions import SonAgentException, OperationalException
-from sonagent.utils.gc_setup import gc_set_threshold
 from sonagent.commands import Arguments
+from sonagent.exceptions import OperationalException, SonAgentException
 from sonagent.loggers import setup_logging_pre
-
+from sonagent.utils.gc_setup import gc_set_threshold
 
 logger = logging.getLogger('sonagent')
 
diff --git a/sonagent/memory/memory.py b/sonagent/memory/memory.py
deleted file mode 100644
index 2820773..0000000
--- a/sonagent/memory/memory.py
+++ /dev/null
@@ -1,107 +0,0 @@
-import os
-import chromadb
-from chromadb.config import Settings
-import logging
-
-logger = logging.getLogger(__name__)
-class SonMemory:
-
-    def __init__(self, collection_name="son_memory", memory_init_mode="file", default_memory_path=None):
-        self.memory_type = None
-        self.chroma_client = None
-        self.memory_collection = None
-
-        if memory_init_mode == "file":
-            self.chroma_client = chromadb.PersistentClient(
-                path=default_memory_path,
-                settings=Settings(allow_reset=True)
-            )
-        elif memory_init_mode == "server":
-            self.chroma_client = chromadb.HttpClient(
-                host='localhost',
-                port=8000
-            )
-        else:
-            self.chroma_client = chromadb.Client()
-
-        
-        if self.chroma_client != None:
-            self.memory_collection = self.chroma_client.get_or_create_collection(name=collection_name)
-        else:
-            self.memory_collection = None
-
-
-    def set_memory_collection(self, collection_name=None):
-        if self.chroma_client != None:
-            self.memory_collection = self.chroma_client.get_collection(name=collection_name)
-        else:
-            self.memory_collection = None
-
-    def delete_memory_collection(self, collection_name=None):
-        if self.chroma_client != None:
-            self.chroma_client.delete_collection(name=collection_name)
-            return True
-        return False
-
-    def search(self, query, n_results=10):
-        results = self.memory_collection.query(
-            query_texts=[query],
-            n_results=n_results
-        )
-        return results
-    
-    def brain_area_search(self, query, area_collection_name, n_results=10):
-        area_collection = self.chroma_client.get_or_create_collection(
-            name=area_collection_name
-        )
-
-        logger.debug(f"Searching in brain area {area_collection_name} with query {query}")
-        
-        results = area_collection.query(
-            query_texts=[query],
-            n_results=n_results
-        )
-        logger.debug(f"results {results}")
-
-        return results
-    
-
-    def add(self, document: str="", metadata: dict={}, id: str="", area_collection_name=None):
-        try:
-            if area_collection_name is not None:
-                area_collection = self.chroma_client.get_or_create_collection(
-                    name=area_collection_name
-                )
-                area_collection.add(
-                    documents=[document],
-                    metadatas=[metadata],
-                    ids=[id]
-                )
-                return True
-            else:
-                self.memory_collection.add(
-                    documents=[document],
-                    metadatas=[metadata],
-                    ids=[id]
-                )
-                return True
-        except Exception as e:
-            print(e)
-            return False
-
-        
-    def search_with_embedding(self, embedding):
-        pass
-
-    def save(self):
-        pass
-    
-    def clear_all(self):
-        self.chroma_client.reset()
-
-    def load(self):
-        pass
-
-    def reset_memory(self):
-        self.chroma_client.reset()
-
diff --git a/sonagent/mixins/__init__.py b/sonagent/mixins/__init__.py
deleted file mode 100644
index 39581c3..0000000
--- a/sonagent/mixins/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from sonagent.mixins.logging_mixin import LoggingMixin  # noqa: F401
diff --git a/sonagent/nerve_system/__init__.py b/sonagent/nerve_system/__init__.py
new file mode 100644
index 0000000..c9857a6
--- /dev/null
+++ b/sonagent/nerve_system/__init__.py
@@ -0,0 +1,3 @@
+from sonagent.nerve_system.brain import Brain  # noqa: F401
+from sonagent.nerve_system.language_area.llm_brain import \
+    LLMBrain  # noqa: F401
diff --git a/sonagent/nerve_system/brain.py b/sonagent/nerve_system/brain.py
new file mode 100644
index 0000000..286f436
--- /dev/null
+++ b/sonagent/nerve_system/brain.py
@@ -0,0 +1,16 @@
+from sonagent.nerve_system.brain_lobe import BrainLobe
+from sonagent.nerve_system.language_area.gpt import GPTLlmBrain
+
+
+class Brain:
+    def __init__(self, brain_config={}, llm_config={}, **kwargs):
+
+        self.language_brain: BrainLobe = None
+        if llm_config.get("api_type", None) == "openai":
+            self.language_brain = GPTLlmBrain()
+
+        self.visual_brain = None
+        self.auditory_brain = None
+        self.movement_brain = None
+
+        self.thalamus = None
diff --git a/sonagent/nerve_system/brain_lobe.py b/sonagent/nerve_system/brain_lobe.py
new file mode 100644
index 0000000..2ccbe5c
--- /dev/null
+++ b/sonagent/nerve_system/brain_lobe.py
@@ -0,0 +1,22 @@
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class BrainLobe:
+    shm_nerve = {}
+
+    def __init__(self):
+        logger.info("Initializing Brain...")
+
+    def process(self, stimulus):
+        logger.info(f"Processing stimulus: {stimulus}")
+        return stimulus
+    
+    def stimulation(self, stimulus):
+        logger.info(f"Stimulating with stimulus: {stimulus}")
+        return stimulus
+    
+    def start(self):
+        logger.info("Brain started.")
+
diff --git a/sonagent/memory/__init__.py b/sonagent/nerve_system/consciousness/thinking.py
similarity index 100%
rename from sonagent/memory/__init__.py
rename to sonagent/nerve_system/consciousness/thinking.py
diff --git a/sonagent/nerve_system/language_area/__init__.py b/sonagent/nerve_system/language_area/__init__.py
new file mode 100644
index 0000000..0f36dbe
--- /dev/null
+++ b/sonagent/nerve_system/language_area/__init__.py
@@ -0,0 +1,1 @@
+from sonagent.nerve_system.language_area.gpt import GPTLlmBrain  # noqa: F401
diff --git a/sonagent/memory/long_memory.py b/sonagent/nerve_system/language_area/claude.py
similarity index 100%
rename from sonagent/memory/long_memory.py
rename to sonagent/nerve_system/language_area/claude.py
diff --git a/sonagent/nerve_system/language_area/coding/__init__.py b/sonagent/nerve_system/language_area/coding/__init__.py
new file mode 100644
index 0000000..ca6e126
--- /dev/null
+++ b/sonagent/nerve_system/language_area/coding/__init__.py
@@ -0,0 +1,2 @@
+from sonagent.nerve_system.language_area.coding.gencode import \
+    SonCodeAgent  # noqa: F401
diff --git a/sonagent/coding/gencode.py b/sonagent/nerve_system/language_area/coding/gencode.py
similarity index 84%
rename from sonagent/coding/gencode.py
rename to sonagent/nerve_system/language_area/coding/gencode.py
index dc856e5..3738c92 100644
--- a/sonagent/coding/gencode.py
+++ b/sonagent/nerve_system/language_area/coding/gencode.py
@@ -1,25 +1,27 @@
-import os
-import autogen
-from typing import Dict, Union
-from sonagent.coding.sonautogen import SonAutoGenAgent
-from typing import Any
-from sonagent.llm.oai_llm import create_pull_request_info, rewrite_python_code_docs_string, auto_create_skill_docs
-from sonagent.llm.prompt import DEFAULT_SYSTEM_MESSAGE_AUTO_GEN
-from sonagent.persistence.models import SkillDocs
 import json
 import logging
-from pathlib import Path
-import yaml
+import os
+from typing import Any, Dict, Union
 
-# llm_config = {
-#     "config_list": [{"model": "gpt-4-0125-preview", "api_key": os.environ["OPENAI_API_KEY"]}],
-# }
+import autogen
+import yaml
 
-# config_list = [{"model": "gpt-4-0125-preview", "api_key": os.environ["OPENAI_API_KEY"]}]
+import sonagent.nerve_system.language_area.prompt.coding as coding_prompt
+from sonagent.nerve_system.language_area.coding.sonautogen import \
+    SonAutoGenAgent
+from sonagent.nerve_system.language_area.coding.utils import \
+    rewrite_code_post_process
+from sonagent.nerve_system.stimulus import Stimulus
+from sonagent.persistence.models import SkillDocs
 
 
 class SonCodeAgent:
-    def __init__(self, git_manager: Any = None, user_data_dir: str = '/user_data') -> None:
+    def __init__(
+            self, git_manager: Any = None, 
+            user_data_dir: str = '/user_data', 
+            llmbrain: Any = None
+    ) -> None:
+        self.llmbrain = llmbrain
         self.user_data_dir = user_data_dir
         self.config_item = {"model": "gpt-4-0125-preview", "api_key": os.environ["OPENAI_API_KEY"]}
         self.llm_config = {
@@ -30,11 +32,10 @@ def __init__(self, git_manager: Any = None, user_data_dir: str = '/user_data') -
         self.config_list = [self.config_item]
         self.git_manager = git_manager
         
-
         # create an AssistantAgent named "assistant"
         self.assistant = autogen.AssistantAgent(
             name="assistant",
-            system_message=DEFAULT_SYSTEM_MESSAGE_AUTO_GEN,
+            system_message=coding_prompt.DEFAULT_SYSTEM_MESSAGE_AUTO_GEN,
             llm_config={
                 "cache_seed": 41,  # seed for caching and reproducibility
                 "config_list": self.config_list,  # a list of OpenAI API configurations
@@ -80,16 +81,18 @@ def gen_code(self, message: str, is_create_pull_request: bool = False) -> Union[
         self.latest_code = self.user_proxy.latest_code
         skill_name = ""
 
-        if self.latest_code == None:
+        if self.latest_code is None:
             logging.error("No code generated")
         else:
-            self.latest_code = rewrite_python_code_docs_string(
-                self.latest_code
-            )
-        
+            output_code = self.llmbrain.process(
+                Stimulus.REWRITE_CODE, code=self.latest_code)
+            self.latest_code = rewrite_code_post_process(output_code)
+
         metadata = {}
         pull_str = str(chat_res.summary) + "-- final code --" + str(self.latest_code)
-        metadata_str = create_pull_request_info(pull_str)
+        metadata_str = self.llmbrain.process(
+                Stimulus.WRITE_GITHUB_METADATA, summary_text=pull_str)
+        
         logging.info(f"metadata_str: {metadata_str}")
         
         # Removing the triple backticks and 'json' label
@@ -136,7 +139,7 @@ def gen_code(self, message: str, is_create_pull_request: bool = False) -> Union[
 
                 # write skill register to skill file
                 skill_class = metadata.get("class_name", None)
-                if skill_class != None and skill_class in str(chat_res.summary):
+                if skill_class is not None and skill_class in str(chat_res.summary):
                     skill_file_path = f"{self.git_manager.local_repo_path}/user_data/skills/skills.yaml"
                     self.add_skill_register_to_agent(skill_class, skill_file_path)
                 skill_name = skill_class
@@ -160,26 +163,23 @@ def gen_code(self, message: str, is_create_pull_request: bool = False) -> Union[
 
             # write skill register to skill file
             skill_class = metadata.get("class_name", None)
-            if skill_class != None and skill_class in str(pull_str):
+            if skill_class is not None and skill_class in str(pull_str):
                 skill_file_path = f"{self.git_manager.local_repo_path}/skills/skills.yaml"
                 self.add_skill_register_to_agent(skill_class, skill_file_path)
             skill_name = skill_class
-        if self.latest_code != None and skill_name != "":
+        if self.latest_code is not None and skill_name != "":
             self.create_and_save_code_docs(skill_name, self.latest_code)
 
         return chat_res, metadata
     
     def save_source_code(self, code: str, code_path) -> None:
-        # save code to user_data folder clone from github
-
-        # save file to user data skill folder
-
-        # open pull request to github
         pass
     
     def create_and_save_code_docs(self, skill_name: str, code: str) -> None:
         try:
-            docs = auto_create_skill_docs(code)
+            docs = self.llmbrain.process(
+                Stimulus.CREATE_SKILL_DOCS, code=code
+            )
             logging.info(f"Docs: {docs}")
             # save docs to models
             plan = SkillDocs(skill_name=skill_name, docs=docs)
diff --git a/sonagent/coding/sonautogen.py b/sonagent/nerve_system/language_area/coding/sonautogen.py
similarity index 91%
rename from sonagent/coding/sonautogen.py
rename to sonagent/nerve_system/language_area/coding/sonautogen.py
index 86d1d89..3071e85 100644
--- a/sonagent/coding/sonautogen.py
+++ b/sonagent/nerve_system/language_area/coding/sonautogen.py
@@ -1,17 +1,9 @@
-import autogen
 from typing import Callable, Dict, List, Literal, Optional, Union
-from autogen import ConversableAgent
 
-from autogen.runtime_logging import logging_enabled, log_new_agent
-from autogen.code_utils import (
-    UNKNOWN,
-    content_str,
-    check_can_use_docker_or_throw,
-    decide_use_docker,
-    execute_code,
-    extract_code,
-    infer_lang,
-)
+import autogen
+from autogen.code_utils import execute_code
+from autogen.runtime_logging import log_new_agent, logging_enabled
+
 
 class SonAutoGenAgent(autogen.ConversableAgent):
     DEFAULT_USER_PROXY_AGENT_DESCRIPTIONS = {
diff --git a/sonagent/nerve_system/language_area/coding/utils.py b/sonagent/nerve_system/language_area/coding/utils.py
new file mode 100644
index 0000000..04df5ef
--- /dev/null
+++ b/sonagent/nerve_system/language_area/coding/utils.py
@@ -0,0 +1,25 @@
+import logging
+import re
+
+logger = logging.getLogger(__name__)
+
+
+def rewrite_code_post_process(response_content):
+    code = str(response_content)
+    logger.info("---------------")
+    logging.info(f"Rewrite Python Code: {code}")
+    logger.info("---------------")
+
+    # get ```python ``` block
+    try:
+        pattern = r'```python(.*?)```'
+        matches = re.findall(pattern, code, re.DOTALL)
+        string_a = ""
+        for match in matches:
+            string_a = match.strip()
+        python_code = string_a
+
+    except Exception as e:
+        logger.error(f"--- Error: {e}")
+        python_code = code
+    return python_code
diff --git a/sonagent/planning/__init__.py b/sonagent/nerve_system/language_area/gemini.py
similarity index 100%
rename from sonagent/planning/__init__.py
rename to sonagent/nerve_system/language_area/gemini.py
diff --git a/sonagent/nerve_system/language_area/gpt.py b/sonagent/nerve_system/language_area/gpt.py
new file mode 100644
index 0000000..c0d25a9
--- /dev/null
+++ b/sonagent/nerve_system/language_area/gpt.py
@@ -0,0 +1,91 @@
+import logging
+import os
+
+from openai import OpenAI
+
+from sonagent.nerve_system.language_area.llm_brain import LLMBrain
+
+logger = logging.getLogger(__name__)
+
+
+class GPTLlmBrain(LLMBrain):
+    def __init__(self):
+        super().__init__()
+
+    def infer(
+        self, prompt=None,
+        system_prompt=None, model="gpt-3.5-turbo", custom_functions=None
+    ):
+        logger.info(f"Infer LLM with prompt: {prompt}")
+        if system_prompt:
+            messages = [
+                {
+                    "role": "system",
+                    "content": system_prompt,
+                },
+                {"role": "user", "content": prompt},
+            ]
+        else:
+            messages = [{"role": "user", "content": prompt}]
+
+        client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
+
+        if custom_functions:
+            response = client.chat.completions.create(
+                model=model,
+                messages=messages,
+                functions=custom_functions,
+                function_call="auto",
+                temperature=1,
+                max_tokens=2048,
+                top_p=1,
+                frequency_penalty=0,
+                presence_penalty=0,
+            )
+            return response.choices[0].message.content, response
+        else:
+            response = client.chat.completions.create(
+                model=model,
+                messages=messages,
+                temperature=1,
+                max_tokens=2048,
+                top_p=1,
+                frequency_penalty=0,
+                presence_penalty=0,
+            )
+
+        return response.choices[0].message.content
+
+    def chat_infer(
+        self, messages,
+        model="gpt-3.5-turbo",
+        custom_functions=None
+    ):
+        logger.info(f"Infer LLM with messages: {messages}")
+        client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
+
+        if custom_functions:
+            response = client.chat.completions.create(
+                model=model,
+                messages=messages,
+                functions=custom_functions,
+                function_call="auto",
+                temperature=1,
+                max_tokens=2048,
+                top_p=1,
+                frequency_penalty=0,
+                presence_penalty=0,
+            )
+            return response.choices[0].message.content, response
+        else:
+            response = client.chat.completions.create(
+                model=model,
+                messages=messages,
+                temperature=1,
+                max_tokens=2048,
+                top_p=1,
+                frequency_penalty=0,
+                presence_penalty=0,
+            )
+            return response.choices[0].message.content
+
diff --git a/sonagent/skills/learning_skills/__init__.py b/sonagent/nerve_system/language_area/llama.py
similarity index 100%
rename from sonagent/skills/learning_skills/__init__.py
rename to sonagent/nerve_system/language_area/llama.py
diff --git a/sonagent/nerve_system/language_area/llm_brain.py b/sonagent/nerve_system/language_area/llm_brain.py
new file mode 100644
index 0000000..8324c6b
--- /dev/null
+++ b/sonagent/nerve_system/language_area/llm_brain.py
@@ -0,0 +1,100 @@
+from abc import abstractmethod
+
+import sonagent.nerve_system.language_area.prompt.coding as coding_prompts
+import sonagent.nerve_system.language_area.prompt.me as me_prompt
+import sonagent.nerve_system.language_area.prompt.planning as planning_prompt
+import sonagent.nerve_system.language_area.prompt.schedule as schedule_prompt
+from sonagent.nerve_system.brain_lobe import BrainLobe
+from sonagent.nerve_system.language_area.coding import SonCodeAgent
+from sonagent.nerve_system.stimulus import Stimulus
+
+
+class LLMBrain(BrainLobe):
+    def __init__(self):
+        super().__init__()
+
+    @abstractmethod
+    def infer(
+        self, prompt, system_prompt=None, model="gpt-3.5-turbo", custom_functions=None
+    ):
+        raise NotImplementedError
+
+    @abstractmethod
+    def chat_infer(self, messages, model="gpt-3.5-turbo", custom_functions=None):
+        raise NotImplementedError
+
+    def process(self, stimulus, **kwargs):
+        if stimulus == Stimulus.ASKING:
+            # get prompt from kwargs
+            prompt = me_prompt.ASK_ABOUT_ME_PROMPT.format(
+                believe=kwargs.get("believe", ""),
+                question=kwargs.get("question", ""),
+            )
+            result = self.infer(prompt)
+        elif stimulus == Stimulus.SCHEDULING:
+            prompt = schedule_prompt.AUTO_SCHEDULE_PROMPT.format(
+                goal=kwargs.get("goal", ""),
+            )
+            system_prompt = schedule_prompt.SYSTEM_PROMPT
+            result = self.infer(prompt, system_prompt)
+        elif stimulus == Stimulus.PLANNING:
+            prompt = planning_prompt.PROMPT_PLAN.format(
+                believe=kwargs.get("believe", ""),
+                goal=kwargs.get("goal", ""),
+                available_functions=kwargs.get("available_functions", ""),
+            )
+            result = self.infer(prompt)
+        elif stimulus == Stimulus.CLEAN_BELIEF:
+            prompt = planning_prompt.CLEAN_BELIEF_PROMPT.format(
+                goal=kwargs.get("goal", ""),
+                believe=kwargs.get("believe", ""),
+            )
+            result = self.infer(prompt)
+        elif stimulus == Stimulus.CODING:
+            git_manager = kwargs.get("git_manager")
+            user_data_dir = kwargs.get("user_data_dir")
+            summary_plan_or_requirement = kwargs.get("summary_plan_or_requirement")
+
+            codeagent = SonCodeAgent(
+                git_manager=git_manager, user_data_dir=user_data_dir, llmbrain=self
+            )
+
+            codeagent.gen_code(
+                message=summary_plan_or_requirement, is_create_pull_request=True
+            )
+
+            result = "Code generated by LLMBrain"
+        elif stimulus == Stimulus.REWRITE_CODE:
+            code = kwargs.get("code")
+            prompt = coding_prompts.REWRITE_CODE_ADD_DOCSTRING_TO_CLASS.format(
+                code=code
+            )
+            sys_prompt = coding_prompts.REWIRTE_CODE_ADD_DOCS_SYSTEM_PROMPT
+            result = self.infer(prompt, sys_prompt)     
+        elif stimulus == Stimulus.CREATE_SKILL_DOCS:
+            code = kwargs.get("code")
+            prompt = coding_prompts.AUTO_SKILL_DOCS_PROMPT.format(code=code)
+            sys_prompt = coding_prompts.AUTO_SKILL_DOCS_SYSTEM_PROMPT
+            result = self.infer(prompt, sys_prompt)
+        elif stimulus == Stimulus.WRITE_GITHUB_METADATA:
+            summary_text = kwargs.get("summary_text")
+            prompt = coding_prompts.GITHUB_PULL_REQUEST_PROMPT.format(
+                summary_text=summary_text
+            )
+            sys_prompt = coding_prompts.GITHUB_PULL_REQUEST_SYSTEM_PROMPT
+            result = self.infer(prompt, sys_prompt)
+        elif stimulus == Stimulus.CHAT_CODE:
+            messages = kwargs.get("messages")
+            result = self.chat_infer(
+                messages, custom_functions=kwargs.get("custom_functions")
+            )
+        elif stimulus == Stimulus.SUMMARIZING:
+            pass
+
+        return result
+
+    def planning(self, stimulus):
+        return stimulus + " planned by LLMBrain"
+
+    def summarize(self, stimulus):
+        return stimulus + " summarized by LLMBrain"
diff --git a/sonagent/nerve_system/language_area/planning/planner.py b/sonagent/nerve_system/language_area/planning/planner.py
new file mode 100644
index 0000000..9929e5e
--- /dev/null
+++ b/sonagent/nerve_system/language_area/planning/planner.py
@@ -0,0 +1,16 @@
+# planning module 
+from semantic_kernel.kernel import Kernel
+from semantic_kernel.planning.basic_planner import BasicPlanner, Plan
+
+import sonagent.nerve_system.language_area.prompt.planning as planning_prompt
+
+
+class SonAgentPlanner(BasicPlanner):
+
+    def create_plan_async(
+        self,
+        goal: str,
+        kernel: Kernel,
+        prompt: str = planning_prompt.PROMPT,
+    ) -> Plan:
+        return super().create_plan_async(goal, kernel, prompt)
diff --git a/sonagent/nerve_system/language_area/prompt/__init__.py b/sonagent/nerve_system/language_area/prompt/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sonagent/llm/prompt.py b/sonagent/nerve_system/language_area/prompt/coding.py
similarity index 72%
rename from sonagent/llm/prompt.py
rename to sonagent/nerve_system/language_area/prompt/coding.py
index 868d085..52a72e0 100644
--- a/sonagent/llm/prompt.py
+++ b/sonagent/nerve_system/language_area/prompt/coding.py
@@ -1,164 +1,29 @@
+DEFAULT_SYSTEM_MESSAGE_AUTO_GEN = """You are a helpful AI assistant.
+Solve tasks using your coding and language skills.
+In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.
+    1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.
+    2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.
+Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.
+When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.
+If you want the user to save the code in a file before executing it, put # filename: <filename> inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.
+If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.
+When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible.
+Reply "TERMINATE" in the end when everything is done.
 
-#to do: move this one to langchain 
-
-
-def summary_doc(text: str) -> str:
-    SUMMARY_DOC = f"""
-    You are an expert software engineer with expertise in summarizing and pulling out important sections of a text. 
-    The following text is from discussions and is about Software Development. 
-    Follow these steps: read the text, summarize the text, and identify key issues can be planned for implementation. 
-    In your response include the summary and bullet points for the main ideas, steps, and key vocabulary.
-    ### Text
-    {text}
-    """
-    return SUMMARY_DOC
-
-
-def create_git_pull_request_param(sumary_text):
-
-    GITHUB_PULL_REQUEST = f"""
-    You are a software engineer working on a python project.
-    You have been asked to create a pull request for the following changes.
-    The changes are to the codebase of a project. 
-    Based on the content provided below. Let's create a json file, ouput is json.
-
-    For example:
-
-    Example 1:
-    ### SUMMARY
-    SonAgent (to assistant):
-    create a python class that have function to plot apple stock price in from 1 year ago to now user yahoo finance data 
-    that class need extend from 
-    ```python
-    from pydantic import BaseModel
-    ```
-    --------------------------------------------------------------------------------
-    assistant (to SonAgent):
-
-    To accomplish this task, we will create a Python class that extends from `BaseModel` provided by `pydantic`. This class will have a function to plot the Apple stock price from 1 year ago to the current date using Yahoo Finance data. We will use the `yfinance` library to fetch the stock data and `matplotlib` for plotting. If you don't have `yfinance` and `matplotlib` installed, you will need to install them using pip.
-
-    Here's the plan:
-    1. Import necessary libraries.
-    2. Extend the class from `BaseModel`.
-    3. Implement a function within the class to fetch and plot the Apple stock price data.
-
-    First, ensure you have `pydantic`, `yfinance`, and `matplotlib` installed. You can install them using pip. Execute the following command in your shell:
-
-    ### OUTPUT
-    {
-        "branch_name": "feature/sonagent-plot-apple-stock",
-        "commit_message": "add new feature to plot apple stock price",
-        "pull_request_title": "Add new skill to agent to plot Apple stock price",
-        "pull_request_body": "This pull request adds a new skill to the agent to plot the Apple stock price using Yahoo Finance data.",
-        "source_code_file_name": "skill_plot_apple_stock.py",
-    }
-
-    Example 2:
-    ### SUMMARY
-    Certainly! The following is a summary of the Python function for performing a Google search using the googlesearch-python library:
-    Install the googlesearch-python library using pip install googlesearch-python.
-    Create a function called google_search that takes a search query and an optional parameter for the number of results to fetch.
-    Inside the function, use the search function from the library to perform the Google search with the given query and retrieve the specified number of results.
-    Iterate through the search results and print the title and URL of each result.
-    Handle exceptions gracefully in case of errors during the search process.
-    Remember to use this functionality responsibly and be aware of potential legal and ethical considerations when interacting with external APIs or web services.
-
-    ### OUTPUT
-    {
-        "branch_name": "feature/sonagent-google-search",
-        "commit_message": "add new feature to perform Google search",
-        "pull_request_title": "Add new skill to agent to perform Google search",
-        "pull_request_body": "This pull request adds a new skill to the agent to perform a Google search using the googlesearch-python library.",
-        "source_code_file_name": "skill_google_search.py",
-    }
-
-
-    ### SUMMARY
-    {sumary_text}
-
-    ### OUTPUT
-
-    """
-
-    return GITHUB_PULL_REQUEST
-
-
-
-GITHUB_PULL_REQUEST_PROMPT = """
-You are a software engineer working on a python project.
-You have been asked to create a pull request for the following changes.
-The changes are to the codebase of a project. 
-Based on the content provided below. Let's create a json file, ouput is json that format can load by json.loads.
-
-For example:
-
-Example 1:
-[SUMMARY]
-SonAgent (to assistant):
-create a python class that have function to plot apple stock price in from 1 year ago to now user yahoo finance data 
-that class need extend from 
-```python
-from pydantic import BaseModel
-```
---------------------------------------------------------------------------------
-assistant (to SonAgent):
-
-To accomplish this task, we will create a Python class `PlotAppleStock` that extends from `BaseModel` provided by `pydantic`. 
-This class will have a function to plot the Apple stock price from 1 year ago to the current date using Yahoo Finance data. 
-We will use the `yfinance` library to fetch the stock data and `matplotlib` for plotting. 
-If you don't have `yfinance` and `matplotlib` installed, you will need to install them using pip.
-
-Here's the plan:
-1. Import necessary libraries.
-2. Extend the class from `BaseModel`.
-3. Implement a function within the class to fetch and plot the Apple stock price data.
-
-First, ensure you have `pydantic`, `yfinance`, and `matplotlib` installed. You can install them using pip. Execute the following command in your shell:
-
-[OUTPUT]
-```json
-{{
-    "branch_name": "feature/sonagent-plot-apple-stock",
-    "commit_message": "add new feature to plot apple stock price",
-    "pull_request_title": "Add new skill to agent to plot Apple stock price",
-    "pull_request_body": "This pull request adds a new skill to the agent to plot the Apple stock price using Yahoo Finance data.",
-    "source_code_file_name": "skill_plot_apple_stock.py",
-    "class_name": "PlotAppleStock"
-}}
-```
-
-Example 2:
-[SUMMARY]
-Certainly! The following is a summary of the Python function for performing a Google search using the googlesearch-python library:
-Install the googlesearch-python library using pip install googlesearch-python.
-Create a class called `GooleSearch` have a function called google_search that takes a search query and an optional parameter for the number of results to fetch.
-Inside the function, use the search function from the library to perform the Google search with the given query and retrieve the specified number of results.
-Iterate through the search results and print the title and URL of each result.
-Handle exceptions gracefully in case of errors during the search process.
-Remember to use this functionality responsibly and be aware of potential legal and ethical considerations when interacting with external APIs or web services.
-
-[OUTPUT]
-```json
-{{
-    "branch_name": "feature/sonagent-google-search",
-    "commit_message": "add new feature to perform Google search",
-    "pull_request_title": "Add new skill to agent to perform Google search",
-    "pull_request_body": "This pull request adds a new skill to the agent to perform a Google search using the googlesearch-python library.",
-    "source_code_file_name": "skill_google_search.py",
-    "class_name": "GooleSearch"
-}}
-```
-
-[SUMMARY]
-{sumary_text}
-
-[OUTPUT]
-
+follow coding conventions and best practices bellow:
+- Classes must have docstrings, keep docs string of class and function what you get
+- If the function call to execute the code is not placed within the if name == "main": block, please move the code execution into the if name == "main": block. This is because this code block is intended for use when importing into other modules
+- Please note that the syntax for the class docs string should follow the format as follows: ClassName.function_name after that followed by a description of the function's parameters in the args section
+- if source code not have class, you need to create a class and move the function into the class that class need to extend from `BaseModel` provided by `pydantic`
+- function inside a class need self as first argument
+- keep import statement at the top of the file dont remove import becauset that will make code wrong
+- For IO operations when required to print or notify the user, use the following method instead of the print function `from sonagent.rpc import IOMsg` IOMsg.send_msg(text) with text is str type message you want to send, or print 
+- For Input operations when required to get input from the user, use the following method instead of the input function `from sonagent.rpc import IOMsg` IOMsg.get_input() and store the result in a variable, dont use input function
 """
 
+REWIRTE_CODE_ADD_DOCS_SYSTEM_PROMPT = "You are a python expert capable of adding doc strings and comments to user code. Please describe carefully without forgetting the keywords and try to make the description friendly to search engines"
 
-def rewrite_code_with_docstring(input_code: str) -> str:
-    ADD_DOCSTRING_TO_CLASS = f'''
+REWRITE_CODE_ADD_DOCSTRING_TO_CLASS = '''
 You are a software engineer working on a Python project. You need to add  or rewrite docs string to Python classes following the following rules:
 - Classes must have docstrings listing all the parameters of a function, as shown in the example
 - If the function call to execute the code is not placed within the if name == "main": block, please move the code execution into the if name == "main": block. This is because this code block is intended for use when importing into other modules
@@ -284,32 +149,152 @@ def plot_stock(self, plot_days=30):
 ```
 [INPUT]
 ```python
-{input_code}
+{code}
 ```
 [OUTPUT]
 
-    '''
+'''
 
-    return ADD_DOCSTRING_TO_CLASS
+GITHUB_PULL_REQUEST_SYSTEM_PROMPT = "you are a sennior software engineer and you are creating a pull request for the following changes. Your results will be used in another software."
+GITHUB_PULL_REQUEST_PROMPT = """
+You are a software engineer working on a python project.
+You have been asked to create a pull request for the following changes.
+The changes are to the codebase of a project. 
+Based on the content provided below. Let's create a json file, ouput is json that format can load by json.loads.
 
+For example:
 
-DEFAULT_SYSTEM_MESSAGE_AUTO_GEN = """You are a helpful AI assistant.
-Solve tasks using your coding and language skills.
-In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.
-    1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.
-    2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.
-Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.
-When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.
-If you want the user to save the code in a file before executing it, put # filename: <filename> inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.
-If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.
-When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible.
-Reply "TERMINATE" in the end when everything is done.
+Example 1:
+[SUMMARY]
+SonAgent (to assistant):
+create a python class that have function to plot apple stock price in from 1 year ago to now user yahoo finance data 
+that class need extend from 
+```python
+from pydantic import BaseModel
+```
+--------------------------------------------------------------------------------
+assistant (to SonAgent):
 
-follow coding conventions and best practices bellow:
-- Classes must have docstrings, keep docs string of class and function what you get
-- If the function call to execute the code is not placed within the if name == "main": block, please move the code execution into the if name == "main": block. This is because this code block is intended for use when importing into other modules
-- Please note that the syntax for the class docs string should follow the format as follows: ClassName.function_name after that followed by a description of the function's parameters in the args section
-- if source code not have class, you need to create a class and move the function into the class that class need to extend from `BaseModel` provided by `pydantic`
-- function inside a class need self as first argument
-- keep import statement at the top of the file dont remove import becauset that will make code wrong
-    """
\ No newline at end of file
+To accomplish this task, we will create a Python class `PlotAppleStock` that extends from `BaseModel` provided by `pydantic`. 
+This class will have a function to plot the Apple stock price from 1 year ago to the current date using Yahoo Finance data. 
+We will use the `yfinance` library to fetch the stock data and `matplotlib` for plotting. 
+If you don't have `yfinance` and `matplotlib` installed, you will need to install them using pip.
+
+Here's the plan:
+1. Import necessary libraries.
+2. Extend the class from `BaseModel`.
+3. Implement a function within the class to fetch and plot the Apple stock price data.
+
+First, ensure you have `pydantic`, `yfinance`, and `matplotlib` installed. You can install them using pip. Execute the following command in your shell:
+
+[OUTPUT]
+```json
+{{
+    "branch_name": "feature/sonagent-plot-apple-stock",
+    "commit_message": "add new feature to plot apple stock price",
+    "pull_request_title": "Add new skill to agent to plot Apple stock price",
+    "pull_request_body": "This pull request adds a new skill to the agent to plot the Apple stock price using Yahoo Finance data.",
+    "source_code_file_name": "skill_plot_apple_stock.py",
+    "class_name": "PlotAppleStock"
+}}
+```
+
+Example 2:
+[SUMMARY]
+Certainly! The following is a summary of the Python function for performing a Google search using the googlesearch-python library:
+Install the googlesearch-python library using pip install googlesearch-python.
+Create a class called `GooleSearch` have a function called google_search that takes a search query and an optional parameter for the number of results to fetch.
+Inside the function, use the search function from the library to perform the Google search with the given query and retrieve the specified number of results.
+Iterate through the search results and print the title and URL of each result.
+Handle exceptions gracefully in case of errors during the search process.
+Remember to use this functionality responsibly and be aware of potential legal and ethical considerations when interacting with external APIs or web services.
+
+[OUTPUT]
+```json
+{{
+    "branch_name": "feature/sonagent-google-search",
+    "commit_message": "add new feature to perform Google search",
+    "pull_request_title": "Add new skill to agent to perform Google search",
+    "pull_request_body": "This pull request adds a new skill to the agent to perform a Google search using the googlesearch-python library.",
+    "source_code_file_name": "skill_google_search.py",
+    "class_name": "GooleSearch"
+}}
+```
+
+[SUMMARY]
+{summary_text}
+
+[OUTPUT]
+
+"""
+
+
+AUTO_SKILL_DOCS_SYSTEM_PROMPT = (
+    "You are a software engineer with the ability to write " +
+    "Python software documentation. "
+    "You receive an INPUT and document that code in OUTPUT."
+)
+
+AUTO_SKILL_DOCS_PROMPT = """
+
+document  INPUT code with document template like example
+Example 1:
+        
+[INPUT]
+```python
+import sys
+from typing import TYPE_CHECKING, List, Optional
+
+if sys.version_info >= (3, 9):
+    from typing import Annotated
+else:
+    from typing_extensions import Annotated
+
+from semantic_kernel.functions.kernel_function_decorator import kernel_function
+
+if TYPE_CHECKING:
+    from semantic_kernel.connectors.search_engine.connector import ConnectorBase
+
+
+class WebSearchEnginePlugin:
+
+    _connector: "ConnectorBase"
+
+    def __init__(self, connector: "ConnectorBase") -> None:
+        self._connector = connector
+
+    @kernel_function(description="Performs a web search for a given query")
+    async def search(
+        self,
+        query: Annotated[str, "The search query"],
+        num_results: Annotated[Optional[int], "The number of search results to return"] = 1,
+        offset: Annotated[Optional[int], "The number of search results to skip"] = 0,
+    ) -> List[str]:
+        return await self._connector.search(query, num_results, offset)
+```
+[OUTPUT]
+Description: A plugin that provides web search engine functionality
+
+Usage:
+    connector = BingConnector(bing_search_api_key)
+    kernel.import_plugin_from_object(WebSearchEnginePlugin(connector), plugin_name="WebSearch")
+
+Examples:
+    {{WebSearch.search "What is semantic kernel?"}}
+    =>  Returns the first `num_results` number of results for the given search query
+        and ignores the first `offset` number of results.
+
+Method:
+    - `search(query: str, num_results: Optional[int] = 1, offset: Optional[int] = 0) -> List[str]`:
+        Performs a web search for a given query and returns a list of search results.
+
+    - `__init__(connector: ConnectorBase)`:
+        Initializes the plugin with the specified connector.
+
+
+[INTPUT]
+```python
+{code}
+```
+[OUTPUT]
+"""
diff --git a/sonagent/nerve_system/language_area/prompt/me.py b/sonagent/nerve_system/language_area/prompt/me.py
new file mode 100644
index 0000000..90a0643
--- /dev/null
+++ b/sonagent/nerve_system/language_area/prompt/me.py
@@ -0,0 +1,13 @@
+ASK_ABOUT_ME_PROMPT = """
+You are a person with knowledge and believe provided in [believe]. 
+[believe] is always the truth. [believe] is used for inferences and thoughts. 
+Please rely on it to answer the following question.
+answer in the language of the person asking the question
+If belief is not relevant to the question. Please answer "I don't know"
+
+[believe]
+{believe}
+
+Q: {question}
+A:
+"""
diff --git a/sonagent/nerve_system/language_area/prompt/planning.py b/sonagent/nerve_system/language_area/prompt/planning.py
new file mode 100644
index 0000000..b0551ff
--- /dev/null
+++ b/sonagent/nerve_system/language_area/prompt/planning.py
@@ -0,0 +1,233 @@
+
+PROMPT = """
+You are a planner for the Semantic Kernel.
+Your job is to create a properly formatted JSON plan step by step, to satisfy the goal given.
+Create a list of subtasks based off the [GOAL] provided.
+Each subtask must be from within the [AVAILABLE FUNCTIONS] list. Do not use any functions that are not in the list.
+Base your decisions on which functions to use from the description and the name of the function.
+Sometimes, a function may take arguments. Provide them if necessary.
+The plan should be as short as possible.
+For example:
+
+[AVAILABLE FUNCTIONS]
+EmailConnector.LookupContactEmail
+description: looks up the a contact and retrieves their email address
+args:
+- name: the name to look up
+
+WriterSkill.EmailTo
+description: email the input text to a recipient
+args:
+- input: the text to email
+- recipient: the recipient's email address. Multiple addresses may be included if separated by ';'.
+
+WriterSkill.Translate
+description: translate the input to another language
+args:
+- input: the text to translate
+- language: the language to translate to
+
+WriterSkill.Summarize
+description: summarize input text
+args:
+- input: the text to summarize
+
+FunSkill.Joke
+description: Generate a funny joke
+args:
+- input: the input to generate a joke about
+
+[GOAL]
+"Tell a joke about cars. Translate it to Spanish"
+
+[OUTPUT]
+    {
+        "input": "cars",
+        "subtasks": [
+            {"function": "FunSkill.Joke"},
+            {"function": "WriterSkill.Translate", "args": {"language": "Spanish"}}
+        ]
+    }
+
+[AVAILABLE FUNCTIONS]
+WriterSkill.Brainstorm
+description: Brainstorm ideas
+args:
+- input: the input to brainstorm about
+
+EdgarAllenPoeSkill.Poe
+description: Write in the style of author Edgar Allen Poe
+args:
+- input: the input to write about
+
+WriterSkill.EmailTo
+description: Write an email to a recipient
+args:
+- input: the input to write about
+- recipient: the recipient's email address.
+
+WriterSkill.Translate
+description: translate the input to another language
+args:
+- input: the text to translate
+- language: the language to translate to
+
+[GOAL]
+"Tomorrow is Valentine's day. I need to come up with a few date ideas.
+She likes Edgar Allen Poe so write using his style.
+E-mail these ideas to my significant other. Translate it to French."
+
+[OUTPUT]
+    {
+        "input": "Valentine's Day Date Ideas",
+        "subtasks": [
+            {"function": "WriterSkill.Brainstorm"},
+            {"function": "EdgarAllenPoeSkill.Poe"},
+            {"function": "WriterSkill.EmailTo", "args": {"recipient": "significant_other"}},
+            {"function": "WriterSkill.Translate", "args": {"language": "French"}}
+        ]
+    }
+
+[AVAILABLE FUNCTIONS]
+{{$available_functions}}
+
+[GOAL]
+{{$goal}}
+
+[OUTPUT]
+"""
+
+
+PROMPT_PLAN = """
+You are a planner for the Agent.
+Your job is to create a properly formatted JSON plan step by step, to satisfy the goal given with 
+the things you believe to be the best..
+Create a list of subtasks based off the [GOAL] provided.
+Each subtask must be from within the [AVAILABLE FUNCTIONS] list. Do not use any functions that are not in the list.
+Base your decisions on which functions to use from the description and the name of the function.
+Sometimes, a function may take arguments. Provide them if necessary.
+The plan should be as short as possible. If you dont have available functions to satisfy the goal, Please name that function with the prefix `unknow_[function_name]`.
+
+For example:
+
+[AVAILABLE FUNCTIONS]
+EmailConnector.LookupContactEmail
+description: looks up the a contact and retrieves their email address
+args:
+- name: the name to look up
+
+WriterSkill.EmailTo
+description: email the input text to a recipient
+args:
+- input: the text to email
+- recipient: the recipient's email address. Multiple addresses may be included if separated by ';'.
+
+WriterSkill.Translate
+description: translate the input to another language
+args:
+- input: the text to translate
+- language: the language to translate to
+
+WriterSkill.Summarize
+description: summarize input text
+args:
+- input: the text to summarize
+
+FunSkill.Joke
+description: Generate a funny joke
+args:
+- input: the input to generate a joke about
+
+[GOAL]
+"Tell a joke about cars at 9h am everyday. Translate it to Spanish"
+
+[BELIEVE]
+- cars can be used to transport people
+- cars can be used to fly around the world
+- cars can be used to go to the moon
+
+[OUTPUT]
+    {{
+        "input": "cars",
+        "subtasks": [
+            {{"function": "FunSkill.Joke", "description": "Generate a funny joke about cars"}},
+            {{"function": "WriterSkill.Translate", "args": {{"language": "Spanish"}}, "description": "Translate the joke to Spanish"}}
+        ]
+    }}
+
+[AVAILABLE FUNCTIONS]
+WriterSkill.Brainstorm
+description: Brainstorm ideas
+args:
+- input: the input to brainstorm about
+
+EdgarAllenPoeSkill.Poe
+description: Write in the style of author Edgar Allen Poe
+args:
+- input: the input to write about
+
+WriterSkill.EmailTo
+description: Write an email to a recipient
+args:
+- input: the input to write about
+- recipient: the recipient's email address.
+
+[GOAL]
+"Tomorrow is Valentine's day. I need to come up with a few date ideas.
+She likes Edgar Allen Poe so write using his style.
+E-mail these ideas to my significant other. Translate it to French."
+
+[OUTPUT]
+    {{
+        "input": "Valentine's Day Date Ideas",
+        "subtasks": [
+            {{"function": "WriterSkill.Brainstorm", "description": "Brainstorm ideas for Valentine's Day"}},
+            {{"function": "EdgarAllenPoeSkill.Poe", "description": "Write in the style of Edgar Allen Poe"}},
+            {{"function": "WriterSkill.EmailTo", "args": {{"recipient": "significant_other"}}, "description": "Email the ideas to my significant other"}},
+            {{"function": "unknow_WriterSkill.Translate", "args": {{"language": "French"}}, description: "Translate the ideas to French"}}
+        ]
+    }}
+
+
+[AVAILABLE FUNCTIONS]
+{available_functions}
+
+[GOAL]
+{goal}
+
+[BELIEVE]
+{believe}
+
+[OUTPUT]
+"""
+
+
+CLEAN_BELIEF_PROMPT = """
+List the beliefs related to achieving your goals and eliminate the remaining beliefs
+[BELIEVE]
+- Earth orbits the sun
+- The sun is a star
+- The sun is a ball of fire
+- The sun is a source of light
+- The sun is a source of energy
+- A tree is a plant
+
+[GOAL]
+- Calculate the orbits of the planets
+
+[OUTPUT]
+- Earth orbits the sun
+- The sun is a star
+- The sun is a ball of fire
+- The sun is a source of light
+- The sun is a source of energy
+
+
+[BELIEVE]
+{believe}
+[GOAL]
+{goal}
+
+[OUTPUT]
+
+"""
diff --git a/sonagent/llm/prompt_create_schedule.py b/sonagent/nerve_system/language_area/prompt/schedule.py
similarity index 83%
rename from sonagent/llm/prompt_create_schedule.py
rename to sonagent/nerve_system/language_area/prompt/schedule.py
index 58d99e3..bc5173f 100644
--- a/sonagent/llm/prompt_create_schedule.py
+++ b/sonagent/nerve_system/language_area/prompt/schedule.py
@@ -1,11 +1,10 @@
-def create_schedule_llm(goal: str) -> str:
-    SYSTEM_PROMP = (
-        "You are an assistant with scheduling abilities and the ability "
-        "to perform recurring tasks based on user goals. Please create a"
-        "schedule from the following goal."
-    )
+SYSTEM_PROMPT = (
+    "You are an assistant with scheduling abilities and the ability "
+    "to perform recurring tasks based on user goals. Please create a"
+    "schedule from the following goal."
+)
 
-    AUTO_SCHEDULE_PROMPT = f"""
+AUTO_SCHEDULE_PROMPT = """
     You are a reliable assistant, please help the user schedule with their goal, and the output is a single JSON in json block format.
     If time is not given, set it as 00:00:00 keep datetime format is "YYYY-MM-DD HH:MM:SS".
     if dont have schedule_start_at or schedule_end_at set them as empty string.
@@ -59,4 +58,3 @@ def create_schedule_llm(goal: str) -> str:
     [OUTPUT]
 
 """
-    return SYSTEM_PROMP, AUTO_SCHEDULE_PROMPT
diff --git a/sonagent/nerve_system/language_area/prompt/summary.py b/sonagent/nerve_system/language_area/prompt/summary.py
new file mode 100644
index 0000000..8fb01f0
--- /dev/null
+++ b/sonagent/nerve_system/language_area/prompt/summary.py
@@ -0,0 +1,8 @@
+SUMMARY_DOC = """
+You are an expert software engineer with expertise in summarizing and pulling out important sections of a text. 
+The following text is from discussions and is about Software Development. 
+Follow these steps: read the text, summarize the text, and identify key issues can be planned for implementation. 
+In your response include the summary and bullet points for the main ideas, steps, and key vocabulary.
+### Text
+{text}
+"""
diff --git a/sonagent/nerve_system/language_area/utils.py b/sonagent/nerve_system/language_area/utils.py
new file mode 100644
index 0000000..04df5ef
--- /dev/null
+++ b/sonagent/nerve_system/language_area/utils.py
@@ -0,0 +1,25 @@
+import logging
+import re
+
+logger = logging.getLogger(__name__)
+
+
+def rewrite_code_post_process(response_content):
+    code = str(response_content)
+    logger.info("---------------")
+    logging.info(f"Rewrite Python Code: {code}")
+    logger.info("---------------")
+
+    # get ```python ``` block
+    try:
+        pattern = r'```python(.*?)```'
+        matches = re.findall(pattern, code, re.DOTALL)
+        string_a = ""
+        for match in matches:
+            string_a = match.strip()
+        python_code = string_a
+
+    except Exception as e:
+        logger.error(f"--- Error: {e}")
+        python_code = code
+    return python_code
diff --git a/sonagent/nerve_system/memory_area/__init__.py b/sonagent/nerve_system/memory_area/__init__.py
new file mode 100644
index 0000000..2ab4c6a
--- /dev/null
+++ b/sonagent/nerve_system/memory_area/__init__.py
@@ -0,0 +1,3 @@
+from sonagent.nerve_system.memory_area.memory import SonMemory  # noqa: F401
+from sonagent.nerve_system.memory_area.short_memory import \
+    ShortTermMemory  # noqa: F401
diff --git a/sonagent/nerve_system/memory_area/memory.py b/sonagent/nerve_system/memory_area/memory.py
new file mode 100644
index 0000000..3b66fab
--- /dev/null
+++ b/sonagent/nerve_system/memory_area/memory.py
@@ -0,0 +1,88 @@
+import logging
+
+from sonagent.nerve_system.brain_lobe import BrainLobe
+from sonagent.tools import ChromaDB, Embedding, OAIEmbedding, VectorDB
+
+logger = logging.getLogger(__name__)
+
+
+class SonMemory(BrainLobe):
+
+    def __init__(
+        self,
+        collection_name="son_memory",
+        memory_type="file",
+        embedding_type="openai",
+        default_memory_path=None,
+        **kwargs
+    ):
+        self.memory_type = None
+        self.vtdb: VectorDB = None
+        self.embed: Embedding = None
+
+        self.chroma_client = None
+        self.memory_collection = collection_name
+
+        # setup vector database
+        if memory_type == "file":
+            self.vtdb = VectorDB(db_path=default_memory_path)
+        
+        elif memory_type == "chromadb":
+            host = kwargs.get("host", "localhost")
+            port = kwargs.get("port", 8000)
+            self.vtdb = ChromaDB(host=host, port=port)
+            
+        elif memory_type == "qdrand":
+            # TODO: Implement QDRand memory
+            pass
+
+        # setup embedding
+        if embedding_type == "openai":
+            self.embed = OAIEmbedding()
+
+    def delete_memory_collection(self, collection_name=None):
+        if self.vtdb is not None:
+            self.vtdb.delete_collection(collection_name)
+            return True
+        return False
+
+    def search(self, query, n_results=10, collection_name=None):
+        if collection_name is None:
+            collection_name = self.memory_collection
+        
+        logger.debug(
+            f"Searching in brain area {collection_name} with query {query}"
+        )
+
+        embedding = self.embed.embed(query)
+        results = self.vtdb.query(
+            embedding=embedding, k=n_results, collection=collection_name
+        )
+        return results
+
+    def add(
+        self,
+        document: str = "",
+        metadata: dict = {},
+        id: str = "",
+        collection_name=None,
+    ):
+        if collection_name is None:
+            collection_name = self.memory_collection
+
+        try:
+            self.vtdb.add(
+                embeddings=[self.embed.embed(document)],
+                docs=[document], metadatas=[metadata], ids=[id],
+                collection=collection_name
+            )
+            return True
+        except Exception as e:
+            print(e)
+            return False
+
+    def clear_all(self):
+        self.vtdb.reset()
+
+    def reset_memory(self):
+        self.vtdb.reset()
diff --git a/sonagent/memory/short_memory.py b/sonagent/nerve_system/memory_area/short_memory.py
similarity index 72%
rename from sonagent/memory/short_memory.py
rename to sonagent/nerve_system/memory_area/short_memory.py
index 4386400..55540ec 100644
--- a/sonagent/memory/short_memory.py
+++ b/sonagent/nerve_system/memory_area/short_memory.py
@@ -1,17 +1,16 @@
 
-from sonagent.memory.memory import SonMemory
-from sonagent.llm.oai_llm import text_summary
+from sonagent.nerve_system.memory_area import SonMemory
+
 
 class ShortTermMemory(SonMemory):
 
     def __init__(self, collection_name="short_term_memory", memory_init_mode="file", default_memory_path=None):
-        super().__init__(collection_name=collection_name, memory_init_mode=memory_init_mode, default_memory_path=default_memory_path)
-
         self.chat_dialog = []
         self.summerize_dialog_str = None
 
     def summerize_dialog(self):
-        sum_text = text_summary(self.get_chat_dialog_as_string())
+        sum_text = ""
+        # sum_text = text_summary(self.get_chat_dialog_as_string())
         return sum_text
     
     def add_chat_item(self, item: dict={}):
diff --git a/sonagent/nerve_system/nerve.py b/sonagent/nerve_system/nerve.py
new file mode 100644
index 0000000..3cbbf96
--- /dev/null
+++ b/sonagent/nerve_system/nerve.py
@@ -0,0 +1,6 @@
+from sonagent.nerve_system.brain_lobe import BrainLobe
+
+
+class Nerve:
+    def stimulation(self, stimulus):
+        BrainLobe.shm_nerve['stimulus'] = stimulus
diff --git a/sonagent/nerve_system/stimulus.py b/sonagent/nerve_system/stimulus.py
new file mode 100644
index 0000000..67d2663
--- /dev/null
+++ b/sonagent/nerve_system/stimulus.py
@@ -0,0 +1,21 @@
+from enum import Enum
+
+
+class Stimulus(Enum):
+
+    PLANNING = 'planning'
+    CODING = 'coding'
+    CHAT_CODE = 'chat_code'
+    REWRITE_CODE = 'rewrite_code'
+    CREATE_SKILL_DOCS = 'create_skill_docs'
+    WRITE_DOCS = 'write_docs'
+    WRITE_GITHUB_METADATA = 'write_github_metadata'
+    CHATTING = 'chatting'
+    ASKING = 'asking'
+    SCHEDULING = 'scheduling'
+    SUMMARIZING = 'summarizing'
+    CLEAN_BELIEF = 'clean_belief'
+    HEARTBEAT = 'heartbeat'
+
+    def __str__(self):
+        return f"{self.name.lower()}"
diff --git a/sonagent/nerve_system/thalamus.py b/sonagent/nerve_system/thalamus.py
new file mode 100644
index 0000000..e69de29
diff --git a/sonagent/persistence/__init__.py b/sonagent/persistence/__init__.py
index 37c2bc9..f982856 100644
--- a/sonagent/persistence/__init__.py
+++ b/sonagent/persistence/__init__.py
@@ -1,5 +1,6 @@
-from sonagent.persistence.models import init_db
-from sonagent.persistence.belief_models import Belief
-from sonagent.persistence.planning_models import Plan
-from sonagent.persistence.skill_models import SkillDocs
-from sonagent.persistence.schedule_models import ScheduleJob
+from sonagent.persistence.belief_models import Belief  # noqa: F401
+from sonagent.persistence.environment_models import Environment  # noqa: F401
+from sonagent.persistence.models import init_db  # noqa: F401
+from sonagent.persistence.planning_models import Plan  # noqa: F401
+from sonagent.persistence.schedule_models import ScheduleJob  # noqa: F401
+from sonagent.persistence.skill_models import SkillDocs  # noqa: F401
diff --git a/sonagent/persistence/base.py b/sonagent/persistence/base.py
index fc2dac7..81200d2 100644
--- a/sonagent/persistence/base.py
+++ b/sonagent/persistence/base.py
@@ -1,7 +1,6 @@
 
 from sqlalchemy.orm import DeclarativeBase, Session, scoped_session
 
-
 SessionType = scoped_session[Session]
 
 
diff --git a/sonagent/persistence/belief_models.py b/sonagent/persistence/belief_models.py
index 2cf30ff..fe86a0b 100644
--- a/sonagent/persistence/belief_models.py
+++ b/sonagent/persistence/belief_models.py
@@ -1,23 +1,12 @@
 import logging
+from datetime import datetime
+from typing import ClassVar, List, Optional
+
+from sqlalchemy import Integer, String, select
+from sqlalchemy.orm import Mapped, mapped_column
+
 from sonagent.persistence.base import ModelBase, SessionType
 from sonagent.utils.datetime_helpers import dt_now
-from typing import Any, ClassVar, Dict, List, Optional, Sequence, cast
-
-from sqlalchemy import (
-    Enum,
-    Float,
-    ForeignKey,
-    Integer,
-    ScalarResult,
-    Select,
-    String,
-    UniqueConstraint,
-    desc,
-    func,
-    select,
-)
-from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates
-from datetime import datetime, timedelta, timezone
 
 logger = logging.getLogger(__name__)
 
diff --git a/sonagent/persistence/environment_models.py b/sonagent/persistence/environment_models.py
new file mode 100644
index 0000000..9c30990
--- /dev/null
+++ b/sonagent/persistence/environment_models.py
@@ -0,0 +1,32 @@
+import logging
+from datetime import datetime
+from typing import ClassVar, List, Optional
+
+from sqlalchemy import Integer, String, select
+from sqlalchemy.orm import Mapped, mapped_column
+
+from sonagent.persistence.base import ModelBase, SessionType
+from sonagent.utils.datetime_helpers import dt_now
+
+logger = logging.getLogger(__name__)
+
+
+class Environment(ModelBase):
+    __tablename__ = "environment"
+    __allow_unmapped__ = True
+    session: ClassVar[SessionType]
+
+    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
+    key: Mapped[str] = mapped_column(String(255), nullable=False)
+    value: Mapped[str] = mapped_column(String(8192), nullable=False)
+    description: Mapped[str] = mapped_column(String(2048), nullable=True)
+
+    created_at: Mapped[datetime] = mapped_column(nullable=True, default=dt_now)
+    updated_at: Mapped[datetime] = mapped_column(
+        nullable=False, default=dt_now, onupdate=dt_now
+    )
+
+    @staticmethod
+    def get_all_environment(*, created_at: Optional[datetime] = None) -> List["Environment"]:
+        return Environment.session.scalars(
+            select(Environment).filter()).all()
diff --git a/sonagent/persistence/migrations.py b/sonagent/persistence/migrations.py
index 814c513..e2bae9f 100644
--- a/sonagent/persistence/migrations.py
+++ b/sonagent/persistence/migrations.py
@@ -1,12 +1,6 @@
 import logging
-from typing import List, Optional
 
-from sqlalchemy import inspect, select, text, tuple_, update
-
-from sonagent.persistence.belief_models import Belief
-from sonagent.persistence.planning_models import Plan
-from sonagent.persistence.skill_models import SkillDocs
-from sonagent.persistence.schedule_models import ScheduleJob
+from sqlalchemy import inspect
 
 logger = logging.getLogger(__name__)
 
@@ -14,7 +8,7 @@ def check_migrate(engine, decl_base, previous_tables) -> None:
     """
     Checks if migration is necessary and migrates if necessary
     """
-    inspector = inspect(engine)
+    inspect(engine)
     migrating = False
 
     if migrating:
diff --git a/sonagent/persistence/models.py b/sonagent/persistence/models.py
index 2f11ce7..3b03312 100644
--- a/sonagent/persistence/models.py
+++ b/sonagent/persistence/models.py
@@ -1,21 +1,20 @@
 import logging
-
-from typing import Any, Dict, Final, Optional
+from typing import Any, Dict
 
 from sqlalchemy import create_engine, inspect
-from sqlalchemy.exc import NoSuchModuleError
 from sqlalchemy.orm import scoped_session, sessionmaker
 from sqlalchemy.pool import StaticPool
 
 from sonagent.exceptions import OperationalException
 from sonagent.persistence.base import ModelBase
-from sonagent.persistence.migrations import check_migrate
 from sonagent.persistence.belief_models import Belief
+from sonagent.persistence.environment_models import Environment
+from sonagent.persistence.migrations import check_migrate
 from sonagent.persistence.planning_models import Plan
-from sonagent.persistence.skill_models import SkillDocs
 from sonagent.persistence.schedule_models import ScheduleJob
+from sonagent.persistence.skill_models import SkillDocs
 
-
+logger = logging.getLogger(__name__)
 
 _SQL_DOCS_URL = 'http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls'
 
@@ -58,13 +57,15 @@ def init_db(db_url: str) -> None:
 
     ScheduleJob.session = scoped_session(sessionmaker(bind=engine, autoflush=False))
     ScheduleJob.query = ScheduleJob.session.query_property()
+
+    Environment.session = scoped_session(sessionmaker(bind=engine, autoflush=False))
+    Environment.query = Environment.session.query_property()
     
     try:
         previous_tables = inspect(engine).get_table_names()
     except Exception as e:
-        print("okii")
+        logger.error(f"Error inspecting tables: {e}")
     
     ModelBase.metadata.create_all(engine)
 
-    print("run here")
     check_migrate(engine, decl_base=ModelBase, previous_tables=previous_tables)
diff --git a/sonagent/persistence/planning_models.py b/sonagent/persistence/planning_models.py
index 1f98085..4ef0a3b 100644
--- a/sonagent/persistence/planning_models.py
+++ b/sonagent/persistence/planning_models.py
@@ -1,23 +1,11 @@
 import logging
-from sonagent.persistence.base import ModelBase, SessionType
-from typing import Any, ClassVar, Dict, List, Optional, Sequence, cast
-from sonagent.utils.datetime_helpers import dt_now
+from typing import ClassVar, List, Optional
 
-from sqlalchemy import (
-    Enum,
-    Float,
-    ForeignKey,
-    Integer,
-    ScalarResult,
-    Select,
-    String,
-    UniqueConstraint,
-    desc,
-    func,
-    select,
-)
-from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates
+from sqlalchemy import Integer, String, select
+from sqlalchemy.orm import Mapped, mapped_column
 
+from sonagent.persistence.base import ModelBase, SessionType
+from sonagent.utils.datetime_helpers import dt_now
 
 logger = logging.getLogger(__name__)
 
diff --git a/sonagent/persistence/schedule_models.py b/sonagent/persistence/schedule_models.py
index a2cf659..094a1f6 100644
--- a/sonagent/persistence/schedule_models.py
+++ b/sonagent/persistence/schedule_models.py
@@ -1,24 +1,12 @@
 import logging
-from sonagent.persistence.base import ModelBase, SessionType
-from typing import Any, ClassVar, Dict, List, Optional, Sequence, cast
-from sonagent.utils.datetime_helpers import dt_now
+from datetime import datetime, timedelta
+from typing import ClassVar, List, Optional
 
-from sqlalchemy import (
-    Enum,
-    Float,
-    ForeignKey,
-    Integer,
-    ScalarResult,
-    Select,
-    String,
-    UniqueConstraint,
-    desc,
-    func,
-    select,
-)
-from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates
-from datetime import datetime, timedelta, timezone
+from sqlalchemy import Enum, Integer, String, desc, select
+from sqlalchemy.orm import Mapped, mapped_column, validates
 
+from sonagent.persistence.base import ModelBase, SessionType
+from sonagent.utils.datetime_helpers import dt_now
 
 logger = logging.getLogger(__name__)
 
diff --git a/sonagent/persistence/skill_models.py b/sonagent/persistence/skill_models.py
index a56bc91..8e84ec6 100644
--- a/sonagent/persistence/skill_models.py
+++ b/sonagent/persistence/skill_models.py
@@ -1,23 +1,11 @@
 import logging
-from sonagent.persistence.base import ModelBase, SessionType
-from typing import Any, ClassVar, Dict, List, Optional, Sequence, cast
-from sonagent.utils.datetime_helpers import dt_now
+from typing import ClassVar, List, Optional
 
-from sqlalchemy import (
-    Enum,
-    Float,
-    ForeignKey,
-    Integer,
-    ScalarResult,
-    Select,
-    String,
-    UniqueConstraint,
-    desc,
-    func,
-    select,
-)
-from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates
+from sqlalchemy import Integer, String, select
+from sqlalchemy.orm import Mapped, mapped_column
 
+from sonagent.persistence.base import ModelBase, SessionType
+from sonagent.utils.datetime_helpers import dt_now
 
 logger = logging.getLogger(__name__)
 
diff --git a/sonagent/planning/planner.py b/sonagent/planning/planner.py
deleted file mode 100644
index b8f803b..0000000
--- a/sonagent/planning/planner.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# planning module 
-from semantic_kernel.kernel import Kernel
-from semantic_kernel.planning.basic_planner import Plan, BasicPlanner
-from semantic_kernel.planning.sequential_planner import SequentialPlanner
-from semantic_kernel.planning.sequential_planner.sequential_planner_config import SequentialPlannerConfig
-from sonagent.planning.prompt import SEQUENCE_PLAN
-
-
-PROMPT = """
-You are a planner for the Semantic Kernel.
-Your job is to create a properly formatted JSON plan step by step, to satisfy the goal given.
-Create a list of subtasks based off the [GOAL] provided.
-Each subtask must be from within the [AVAILABLE FUNCTIONS] list. Do not use any functions that are not in the list.
-Base your decisions on which functions to use from the description and the name of the function.
-Sometimes, a function may take arguments. Provide them if necessary.
-The plan should be as short as possible.
-For example:
-
-[AVAILABLE FUNCTIONS]
-EmailConnector.LookupContactEmail
-description: looks up the a contact and retrieves their email address
-args:
-- name: the name to look up
-
-WriterSkill.EmailTo
-description: email the input text to a recipient
-args:
-- input: the text to email
-- recipient: the recipient's email address. Multiple addresses may be included if separated by ';'.
-
-WriterSkill.Translate
-description: translate the input to another language
-args:
-- input: the text to translate
-- language: the language to translate to
-
-WriterSkill.Summarize
-description: summarize input text
-args:
-- input: the text to summarize
-
-FunSkill.Joke
-description: Generate a funny joke
-args:
-- input: the input to generate a joke about
-
-[GOAL]
-"Tell a joke about cars. Translate it to Spanish"
-
-[OUTPUT]
-    {
-        "input": "cars",
-        "subtasks": [
-            {"function": "FunSkill.Joke"},
-            {"function": "WriterSkill.Translate", "args": {"language": "Spanish"}}
-        ]
-    }
-
-[AVAILABLE FUNCTIONS]
-WriterSkill.Brainstorm
-description: Brainstorm ideas
-args:
-- input: the input to brainstorm about
-
-EdgarAllenPoeSkill.Poe
-description: Write in the style of author Edgar Allen Poe
-args:
-- input: the input to write about
-
-WriterSkill.EmailTo
-description: Write an email to a recipient
-args:
-- input: the input to write about
-- recipient: the recipient's email address.
-
-WriterSkill.Translate
-description: translate the input to another language
-args:
-- input: the text to translate
-- language: the language to translate to
-
-[GOAL]
-"Tomorrow is Valentine's day. I need to come up with a few date ideas.
-She likes Edgar Allen Poe so write using his style.
-E-mail these ideas to my significant other. Translate it to French."
-
-[OUTPUT]
-    {
-        "input": "Valentine's Day Date Ideas",
-        "subtasks": [
-            {"function": "WriterSkill.Brainstorm"},
-            {"function": "EdgarAllenPoeSkill.Poe"},
-            {"function": "WriterSkill.EmailTo", "args": {"recipient": "significant_other"}},
-            {"function": "WriterSkill.Translate", "args": {"language": "French"}}
-        ]
-    }
-
-[AVAILABLE FUNCTIONS]
-{{$available_functions}}
-
-[GOAL]
-{{$goal}}
-
-[OUTPUT]
-"""
-
-  
-class SonAgentPlanner(BasicPlanner):
-
-    def create_plan_async(
-        self,
-        goal: str,
-        kernel: Kernel,
-        prompt: str = PROMPT,
-    ) -> Plan:
-        return super().create_plan_async(goal, kernel, prompt)
-
-    def load_planning_prompt(self):
-        pass
-
-    def save_plan_to_db(self, plan):
-        pass
-
-
-class SonAgentSequentialPlanner(SequentialPlanner):
-    def __init__(self, kernel: Kernel, config: SequentialPlannerConfig = None, prompt: str = SEQUENCE_PLAN):
-        super().__init__(kernel, config, prompt)
\ No newline at end of file
diff --git a/sonagent/planning/prompt.py b/sonagent/planning/prompt.py
deleted file mode 100644
index d9b8280..0000000
--- a/sonagent/planning/prompt.py
+++ /dev/null
@@ -1,197 +0,0 @@
-PROMPT_PLAN = """
-You are a planner for the Agent.
-Your job is to create a properly formatted JSON plan step by step, to satisfy the goal given with 
-the things you believe to be the best..
-Create a list of subtasks based off the [GOAL] provided.
-Each subtask must be from within the [AVAILABLE FUNCTIONS] list. Do not use any functions that are not in the list.
-Base your decisions on which functions to use from the description and the name of the function.
-Sometimes, a function may take arguments. Provide them if necessary.
-The plan should be as short as possible. If you dont have available functions to satisfy the goal, Please name that function with the prefix `unknow_[function_name]`.
-
-For example:
-
-[AVAILABLE FUNCTIONS]
-EmailConnector.LookupContactEmail
-description: looks up the a contact and retrieves their email address
-args:
-- name: the name to look up
-
-WriterSkill.EmailTo
-description: email the input text to a recipient
-args:
-- input: the text to email
-- recipient: the recipient's email address. Multiple addresses may be included if separated by ';'.
-
-WriterSkill.Translate
-description: translate the input to another language
-args:
-- input: the text to translate
-- language: the language to translate to
-
-WriterSkill.Summarize
-description: summarize input text
-args:
-- input: the text to summarize
-
-FunSkill.Joke
-description: Generate a funny joke
-args:
-- input: the input to generate a joke about
-
-[GOAL]
-"Tell a joke about cars at 9h am everyday. Translate it to Spanish"
-
-[BELIEVE]
-- cars can be used to transport people
-- cars can be used to fly around the world
-- cars can be used to go to the moon
-
-[OUTPUT]
-    {
-        "input": "cars",
-        "subtasks": [
-            {"function": "FunSkill.Joke", "description": "Generate a funny joke about cars"},
-            {"function": "WriterSkill.Translate", "args": {"language": "Spanish"}, "description": "Translate the joke to Spanish"}
-        ]
-    }
-
-[AVAILABLE FUNCTIONS]
-WriterSkill.Brainstorm
-description: Brainstorm ideas
-args:
-- input: the input to brainstorm about
-
-EdgarAllenPoeSkill.Poe
-description: Write in the style of author Edgar Allen Poe
-args:
-- input: the input to write about
-
-WriterSkill.EmailTo
-description: Write an email to a recipient
-args:
-- input: the input to write about
-- recipient: the recipient's email address.
-
-[GOAL]
-"Tomorrow is Valentine's day. I need to come up with a few date ideas.
-She likes Edgar Allen Poe so write using his style.
-E-mail these ideas to my significant other. Translate it to French."
-
-[OUTPUT]
-    {
-        "input": "Valentine's Day Date Ideas",
-        "subtasks": [
-            {"function": "WriterSkill.Brainstorm", "description": "Brainstorm ideas for Valentine's Day"},
-            {"function": "EdgarAllenPoeSkill.Poe", "description": "Write in the style of Edgar Allen Poe"},
-            {"function": "WriterSkill.EmailTo", "args": {"recipient": "significant_other"}, "description": "Email the ideas to my significant other"},
-            {"function": "unknow_WriterSkill.Translate", "args": {"language": "French"}, description: "Translate the ideas to French"}
-        ]
-    }
-
-
-[AVAILABLE FUNCTIONS]
-{{$available_functions}}
-
-[GOAL]
-{{$goal}}
-
-[BELIEVE]
-{{$believe}}
-
-[OUTPUT]
-"""
-
-
-SEQUENCE_PLAN = """
-Create an XML plan step by step, to satisfy the goal given, 
-with the available functions and When creating a plan, prioritize your beliefs first. If it cannot help you achieve your goals, then use other methods..
-
-[AVAILABLE FUNCTIONS]
-
-{{$available_functions}}
-
-[END AVAILABLE FUNCTIONS]
-
-[BELIEVE]
-{{$believe}}
-[END BELIEVE]
-
-To create a plan, follow these steps:
-0. The plan should be as short as possible.
-1. From a <goal> create a <plan> as a series of <functions>.
-2. A plan has 'INPUT' available in context variables by default.
-3. Before using any function in a plan, check that it is present in the [AVAILABLE FUNCTIONS] list. If it is not, do not use it.
-4. Only use functions that are required for the given goal.
-5. Append an "END" XML comment at the end of the plan after the final closing </plan> tag.
-6. Always output valid XML that can be parsed by an XML parser.
-7. If a plan cannot be created with the [AVAILABLE FUNCTIONS], return <plan />.
-
-All plans take the form of:
-<plan>
-    <!-- ... reason for taking step ... -->
-    <function.{FullyQualifiedFunctionName} ... />
-    <!-- ... reason for taking step ... -->
-    <function.{FullyQualifiedFunctionName} ... />
-    <!-- ... reason for taking step ... -->
-    <function.{FullyQualifiedFunctionName} ... />
-    (... etc ...)
-</plan>
-<!-- END -->
-
-To call a function, follow these steps:
-1. A function has one or more named parameters and a single 'output' which are all strings. Parameter values should be xml escaped.
-2. To save an 'output' from a <function>, to pass into a future <function>, use <function.{FullyQualifiedFunctionName} ... setContextVariable="<UNIQUE_VARIABLE_KEY>"/>
-3. To save an 'output' from a <function>, to return as part of a plan result, use <function.{FullyQualifiedFunctionName} ... appendToResult="RESULT__<UNIQUE_RESULT_KEY>"/>
-4. Use a '$' to reference a context variable in a parameter, e.g. when `INPUT='world'` the parameter 'Hello $INPUT' will evaluate to `Hello world`.
-5. Functions do not have access to the context variables of other functions. Do not attempt to use context variables as arrays or objects. Instead, use available functions to extract specific elements or properties from context variables.
-
-DO NOT DO THIS, THE PARAMETER VALUE IS NOT XML ESCAPED:
-<function.Name4 input="$SOME_PREVIOUS_OUTPUT" parameter_name="some value with a <!-- 'comment' in it-->"/>
-
-DO NOT DO THIS, THE PARAMETER VALUE IS ATTEMPTING TO USE A CONTEXT VARIABLE AS AN ARRAY/OBJECT:
-<function.CallFunction input="$OTHER_OUTPUT[1]"/>
-
-Here is a valid example of how to call a function "_Function_.Name" with a single input and save its output:
-<function._Function_.Name input="this is my input" setContextVariable="SOME_KEY"/>
-
-Here is a valid example of how to call a function "FunctionName2" with a single input and return its output as part of the plan result:
-<function.FunctionName2 input="Hello $INPUT" appendToResult="RESULT__FINAL_ANSWER"/>
-
-Here is a valid example of how to call a function "Name3" with multiple inputs:
-<function.Name3 input="$SOME_PREVIOUS_OUTPUT" parameter_name="some value with a &lt;!-- &apos;comment&apos; in it--&gt;"/>
-
-Begin!
-
-<goal>{{$input}}</goal>
-"""
-
-
-CLEAN_BELIEF_PROMPT = """
-List the beliefs related to achieving your goals and eliminate the remaining beliefs
-[BELIEVE]
-- Earth orbits the sun
-- The sun is a star
-- The sun is a ball of fire
-- The sun is a source of light
-- The sun is a source of energy
-- A tree is a plant
-
-[GOAL]
-- Calculate the orbits of the planets
-
-[OUTPUT]
-- Earth orbits the sun
-- The sun is a star
-- The sun is a ball of fire
-- The sun is a source of light
-- The sun is a source of energy
-
-
-[BELIEVE]
-{{$belief}}
-[GOAL]
-{{$goal}}
-
-[OUTPUT]
-
-"""
diff --git a/sonagent/rpc/__init__.py b/sonagent/rpc/__init__.py
index 2c4d154..71f9e40 100644
--- a/sonagent/rpc/__init__.py
+++ b/sonagent/rpc/__init__.py
@@ -1,3 +1,3 @@
+from .io import IOMsg  # noqa: F401
 from .rpc import RPC, RPCException, RPCHandler  # noqa: F401
-from .rpc_manager import RPCManager 
-from .io import IOMsg
\ No newline at end of file
+from .rpc_manager import RPCManager  # noqa: F401
diff --git a/sonagent/rpc/api_server/api_models.py b/sonagent/rpc/api_server/api_models.py
index 5e0f70a..a7d3d10 100644
--- a/sonagent/rpc/api_server/api_models.py
+++ b/sonagent/rpc/api_server/api_models.py
@@ -1,5 +1,3 @@
-from datetime import date, datetime
-from typing import Any, Dict, List, Optional, Union
 
 from pydantic import BaseModel
 
diff --git a/sonagent/rpc/api_server/api_v1.py b/sonagent/rpc/api_server/api_v1.py
index 3b2ca4d..cc97d70 100644
--- a/sonagent/rpc/api_server/api_v1.py
+++ b/sonagent/rpc/api_server/api_v1.py
@@ -1,20 +1,12 @@
 import logging
-from copy import deepcopy
-from typing import List, Optional
 
-from fastapi import APIRouter, Depends, Query
-from fastapi.exceptions import HTTPException
+from fastapi import APIRouter, Depends
 
 from sonagent import __version__
-
-from sonagent.exceptions import OperationalException
 from sonagent.rpc import RPC
-
-from sonagent.rpc.rpc import RPCException
-from sonagent.rpc.api_server.api_models import (Ping, Version, ChatMsg)
+from sonagent.rpc.api_server.api_models import ChatMsg, Ping, Version
 from sonagent.rpc.api_server.utils import get_rpc
 
-
 logger = logging.getLogger(__name__)
 
 
diff --git a/sonagent/rpc/api_server/utils.py b/sonagent/rpc/api_server/utils.py
index f649183..4116d87 100644
--- a/sonagent/rpc/api_server/utils.py
+++ b/sonagent/rpc/api_server/utils.py
@@ -1,7 +1,5 @@
-from typing import Any, AsyncIterator, Dict, Optional
-from uuid import uuid4
+from typing import AsyncIterator, Optional
 
-from fastapi import Depends, HTTPException
 from sonagent.rpc.rpc import RPC, RPCException
 
 from .webserver import ApiServer
diff --git a/sonagent/rpc/api_server/webserver.py b/sonagent/rpc/api_server/webserver.py
index a50e4ff..96293e2 100644
--- a/sonagent/rpc/api_server/webserver.py
+++ b/sonagent/rpc/api_server/webserver.py
@@ -1,20 +1,17 @@
 import logging
 from ipaddress import IPv4Address
-from typing import Any, Optional
+from typing import Any
 
 import orjson
 import uvicorn
-from fastapi import Depends, FastAPI
+from fastapi import FastAPI
 from fastapi.middleware.cors import CORSMiddleware
 from starlette.responses import JSONResponse
 
-from sonagent.rpc.rpc import RPC, RPCException, RPCHandler
-from sonagent.rpc.rpc_types import RPCSendMsg
-from sonagent.exceptions import OperationalException
 from sonagent.configuration import running_in_docker
-
+from sonagent.exceptions import OperationalException
 from sonagent.rpc.api_server.uvicorn_threaded import UvicornServer
-
+from sonagent.rpc.rpc import RPC, RPCException, RPCHandler
 
 logger = logging.getLogger(__name__)
 
@@ -105,8 +102,8 @@ def handle_rpc_exception(self, request, exc):
         )
 
     def configure_app(self, app: FastAPI, config):
-        from sonagent.rpc.api_server.api_v1 import router as api_v1
-        from sonagent.rpc.api_server.api_v1 import router_public as api_v1_public
+        from sonagent.rpc.api_server.api_v1 import \
+            router_public as api_v1_public
 
         app.include_router(api_v1_public, prefix="/api/v1")
 
diff --git a/sonagent/rpc/io.py b/sonagent/rpc/io.py
index 4526503..e21bb80 100644
--- a/sonagent/rpc/io.py
+++ b/sonagent/rpc/io.py
@@ -15,3 +15,8 @@ def send_msg(msg: str):  # Remove the 'self' parameter
             })
         else:
             print(msg)
+
+    @staticmethod
+    def get_input(msg: str):
+        IOMsg.message.append(msg)
+        return msg
diff --git a/sonagent/rpc/rpc.py b/sonagent/rpc/rpc.py
index 8ad05d5..c853052 100644
--- a/sonagent/rpc/rpc.py
+++ b/sonagent/rpc/rpc.py
@@ -1,14 +1,12 @@
 """
 This module contains class to define a RPC communications
 """
-import logging
 from abc import abstractmethod
-from datetime import date, datetime, timedelta, timezone
-from math import isnan
-from typing import Any, Dict, Generator, List, Optional, Sequence, Tuple, Union
 
-from sonagent.rpc.rpc_types import RPCSendMsg
 from sonagent.constants import AGENT_MODE
+from sonagent.rpc.rpc_types import RPCSendMsg
+from sonagent.utils.utils import init_evironment
+
 
 class RPCException(Exception):
     """
@@ -95,6 +93,39 @@ async def reincarnate(self) -> None:
         """
         return await self.sonagent.reincarnate()
     
+    async def show_env(self) -> list:
+        """
+        Send a chat message to all registered rpc modules.
+        :param msg: Message to send
+        :return: None
+        """
+        return await self.sonagent.show_env()
+    
+    async def add_env(self, key: str, value: str, description: str) -> str:
+        """
+        Send a chat message to all registered rpc modules.
+        :param msg: Message to send
+        :return: None
+        """
+        return await self.sonagent.add_env(key, value, description)
+    
+    async def remove_env(self, key: str) -> str:
+        """
+        Send a chat message to all registered rpc modules.
+        :param msg: Message to send
+        :return: None
+        """
+        return await self.sonagent.remove_env(key)
+    
+    async def reload_env(self) -> str:
+        """
+        Send a chat message to all registered rpc modules.
+        :param msg: Message to send
+        :return: None
+        """
+        init_evironment()
+        return "Env reloaded"
+    
     async def askme(self, msg: str) -> str:
         """
         Send a chat message to all registered rpc modules.
diff --git a/sonagent/rpc/rpc_manager.py b/sonagent/rpc/rpc_manager.py
index cc42ce6..9264101 100644
--- a/sonagent/rpc/rpc_manager.py
+++ b/sonagent/rpc/rpc_manager.py
@@ -2,14 +2,11 @@
 This module contains class to manage RPC communications (Telegram, API, ...)
 """
 import logging
-from collections import deque
 from typing import List
 
-from sonagent.enums import RPCMessageType
 from sonagent.rpc import RPC, RPCHandler
 from sonagent.rpc.rpc_types import RPCSendMsg
 
-
 logger = logging.getLogger(__name__)
 
 
@@ -51,7 +48,7 @@ def send_msg(self, msg: RPCSendMsg) -> None:
 
         logger.info('Sending rpc message: %s', msg)
         for mod in self.registered_modules:
-            logger.debug('Forwarding message to rpc.%s', mod.name)
+            logger.info('Forwarding message to rpc.%s', mod.name)
             try:
                 mod.send_msg(msg)
             except NotImplementedError:
diff --git a/sonagent/rpc/rpc_types.py b/sonagent/rpc/rpc_types.py
index 9e28f94..80d1e21 100644
--- a/sonagent/rpc/rpc_types.py
+++ b/sonagent/rpc/rpc_types.py
@@ -1,5 +1,5 @@
-from datetime import datetime
-from typing import Any, List, Literal, Optional, TypedDict, Union
+from typing import Literal, TypedDict, Union
+
 from sonagent.enums import RPCMessageType
 
 
diff --git a/sonagent/rpc/telegram.py b/sonagent/rpc/telegram.py
index 6cde1f1..01e4261 100644
--- a/sonagent/rpc/telegram.py
+++ b/sonagent/rpc/telegram.py
@@ -4,34 +4,28 @@
 This module manage Telegram communication
 """
 import asyncio
-import json
 import logging
 import re
 from copy import deepcopy
-from dataclasses import dataclass
-from datetime import date, datetime, timedelta
-from functools import partial, wraps
-from html import escape
+from datetime import datetime
 from itertools import chain
-from math import isnan
 from threading import Thread
-from typing import Any, Callable, Coroutine, Dict, List, Literal, Optional, Union
+from typing import List, Optional, Union
 
-
-from telegram import (CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton,
+from tabulate import tabulate
+from telegram import (CallbackQuery, InlineKeyboardButton,
+                      InlineKeyboardMarkup, KeyboardButton,
                       ReplyKeyboardMarkup, Update)
 from telegram.constants import MessageLimit, ParseMode
 from telegram.error import BadRequest, NetworkError, TelegramError
-from telegram.ext import Application, CallbackContext, CallbackQueryHandler, CommandHandler, MessageHandler, ContextTypes
-from telegram.helpers import escape_markdown
-from telegram.ext import filters
+from telegram.ext import (Application, CallbackContext, CommandHandler,
+                          ContextTypes, MessageHandler, filters)
 
+from sonagent.__init__ import __version__
+from sonagent.enums import RPCMessageType
 from sonagent.exceptions import OperationalException
-from sonagent.rpc import RPC, RPCException, RPCHandler
+from sonagent.rpc import RPC, RPCHandler
 from sonagent.rpc.rpc_types import RPCSendMsg
-from sonagent.enums import RPCMessageType
-from sonagent.__init__ import __version__
-
 
 logger = logging.getLogger(__name__)
 logging.getLogger("httpx").setLevel(logging.WARNING)
@@ -76,7 +70,8 @@ def _init_keyboard(self) -> None:
         #       problem in _help()).
         valid_keys: List[str] = [
             r'/ibelieve', r'/show_mode$', r'/mode', r'/sum$', r'/show_skills$',
-            r'/reload_skills$', r'/remove_skill', r'/show_schedule$',
+            r'/reload_skills$', r'/remove_skill', r'/show_schedule$', r'/env$',
+            r'/add_env', r'/remove_env', r'/reload_env',
             r'/help$', r'/version$'
         ]
         # Create keys for generation
@@ -128,16 +123,7 @@ async def echo_msg(self, update: Update, context: ContextTypes.DEFAULT_TYPE) ->
         msg = update.message.text.replace('/sonagent', '')
         if len(msg) <= 0:
             msg = "Hello, I'm SonAgent"
-        
-        chat_result = await self._rpc.chat(msg)
-
-        if len(chat_result) > MAX_MESSAGE_LENGTH:
-            msg_parts = self.split_message_parts(chat_result)
-            for msg_part in msg_parts:
-                # await update.message.reply_text(msg_part)
-                await self._send_msg(msg_part, parse_mode=ParseMode.MARKDOWN)
-        # await update.message.reply_text(chat_result)
-        await self._send_msg(chat_result, parse_mode=ParseMode.MARKDOWN)
+        await self._rpc.chat(msg)
 
     def _init(self) -> None:
         """
@@ -165,8 +151,12 @@ def _init(self) -> None:
             CommandHandler('show_mode', self._show_mode),
             CommandHandler('sum', self._summerize_dialog),
             CommandHandler('show_skills', self._show_skills),
+            CommandHandler('env', self._env),
+            CommandHandler('add_env', self._add_env),
+            CommandHandler('remove_env', self._remove_env),
             CommandHandler('show_schedule', self._show_schedule),
             CommandHandler('reload_skills', self._reload_skills),
+            CommandHandler('reload_env', self._reload_env),
             CommandHandler('remove_skill', self._remove_skill),
             CommandHandler('mode', self._mode),
             CommandHandler('help', self._help),
@@ -258,10 +248,17 @@ def send_msg(self, msg: RPCSendMsg) -> None:
         message = self.compose_message(deepcopy(msg))
         logger.info(f"Sending message: {message}")
         if message:
-            asyncio.run_coroutine_threadsafe(
-                self._send_msg(message, parse_mode=ParseMode.MARKDOWN),
-                self._loop)
-        # self._send_msg(message, disable_notification=(noti == 'silent')),
+            if len(message) > MAX_MESSAGE_LENGTH:
+                msg_parts = self.split_message_parts(message)
+                for msg_part in msg_parts:
+                    asyncio.run_coroutine_threadsafe(
+                        self._send_msg(msg_part, parse_mode=ParseMode.MARKDOWN),
+                        self._loop
+                    )
+            else:
+                asyncio.run_coroutine_threadsafe(
+                    self._send_msg(message, parse_mode=ParseMode.MARKDOWN),
+                    self._loop)
 
     async def _update_msg(self, query: CallbackQuery, msg: str, callback_path: str = "",
                           reload_able: bool = False, parse_mode: str = ParseMode.MARKDOWN) -> None:
@@ -360,6 +357,22 @@ async def _help(self, update: Update, context: CallbackContext) -> None:
         message = (
             "_Bot Control_\n"
             "------------\n"
+            "*/show_plan:* `Show plan`\n"
+            "*/planning:* `Planning`\n"
+            "*/clear_chat:* `Clear chat`\n"
+            "*/reincarnate:* `Reincarnate`\n"
+            "*/askme:* `Ask me`\n"
+            "*/ibelieve:* `I believe in you`\n"
+            "*/show_mode:* `Show mode`\n"
+            "*/sum:* `Summerize dialog`\n"
+            "*/show_skills:* `Show skills`\n"
+            "*/show_schedule:* `Show schedule`\n"
+            "*/reload_skills:* `Reload skills`\n"
+            "*/remove_skill:* `Remove skill`\n"
+            "*/mode:* `Mode`\n"
+            "*/env:* `Environment`\n"
+            "*/add_env:* `Add environment`\n"
+            "*/remove_env:* `Remove environment`\n"
             "*/help:* `This help message`\n"
             "*/version:* `Show version`"
             )
@@ -377,6 +390,82 @@ async def _version(self, update: Update, context: CallbackContext) -> None:
         version_string = f'*Version:* `{__version__}`'
         await self._send_msg(version_string)
     
+    async def _env(self, update: Update, context: CallbackContext) -> None:
+        """
+        Handler for /env.
+        Show version information
+        :param bot: telegram bot
+        :param update: message update
+        :return: None
+        """
+        result = await self._rpc.show_env()
+        head = ['Key', 'Value', 'Description']
+        logger.info(result)
+        message = tabulate(result, headers=head, tablefmt='simple')
+
+        await self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML)
+        # await update.message.reply_text(result, parse_mode=ParseMode.MARKDOWN)
+
+    async def _reload_env(self, update: Update, context: CallbackContext) -> None:
+        """
+        Handler for /reload_env.
+        Show version information
+        :param bot: telegram bot
+        :param update: message update
+        :return: None
+        """
+        result = await self._rpc.reload_env()
+        await update.message.reply_text(result)
+
+    async def _add_env(self, update: Update, context: CallbackContext) -> None:
+        """
+        Handler for /add_env.
+        Show version information
+        :param bot: telegram bot
+        :param update: message update
+        :return: None
+        """
+        result = "Add your environment!"
+        msg = update.message.text.replace('/add_env', '')
+
+        logger.info(msg)
+
+        if len(msg) > 0:
+            try:
+                msg_param = msg.strip().split(' ')
+                key = msg_param[0].strip()
+                value = msg_param[1].strip()
+                description = msg_param[2].strip()
+                result = await self._rpc.add_env(key, value, description)
+            except Exception as e:
+                result = "Wrong format. Please use /add_env key value description"
+                logger.error(e)
+        else:
+            result = "What environment you want to add?"
+
+        await update.message.reply_text(result, parse_mode=ParseMode.MARKDOWN)
+
+    async def _remove_env(self, update: Update, context: CallbackContext) -> None:
+        """
+        Handler for /remove_env.
+        Show version information
+        :param bot: telegram bot
+        :param update: message update
+        :return: None
+        """
+        result = "remove your environment!"
+
+        env_name = update.message.text.replace('/remove_env', '')
+
+        if len(env_name) > 0:
+            result = await self._rpc.remove_env(env_name=env_name.strip())
+        else:
+            result = "What environment you want to remove?"
+
+        # result = "remove your ai skill!"
+
+        await update.message.reply_text(result)
+    
     async def _show_skills(self, update: Update, context: CallbackContext) -> None:
         """
         Handler for /show_skills.
diff --git a/sonagent/rpc/webhook.py b/sonagent/rpc/webhook.py
index 098bb4c..ef0ec87 100644
--- a/sonagent/rpc/webhook.py
+++ b/sonagent/rpc/webhook.py
@@ -1,12 +1,13 @@
 import logging
 import time
 from typing import Any, Dict, Optional
+
 from requests import RequestException, post
+
 from sonagent.enums import RPCMessageType
 from sonagent.rpc import RPC, RPCHandler
 from sonagent.rpc.rpc_types import RPCSendMsg
 
-
 logger = logging.getLogger(__name__)
 
 logger.debug('import module rpc.webhook ...')
diff --git a/sonagent/skills/core_skills/__init__.py b/sonagent/skills/core_skills/__init__.py
deleted file mode 100644
index 0b3486b..0000000
--- a/sonagent/skills/core_skills/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from semantic_kernel.core_skills.conversation_summary_skill import (
-    ConversationSummarySkill,
-)
-from sonagent.skills.core_skills.file_io_skill import FileIOSkill
-from sonagent.skills.core_skills.http_skill import HttpSkill
-from sonagent.skills.core_skills.math_skill import MathSkill
-from sonagent.skills.core_skills.text_skill import TextSkill
-from sonagent.skills.core_skills.time_skill import TimeSkill
-
-__all__ = [
-    "TextSkill",
-    "FileIOSkill",
-    "TimeSkill",
-    "HttpSkill",
-    "ConversationSummarySkill",
-    "MathSkill"
-]
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/conversation_summary_skill.py b/sonagent/skills/core_skills/conversation_summary_skill.py
deleted file mode 100644
index e1b5a65..0000000
--- a/sonagent/skills/core_skills/conversation_summary_skill.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-from typing import TYPE_CHECKING
-
-if TYPE_CHECKING:
-    from semantic_kernel.kernel import Kernel
-    from semantic_kernel.orchestration.sk_context import SKContext
-
-
-class ConversationSummarySkill:
-    """
-    Semantic skill that enables conversations summarization.
-    """
-
-    from semantic_kernel.skill_definition import sk_function
-
-    # The max tokens to process in a single semantic function call.
-    _max_tokens = 1024
-
-    _summarize_conversation_prompt_template = (
-        "BEGIN CONTENT TO SUMMARIZE:\n{{"
-        + "$INPUT"
-        + "}}\nEND CONTENT TO SUMMARIZE.\nSummarize the conversation in 'CONTENT TO"
-        " SUMMARIZE',            identifying main points of discussion and any"
-        " conclusions that were reached.\nDo not incorporate other general"
-        " knowledge.\nSummary is in plain text, in complete sentences, with no markup"
-        " or tags.\n\nBEGIN SUMMARY:\n"
-    )
-
-    def __init__(self, kernel: "Kernel"):
-        self._summarizeConversationFunction = kernel.create_semantic_function(
-            ConversationSummarySkill._summarize_conversation_prompt_template,
-            skill_name=ConversationSummarySkill.__name__,
-            description=("Given a section of a conversation transcript, summarize the part of" " the conversation."),
-            max_tokens=ConversationSummarySkill._max_tokens,
-            temperature=0.1,
-            top_p=0.5,
-        )
-
-    @sk_function(
-        description="Given a long conversation transcript, summarize the conversation.",
-        name="SummarizeConversation",
-        input_description="A long conversation transcript.",
-    )
-    async def summarize_conversation_async(self, input: str, context: "SKContext") -> "SKContext":
-        """
-        Given a long conversation transcript, summarize the conversation.
-
-        :param input: A long conversation transcript.
-        :param context: The SKContext for function execution.
-        :return: SKContext with the summarized conversation result.
-        """
-        from semantic_kernel.text import text_chunker
-        from semantic_kernel.text.function_extension import (
-            aggregate_chunked_results_async,
-        )
-
-        lines = text_chunker._split_text_lines(input, ConversationSummarySkill._max_tokens, True)
-        paragraphs = text_chunker._split_text_paragraph(lines, ConversationSummarySkill._max_tokens)
-
-        return await aggregate_chunked_results_async(self._summarizeConversationFunction, paragraphs, context)
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/file_io_skill.py b/sonagent/skills/core_skills/file_io_skill.py
deleted file mode 100644
index ab9899e..0000000
--- a/sonagent/skills/core_skills/file_io_skill.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-import os
-import typing as t
-
-import aiofiles
-
-from semantic_kernel.sk_pydantic import SKBaseModel
-from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter
-
-if t.TYPE_CHECKING:
-    from semantic_kernel.orchestration.sk_context import SKContext
-
-
-class FileIOSkill(SKBaseModel):
-    """
-    Description: Read and write from a file.
-
-    Usage:
-        kernel.import_skill(FileIOSkill(), skill_name="file")
-
-    Examples:
-
-    {{file.readAsync $path }} => "hello world"
-    {{file.writeAsync}}
-    """
-
-    @sk_function(
-        description="Read a file",
-        name="readAsync",
-        input_description="Path of the source file",
-    )
-    async def read_async(self, path: str) -> str:
-        """
-        Read a file
-
-        Example:
-            {{file.readAsync $path }} => "hello world"
-        Args:
-            path -- The path to the file to read
-
-        Returns:
-            The contents of the file
-        """
-
-        assert os.path.exists(path), f"File {path} does not exist"
-
-        async with aiofiles.open(path, "r", encoding="UTF-8") as fp:
-            content = await fp.read()
-            return content
-
-    @sk_function(
-        description="Write a file",
-        name="writeAsync",
-    )
-    @sk_function_context_parameter(name="path", description="Destination path")
-    @sk_function_context_parameter(name="content", description="File content")
-    async def write_async(self, context: "SKContext") -> None:
-        """
-        Write a file
-
-        Example:
-            {{file.writeAsync}}
-        Args:
-            Contains the 'path' for the Destination file and
-            the 'content' of the file to write.
-        """
-        path = context.variables.get("path")
-        content = context.variables.get("content")
-
-        assert path, "Path is required"
-        assert content, "Content is required"
-
-        async with aiofiles.open(path, "w") as fp:
-            await fp.write(content)
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/http_skill.py b/sonagent/skills/core_skills/http_skill.py
deleted file mode 100644
index 4efb9f5..0000000
--- a/sonagent/skills/core_skills/http_skill.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-import json
-import typing as t
-
-import aiohttp
-
-from semantic_kernel.sk_pydantic import SKBaseModel
-from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter
-
-if t.TYPE_CHECKING:
-    from semantic_kernel.orchestration.sk_context import SKContext
-
-
-class HttpSkill(SKBaseModel):
-    """
-    A skill that provides HTTP functionality.
-
-    Usage:
-        kernel.import_skill(HttpSkill(), "http")
-
-    Examples:
-
-        {{http.getAsync $url}}
-        {{http.postAsync $url}}
-        {{http.putAsync $url}}
-        {{http.deleteAsync $url}}
-    """
-
-    @sk_function(description="Makes a GET request to a uri", name="getAsync")
-    async def get_async(self, url: str) -> str:
-        """
-        Sends an HTTP GET request to the specified URI and returns
-        the response body as a string.
-        params:
-            uri: The URI to send the request to.
-        returns:
-            The response body as a string.
-        """
-        if not url:
-            raise ValueError("url cannot be `None` or empty")
-
-        async with aiohttp.ClientSession() as session:
-            async with session.get(url, raise_for_status=True) as response:
-                return await response.text()
-
-    @sk_function(description="Makes a POST request to a uri", name="postAsync")
-    @sk_function_context_parameter(name="body", description="The body of the request")
-    async def post_async(self, url: str, context: "SKContext") -> str:
-        """
-        Sends an HTTP POST request to the specified URI and returns
-        the response body as a string.
-        params:
-            url: The URI to send the request to.
-            context: Contains the body of the request
-        returns:
-            The response body as a string.
-        """
-        if not url:
-            raise ValueError("url cannot be `None` or empty")
-
-        body = context.variables.get("body")
-
-        headers = {"Content-Type": "application/json"}
-        data = json.dumps(body)
-        async with aiohttp.ClientSession() as session:
-            async with session.post(url, headers=headers, data=data, raise_for_status=True) as response:
-                return await response.text()
-
-    @sk_function(description="Makes a PUT request to a uri", name="putAsync")
-    @sk_function_context_parameter(name="body", description="The body of the request")
-    async def put_async(self, url: str, context: "SKContext") -> str:
-        """
-        Sends an HTTP PUT request to the specified URI and returns
-        the response body as a string.
-        params:
-            url: The URI to send the request to.
-        returns:
-            The response body as a string.
-        """
-        if not url:
-            raise ValueError("url cannot be `None` or empty")
-
-        body = context.variables.get("body")
-
-        headers = {"Content-Type": "application/json"}
-        data = json.dumps(body)
-        async with aiohttp.ClientSession() as session:
-            async with session.put(url, headers=headers, data=data, raise_for_status=True) as response:
-                return await response.text()
-
-    @sk_function(description="Makes a DELETE request to a uri", name="deleteAsync")
-    async def delete_async(self, url: str) -> str:
-        """
-        Sends an HTTP DELETE request to the specified URI and returns
-        the response body as a string.
-        params:
-            uri: The URI to send the request to.
-        returns:
-            The response body as a string.
-        """
-        if not url:
-            raise ValueError("url cannot be `None` or empty")
-        async with aiohttp.ClientSession() as session:
-            async with session.delete(url, raise_for_status=True) as response:
-                return await response.text()
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/math_skill.py b/sonagent/skills/core_skills/math_skill.py
deleted file mode 100644
index 9c4c9ab..0000000
--- a/sonagent/skills/core_skills/math_skill.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-import typing as t
-
-from semantic_kernel.sk_pydantic import SKBaseModel
-from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter
-
-if t.TYPE_CHECKING:
-    from semantic_kernel.orchestration.sk_context import SKContext
-
-
-class MathSkill(SKBaseModel):
-    """
-    Description: MathSkill provides a set of functions to make Math calculations.
-
-    Usage:
-        kernel.import_skill(MathSkill(), skill_name="math")
-
-    Examples:
-        {{math.Add}}         => Returns the sum of initial_value_text and Amount (provided in the SKContext)
-    """
-
-    @sk_function(
-        description="Adds value to a value",
-        name="Add",
-        input_description="The value to add",
-    )
-    @sk_function_context_parameter(
-        name="Amount",
-        description="Amount to add",
-        # type="number",
-        required=True,
-    )
-    def add(self, initial_value_text: str, context: "SKContext") -> str:
-        """
-        Returns the Addition result of initial and amount values provided.
-
-        :param initial_value_text: Initial value as string to add the specified amount
-        :param context: Contains the context to get the numbers from
-        :return: The resulting sum as a string
-        """
-        return MathSkill.add_or_subtract(initial_value_text, context, add=True)
-
-    @sk_function(
-        description="Subtracts value to a value",
-        name="Subtract",
-        input_description="The value to subtract",
-    )
-    @sk_function_context_parameter(
-        name="Amount",
-        description="Amount to subtract",
-        type="number",
-        required=True,
-    )
-    def subtract(self, initial_value_text: str, context: "SKContext") -> str:
-        """
-        Returns the difference of numbers provided.
-
-        :param initial_value_text: Initial value as string to subtract the specified amount
-        :param context: Contains the context to get the numbers from
-        :return: The resulting subtraction as a string
-        """
-        return MathSkill.add_or_subtract(initial_value_text, context, add=False)
-
-    @staticmethod
-    def add_or_subtract(initial_value_text: str, context: "SKContext", add: bool) -> str:
-        """
-        Helper function to perform addition or subtraction based on the add flag.
-
-        :param initial_value_text: Initial value as string to add or subtract the specified amount
-        :param context: Contains the context to get the numbers from
-        :param add: If True, performs addition, otherwise performs subtraction
-        :return: The resulting sum or subtraction as a string
-        """
-        try:
-            initial_value = int(initial_value_text)
-        except ValueError:
-            raise ValueError(f"Initial value provided is not in numeric format: {initial_value_text}")
-
-        context_amount = context["Amount"]
-        if context_amount is not None:
-            try:
-                amount = int(context_amount)
-            except ValueError:
-                raise ValueError("Context amount provided is not in numeric format:" f" {context_amount}")
-
-            result = initial_value + amount if add else initial_value - amount
-            return str(result)
-        else:
-            raise ValueError("Context amount should not be None.")
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/text_skill.py b/sonagent/skills/core_skills/text_skill.py
deleted file mode 100644
index 72b7227..0000000
--- a/sonagent/skills/core_skills/text_skill.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-from semantic_kernel.sk_pydantic import SKBaseModel
-from semantic_kernel.skill_definition import sk_function
-
-
-class TextSkill(SKBaseModel):
-    """
-    TextSkill provides a set of functions to manipulate strings.
-
-    Usage:
-        kernel.import_skill(TextSkill(), skill_name="text")
-
-    Examples:
-        SKContext["input"] = "  hello world  "
-        {{text.trim $input}} => "hello world"
-
-        SKContext["input"] = "  hello world  "
-        {{text.trimStart $input} => "hello world  "
-
-        SKContext["input"] = "  hello world  "
-        {{text.trimEnd $input} => "  hello world"
-
-        SKContext["input"] = "hello world"
-        {{text.uppercase $input}} => "HELLO WORLD"
-
-        SKContext["input"] = "HELLO WORLD"
-        {{text.lowercase $input}} => "hello world"
-    """
-
-    @sk_function(description="Trim whitespace from the start and end of a string.")
-    def trim(self, text: str) -> str:
-        """
-        Trim whitespace from the start and end of a string.
-
-        Example:
-            SKContext["input"] = "  hello world  "
-            {{text.trim $input}} => "hello world"
-        """
-        return text.strip()
-
-    @sk_function(description="Trim whitespace from the start of a string.")
-    def trim_start(self, text: str) -> str:
-        """
-        Trim whitespace from the start of a string.
-
-         Example:
-             SKContext["input"] = "  hello world  "
-             {{text.trim $input}} => "hello world  "
-        """
-        return text.lstrip()
-
-    @sk_function(description="Trim whitespace from the end of a string.")
-    def trim_end(self, text: str) -> str:
-        """
-        Trim whitespace from the end of a string.
-
-         Example:
-             SKContext["input"] = "  hello world  "
-             {{text.trim $input}} => "  hello world"
-        """
-        return text.rstrip()
-
-    @sk_function(description="Convert a string to uppercase.")
-    def uppercase(self, text: str) -> str:
-        """
-        Convert a string to uppercase.
-
-        Example:
-            SKContext["input"] = "hello world"
-             {{text.uppercase $input}} => "HELLO WORLD"
-        """
-        return text.upper()
-
-    @sk_function(description="Convert a string to lowercase.")
-    def lowercase(self, text: str) -> str:
-        """
-        Convert a string to lowercase.
-
-         Example:
-             SKContext["input"] = "HELLO WORLD"
-             {{text.lowercase $input}} => "hello world"
-        """
-        return text.lower()
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/time_skill.py b/sonagent/skills/core_skills/time_skill.py
deleted file mode 100644
index cc4f5b0..0000000
--- a/sonagent/skills/core_skills/time_skill.py
+++ /dev/null
@@ -1,267 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-import datetime
-
-from semantic_kernel.sk_pydantic import SKBaseModel
-from semantic_kernel.skill_definition import sk_function
-
-
-class TimeSkill(SKBaseModel):
-    """
-    Description: TimeSkill provides a set of functions
-                 to get the current time and date.
-
-    Usage:
-        kernel.import_skill(TimeSkill(), skill_name="time")
-
-    Examples:
-        {{time.date}}            => Sunday, 12 January, 2031
-        {{time.today}}           => Sunday, 12 January, 2031
-        {{time.iso_date}}        => 2031-01-12
-        {{time.now}}             => Sunday, January 12, 2031 9:15 PM
-        {{time.utcNow}}          => Sunday, January 13, 2031 5:15 AM
-        {{time.time}}            => 09:15:07 PM
-        {{time.year}}            => 2031
-        {{time.month}}           => January
-        {{time.monthNumber}}     => 01
-        {{time.day}}             => 12
-        {{time.dayOfWeek}}       => Sunday
-        {{time.hour}}            => 9 PM
-        {{time.hourNumber}}      => 21
-        {{time.days_ago $days}} => Sunday, 7 May, 2023
-        {{time.last_matching_day $dayName}} => Sunday, 7 May, 2023
-        {{time.minute}}          => 15
-        {{time.minutes}}         => 15
-        {{time.second}}          => 7
-        {{time.seconds}}         => 7
-        {{time.timeZoneOffset}}  => -0800
-        {{time.timeZoneName}}    => PST
-    """
-
-    @sk_function(description="Get the current date.")
-    def date(self) -> str:
-        """
-        Get the current date
-
-        Example:
-            {{time.date}} => Sunday, 12 January, 2031
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%A, %d %B, %Y")
-
-    @sk_function(description="Get the current date.")
-    def today(self) -> str:
-        """
-        Get the current date
-
-        Example:
-            {{time.today}} => Sunday, 12 January, 2031
-        """
-        return self.date()
-
-    @sk_function(description="Get the current date in iso format.")
-    def iso_date(self) -> str:
-        """
-        Get the current date in iso format
-
-        Example:
-            {{time.iso_date}} => 2031-01-12
-        """
-        today = datetime.date.today()
-        return today.isoformat()
-
-    @sk_function(description="Get the current date and time in the local time zone")
-    def now(self) -> str:
-        """
-        Get the current date and time in the local time zone"
-
-        Example:
-            {{time.now}} => Sunday, January 12, 2031 9:15 PM
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%A, %B %d, %Y %I:%M %p")
-
-    @sk_function(description="Get the current date and time in UTC", name="utcNow")
-    def utc_now(self) -> str:
-        """
-        Get the current date and time in UTC
-
-        Example:
-            {{time.utcNow}} => Sunday, January 13, 2031 5:15 AM
-        """
-        now = datetime.datetime.utcnow()
-        return now.strftime("%A, %B %d, %Y %I:%M %p")
-
-    @sk_function(description="Get the current time in the local time zone")
-    def time(self) -> str:
-        """
-        Get the current time in the local time zone
-
-        Example:
-            {{time.time}} => 09:15:07 PM
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%I:%M:%S %p")
-
-    @sk_function(description="Get the current year")
-    def year(self) -> str:
-        """
-        Get the current year
-
-        Example:
-            {{time.year}} => 2031
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%Y")
-
-    @sk_function(description="Get the current month")
-    def month(self) -> str:
-        """
-        Get the current month
-
-        Example:
-            {{time.month}} => January
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%B")
-
-    @sk_function(description="Get the current month number")
-    def month_number(self) -> str:
-        """
-        Get the current month number
-
-        Example:
-            {{time.monthNumber}} => 01
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%m")
-
-    @sk_function(description="Get the current day")
-    def day(self) -> str:
-        """
-        Get the current day of the month
-
-        Example:
-            {{time.day}} => 12
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%d")
-
-    @sk_function(description="Get the current day of the week", name="dayOfWeek")
-    def day_of_week(self) -> str:
-        """
-        Get the current day of the week
-
-        Example:
-            {{time.dayOfWeek}} => Sunday
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%A")
-
-    @sk_function(description="Get the current hour")
-    def hour(self) -> str:
-        """
-        Get the current hour
-
-        Example:
-            {{time.hour}} => 9 PM
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%I %p")
-
-    @sk_function(description="Get the current hour number", name="hourNumber")
-    def hour_number(self) -> str:
-        """
-        Get the current hour number
-
-        Example:
-            {{time.hourNumber}} => 21
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%H")
-
-    @sk_function(description="Get the current minute")
-    def minute(self) -> str:
-        """
-        Get the current minute
-
-        Example:
-            {{time.minute}} => 15
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%M")
-
-    @sk_function(description="Get the date of offset from today by a provided number of days")
-    def days_ago(self, days: str) -> str:
-        """
-        Get the date a provided number of days in the past
-
-        params:
-            days: The number of days to offset from today
-        returns:
-            The date of the offset day.
-
-        Example:
-             SKContext["input"] = "3"
-             {{time.days_ago $input}} => Sunday, 7 May, 2023
-        """
-        d = datetime.date.today() - datetime.timedelta(days=int(days))
-        return d.strftime("%A, %d %B, %Y")
-
-    @sk_function(
-        description="""Get the date of the last day matching the supplied week day name in English.
-        Example: Che giorno era 'Martedi' scorso -> dateMatchingLastDayName 'Tuesday' => Tuesday,
-        16 May, 2023"""
-    )
-    def date_matching_last_day_name(self, day_name: str) -> str:
-        """
-        Get the date of the last day matching the supplied day name
-
-        params:
-            day_name: The day name to match with.
-        returns:
-            The date of the matching day.
-
-        Example:
-             SKContext["input"] = "Sunday"
-             {{time.date_matching_last_day_name $input}} => Sunday, 7 May, 2023
-        """
-        d = datetime.date.today()
-        for i in range(1, 8):
-            d = d - datetime.timedelta(days=1)
-            if d.strftime("%A") == day_name:
-                return d.strftime("%A, %d %B, %Y")
-        raise ValueError("day_name is not recognized")
-
-    @sk_function(description="Get the seconds on the current minute")
-    def second(self) -> str:
-        """
-        Get the seconds on the current minute
-
-        Example:
-            {{time.second}} => 7
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%S")
-
-    @sk_function(description="Get the current time zone offset", name="timeZoneOffset")
-    def time_zone_offset(self) -> str:
-        """
-        Get the current time zone offset
-
-        Example:
-            {{time.timeZoneOffset}} => -08:00
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%z")
-
-    @sk_function(description="Get the current time zone name", name="timeZoneName")
-    def time_zone_name(self) -> str:
-        """
-        Get the current time zone name
-
-        Example:
-            {{time.timeZoneName}} => PST
-        """
-        now = datetime.datetime.now()
-        return now.strftime("%Z")
\ No newline at end of file
diff --git a/sonagent/skills/core_skills/wait_skill.py b/sonagent/skills/core_skills/wait_skill.py
deleted file mode 100644
index a53a00d..0000000
--- a/sonagent/skills/core_skills/wait_skill.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-import asyncio
-
-from semantic_kernel.sk_pydantic import SKBaseModel
-from semantic_kernel.skill_definition import sk_function
-
-
-class WaitSkill(SKBaseModel):
-    """
-    WaitSkill provides a set of functions to wait for a certain amount of time.
-
-    Usage:
-        kernel.import_skill(WaitSkill(), skill_name="wait")
-
-    Examples:
-        {{wait.seconds 5}} => Wait for 5 seconds
-    """
-
-    @sk_function(description="Wait for a certain number of seconds.")
-    async def wait(self, seconds_text: str) -> None:
-        try:
-            seconds = max(float(seconds_text), 0)
-        except ValueError:
-            raise ValueError("seconds text must be a number")
-        await asyncio.sleep(seconds)
diff --git a/sonagent/skills/learning_skills/run.py b/sonagent/skills/learning_skills/run.py
deleted file mode 100644
index 5887504..0000000
--- a/sonagent/skills/learning_skills/run.py
+++ /dev/null
@@ -1,2 +0,0 @@
-def learning_run():
-    pass
\ No newline at end of file
diff --git a/sonagent/skills/learning_skills/skprompt.txt b/sonagent/skills/learning_skills/skprompt.txt
deleted file mode 100644
index d005e95..0000000
--- a/sonagent/skills/learning_skills/skprompt.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-class {{skill_name}}Tool:
-    @sk_function(
-        description="{{skill_description}}",
-        name="{{skill_name}}",
-    )
-    @sk_function_context_parameter(
-        name="{{skill_description_1}}",
-        description="The first number to add",
-    )
-    @sk_function_context_parameter(
-        name="skill_description_2",
-        description="The second number to add",
-    )
-
-[GOAL]
-gen code with this template for add 2 number 
-
-[OUTPUT]
-class AddTool:
-    @sk_function(
-        description="Adds two numbers together",
-        name="add",
-    )
-    @sk_function_context_parameter(
-        name="The first number to add",
-        description="The first number to add",
-    )
-    @sk_function_context_parameter(
-        name="The second number to add",
-        description="The second number to add",
-    )
-    def add(self, context: SKContext) -> str:
-        return str(float(context["input"]) + float(context["number2"]))
-
-[GOAL]
-gen code with this template for subtract 2 number 
-[OUTPUT]
diff --git a/sonagent/skills/loading.py b/sonagent/skills/loading.py
index c448eed..3d4beda 100644
--- a/sonagent/skills/loading.py
+++ b/sonagent/skills/loading.py
@@ -10,9 +10,6 @@
 from pathlib import Path
 from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union
 
-from sonagent.exceptions import OperationalException
-
-
 logger = logging.getLogger(__name__)
 
 
diff --git a/sonagent/skills/skills.py b/sonagent/skills/skills.py
index 9826ad7..0d6a40e 100644
--- a/sonagent/skills/skills.py
+++ b/sonagent/skills/skills.py
@@ -1,7 +1,7 @@
 
-import logging
+from abc import ABC, abstractmethod
+
 from semantic_kernel.sk_pydantic import SKBaseModel
-from abc import ABC, abstractmethod 
 
 
 class SonSkill(ABC, SKBaseModel):
diff --git a/sonagent/skills/skills_manager.py b/sonagent/skills/skills_manager.py
index 58b4dc5..7fd72b3 100644
--- a/sonagent/skills/skills_manager.py
+++ b/sonagent/skills/skills_manager.py
@@ -1,16 +1,12 @@
 import logging
-from collections import deque
-import sys
 from pathlib import Path
-from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union
+from typing import Any, List
 
-from semantic_kernel.sk_pydantic import SKBaseModel
 import yaml
-from sonagent.skills.loading import BaseLoading
-from sonagent.skills.skills import SonSkill
 from pydantic import BaseModel
 
-from sonagent.utils.utils import hash_str, hash_md5_str
+from sonagent.skills.loading import BaseLoading
+from sonagent.utils.utils import hash_md5_str
 
 logger = logging.getLogger(__name__)
 
@@ -53,8 +49,8 @@ def get_all_skills(self) -> List[BaseModel]:
         return self.skill_object_list
     
     def search_skill_function_by_semantic_query(self, query: str, memory) -> List[BaseModel]:
-        results = memory.brain_area_search(
-            area_collection_name=self.skills_area,
+        results = memory.search(
+            collection_name=self.skills_area,
             query=query
         )
         return results
@@ -68,18 +64,28 @@ def start_skill(self, memory: Any) -> None:
 
         self.load_skills()
         self.save_skills_function_to_memory(memory=memory)
+    
+    def remove_skill_by_name(self, skill_name: str, memory: Any) -> None:
+        # clear memory collection 
+        try:
+            memory.delete_memory_collection(self.skills_area)
+        except Exception as e:
+            logger.info(f"Error deleting memory collection: {e}")
+
+        self.load_skills()
+        self.skill_object_list = [skill for skill in self.skill_object_list if skill.__doc__ != skill_name]
+        self.save_skills_function_to_memory(memory=memory)
 
     def save_skills_function_to_memory(self, memory: Any) -> None:
         logger.info("Adding skills to memory.")
         logger.info(f"Adding skills to memory. {self.skill_object_list}")
         for skill in self.skill_object_list:
             logger.info(f"Adding skill {str(skill.__doc__)} to memory: {hash_md5_str(skill.__doc__)}")
-            # skill_hash_str(skill.name())
             is_added = memory.add(
                 document=skill.__doc__,
                 metadata={'skill_description': skill.__doc__},
                 id=hash_md5_str(skill.__doc__),
-                area_collection_name=self.skills_area
+                collection_name=self.skills_area
             )
             if is_added:
                 logger.info(f"Skill {skill} added to memory.")
diff --git a/sonagent/sonbot.py b/sonagent/sonbot.py
index ed8084f..e345cb5 100644
--- a/sonagent/sonbot.py
+++ b/sonagent/sonbot.py
@@ -1,26 +1,22 @@
-import os
 import ast
 import logging
-import traceback
-from copy import deepcopy
-from datetime import datetime, time, timedelta, timezone
-from math import isclose
-from threading import Lock
-from time import sleep
-from typing import Any, Dict, List, Optional, Tuple
-
-from sonagent.mixins import LoggingMixin
+import os
+from datetime import datetime
+from typing import Any
+
+from croniter import croniter
+from schedule import Scheduler
+
+from sonagent.agent import Agent
 from sonagent.enums.enums import State
 from sonagent.enums.rpcmessagetype import RPCMessageType
-from sonagent.rpc import RPCManager, IOMsg
-from sonagent.skills.skills_manager import SkillsManager
+from sonagent.loggers.logging_mixin import LoggingMixin
 from sonagent.persistence.belief_models import Belief
-from sonagent.persistence.models import ScheduleJob
-from sonagent.agent import Agent
-from sonagent.persistence.models import init_db
-from schedule import Scheduler
-from croniter import croniter
+from sonagent.persistence.models import ScheduleJob, init_db
+from sonagent.rpc import IOMsg, RPCManager
+from sonagent.skills.skills_manager import SkillsManager
 from sonagent.utils.datetime_helpers import dt_now
+from sonagent.utils.utils import init_evironment
 
 # import threading
 
@@ -42,11 +38,10 @@ def __init__(self, config: dict, args: Any = None) -> None:
         memory_url = self.args.get('memory-url', "user_data/memory")
         agentdb = self.args.get('agentdb', "sqlite:///user_data/agentdb.sqlite")
 
-        # get openai key 
-        openai = self.config.get('openai')
-        if openai.get('api_type', None) == 'openai':
-            os.environ["OPENAI_API_KEY"] = openai.get('api_key')
-            print("----------------")
+        llm = self.config.get('llm')
+        if llm.get('api_type', None) == 'openai':
+            os.environ["OPENAI_API_KEY"] = llm.get('api_key')
+            logger.info("Run with openai LLM")
 
         if agentdb is None:
             agentdb = "sqlite:///user_data/agentdb.sqlite"
@@ -58,7 +53,10 @@ def __init__(self, config: dict, args: Any = None) -> None:
         except Exception as e:
             logger.error(f"Error initializing database: {e}")
             raise e
-        
+
+        # init env 
+        init_evironment()
+
         self.skills = SkillsManager(self)
 
         names = str(self.skills.load_register_skills_name())
@@ -95,7 +93,7 @@ def update_schedule_jobs(self) -> None:
             for job in job_list:
                 # job.run()
                 job_dict = ast.literal_eval(job.plan)
-                result = self.agent.execute_plan(job_dict)
+                self.agent.execute_plan(job_dict)
                 if job.is_recurring:
                     cron_expression = job.schedule_interval
 
@@ -120,7 +118,12 @@ async def chat(self, input: str) -> str:
                 logger.error(f"Error notifying chat event: {e}")
             return chat
         else:
-            return await self.agent.chat_code(input)
+            code_chat = await self.agent.chat_code(input)
+            try:
+                self.notify_chat_event(code_chat)
+            except Exception as e:
+                logger.error(f"Error notifying code chat event: {e}")
+            return code_chat
     
     async def get_mode(self) -> str:
         return self.agent_mode
@@ -155,6 +158,15 @@ async def show_plan(self) -> str:
     async def show_schedule(self) -> str:
         return await self.agent.show_schedule()
     
+    async def show_env(self) -> list:
+        return await self.agent.show_env()
+    
+    async def remove_env(self, key: str) -> str:
+        return await self.agent.remove_env(key)
+    
+    async def add_env(self, key: str, value: str, description: str) -> str:
+        return await self.agent.add_env(key, value, description)
+    
     def show_skills(self) -> str:
         return self.agent.show_skills()
     
@@ -218,4 +230,4 @@ def notify_status(self, msg: str, msg_type=RPCMessageType.STATUS) -> None:
         self.rpc.send_msg({
             'type': msg_type,
             'status': msg
-        })
\ No newline at end of file
+        })
diff --git a/sonagent/tools/__init__.py b/sonagent/tools/__init__.py
index 0016ea7..2f583cf 100644
--- a/sonagent/tools/__init__.py
+++ b/sonagent/tools/__init__.py
@@ -1,2 +1,7 @@
+from sonagent.tools.embedding.embedding import Embedding  # noqa: F401
+from sonagent.tools.embedding.openai_embedding import \
+    OAIEmbedding  # noqa: F401
 from sonagent.tools.git_manager import GitManager  # noqa: F401
 from sonagent.tools.local_code_manager import LocalCodeManager  # noqa: F401
+from sonagent.tools.vector_database.chromadb import ChromaDB  # noqa: F401
+from sonagent.tools.vector_database.vectordb import VectorDB  # noqa: F401
diff --git a/sonagent/tools/code_manager.py b/sonagent/tools/code_manager.py
index 6498e5e..60d5d47 100644
--- a/sonagent/tools/code_manager.py
+++ b/sonagent/tools/code_manager.py
@@ -1,9 +1,4 @@
 import logging
-import requests
-import git
-import shutil
-import os
-from pathlib import Path
 from abc import ABC, abstractmethod
 
 logger = logging.getLogger(__name__)
diff --git a/sonagent/tools/embedding/__init__.py b/sonagent/tools/embedding/__init__.py
new file mode 100644
index 0000000..011e2c8
--- /dev/null
+++ b/sonagent/tools/embedding/__init__.py
@@ -0,0 +1,2 @@
+from sonagent.tools.embedding.embedding import Embedding  # noqa
+from sonagent.tools.embedding.openai_embedding import OAIEmbedding  # noqa
diff --git a/sonagent/tools/embedding/embedding.py b/sonagent/tools/embedding/embedding.py
new file mode 100644
index 0000000..3d32873
--- /dev/null
+++ b/sonagent/tools/embedding/embedding.py
@@ -0,0 +1,14 @@
+from abc import ABC, abstractmethod
+
+
+class Embedding(ABC):
+    def __init__(self, embedding_type):
+        self.embedding_type = embedding_type
+
+    @abstractmethod
+    def embed(self, text: str):
+        pass
+
+    @abstractmethod
+    def embed_batch(self, texts: list[str]):
+        pass
diff --git a/sonagent/tools/embedding/openai_embedding.py b/sonagent/tools/embedding/openai_embedding.py
new file mode 100644
index 0000000..7369d51
--- /dev/null
+++ b/sonagent/tools/embedding/openai_embedding.py
@@ -0,0 +1,29 @@
+import os
+
+from openai import OpenAI
+
+from sonagent.tools.embedding.embedding import Embedding
+
+
+class OAIEmbedding(Embedding):
+    def __init__(self):
+        super().__init__('openai')
+        api_key = os.environ.get('OPENAI_API_KEY')
+        self.client = OpenAI(api_key=api_key)
+
+    def embed(self, text: str):
+        response = self.client.embeddings.create(
+            input=text,
+            model="text-embedding-3-small"
+        )
+        return response.data[0].embedding
+
+    def embed_batch(self, texts):
+        result = {}
+        response = self.client.embeddings.create(
+            input=texts,
+            model="text-embedding-3-small"
+        )
+        for i, text in enumerate(texts):
+            result[text] = response.data[i].embedding
+        return result
diff --git a/sonagent/tools/git_manager.py b/sonagent/tools/git_manager.py
index f27e0e8..79925dc 100644
--- a/sonagent/tools/git_manager.py
+++ b/sonagent/tools/git_manager.py
@@ -1,9 +1,11 @@
 import logging
-import requests
-import git
-import shutil
 import os
+import shutil
 from pathlib import Path
+
+import git
+import requests
+
 from sonagent.tools.code_manager import CodeManager
 
 logger = logging.getLogger(__name__)
diff --git a/sonagent/tools/local_code_manager.py b/sonagent/tools/local_code_manager.py
index ad1e743..4d8b02e 100644
--- a/sonagent/tools/local_code_manager.py
+++ b/sonagent/tools/local_code_manager.py
@@ -1,12 +1,9 @@
 
 import logging
-import requests
-
-import shutil
 import os
 from pathlib import Path
-from sonagent.tools.code_manager import CodeManager
 
+from sonagent.tools.code_manager import CodeManager
 
 logger = logging.getLogger(__name__)
 
diff --git a/sonagent/tools/vector_database/__init__.py b/sonagent/tools/vector_database/__init__.py
new file mode 100644
index 0000000..dfa4e70
--- /dev/null
+++ b/sonagent/tools/vector_database/__init__.py
@@ -0,0 +1,1 @@
+from sonagent.tools.vector_database.vectordb import VectorDB  # noqa
diff --git a/sonagent/tools/vector_database/chromadb.py b/sonagent/tools/vector_database/chromadb.py
new file mode 100644
index 0000000..a1f423c
--- /dev/null
+++ b/sonagent/tools/vector_database/chromadb.py
@@ -0,0 +1,33 @@
+import chromadb
+
+from sonagent.tools.vector_database.vectordb import VectorDB
+
+
+class ChromaDB(VectorDB):
+    def __init__(self, host: str = "localhost", port: int = 8000):
+        super().__init__(db_path='')
+        self.client = chromadb.HttpClient(host=host, port=port)
+
+    def add(
+        self,
+        embeddings: list,
+        metadatas: list,
+        docs: list,
+        ids: list,
+        collection: str = "",
+    ):
+        collection = self.client.get_or_create_collection(name=collection)
+        collection.add(
+            embeddings=embeddings,
+            metadatas=metadatas,
+            documents=docs,
+            ids=ids,
+        )
+
+    def query(self, embedding: list, k: int, collection: str = ""):
+        collection = self.client.get_or_create_collection(name=collection)
+        result = collection.query(
+            query_embeddings=[embedding],
+            n_results=k
+        )
+        return result
diff --git a/sonagent/tools/vector_database/qdrand.py b/sonagent/tools/vector_database/qdrand.py
new file mode 100644
index 0000000..e69de29
diff --git a/sonagent/tools/vector_database/vectordb.py b/sonagent/tools/vector_database/vectordb.py
new file mode 100644
index 0000000..c1bd564
--- /dev/null
+++ b/sonagent/tools/vector_database/vectordb.py
@@ -0,0 +1,45 @@
+from abc import ABC
+
+import chromadb
+from chromadb.config import Settings
+
+
+class VectorDB(ABC):
+    def __init__(self, db_path):
+        self.client = chromadb.PersistentClient(
+            path=db_path,
+            settings=Settings(allow_reset=True)
+        )
+
+    def add(
+        self,
+        embeddings: list,
+        metadatas: list,
+        docs: list,
+        ids: list,
+        collection: str = "",
+    ):
+        collection = self.client.get_or_create_collection(name=collection)
+        collection.add(
+            embeddings=embeddings,
+            metadatas=metadatas,
+            documents=docs,
+            ids=ids,
+        )
+
+    def query(self, embedding: list, k: int, collection: str = ""):
+        collection = self.client.get_or_create_collection(name=collection)
+        result = collection.query(
+            query_embeddings=[embedding],
+            n_results=k
+        )
+        return result
+    
+    def get_collection(self, collection_name):
+        return self.client.get_collection(collection_name)
+    
+    def delete_collection(self, collection_name):
+        return self.client.delete_collection(collection_name)
+    
+    def reset(self):
+        return self.client.reset()
diff --git a/sonagent/utils/__init__.py b/sonagent/utils/__init__.py
index e69de29..b7c2394 100644
--- a/sonagent/utils/__init__.py
+++ b/sonagent/utils/__init__.py
@@ -0,0 +1,1 @@
+from sonagent.utils.utils import get_schema_from_dict  # noqa: F401
\ No newline at end of file
diff --git a/sonagent/utils/gc_setup.py b/sonagent/utils/gc_setup.py
index a3532cb..9ca5d42 100644
--- a/sonagent/utils/gc_setup.py
+++ b/sonagent/utils/gc_setup.py
@@ -2,7 +2,6 @@
 import logging
 import platform
 
-
 logger = logging.getLogger(__name__)
 
 
diff --git a/sonagent/utils/utils.py b/sonagent/utils/utils.py
index 9d8b6e4..de5a10e 100644
--- a/sonagent/utils/utils.py
+++ b/sonagent/utils/utils.py
@@ -1,4 +1,11 @@
 import hashlib
+import logging
+import os
+
+from sonagent.persistence.models import Environment
+
+logger = logging.getLogger(__name__)
+
 
 def read_text_from_file(file_path: str) -> str:
     f = open(file_path, "r")
@@ -16,7 +23,25 @@ def hash_md5_str(string: str) -> str:
     m = hashlib.md5(string.encode('UTF-8'))
     return m.hexdigest()
 
-def create_github_issue():
-    pass
 
+def get_schema_from_dict(data: dict) -> dict:
+    schema = {}
+    for key, value in data.items():
+        if isinstance(value, dict):
+            schema[key] = get_schema_from_dict(value)
+        else:
+            schema[key] = type(value).__name__
+    return schema
+
+
+def init_evironment():
+    try:
+        logger.info("Initializing environment ...")
+        envs = Environment.get_all_environment()
+        for env in envs:
+            os.environ[str(env.key)] = str(env.value)
 
+        logger.debug(os.environ)
+    except Exception as e:
+        logger.error(f"Error initializing environment: {e}")
+        raise e
diff --git a/sonagent/version.py b/sonagent/version.py
index a682442..d521168 100644
--- a/sonagent/version.py
+++ b/sonagent/version.py
@@ -1,1 +1,1 @@
-__version__ = '1.0.9'
+__version__ = '1.0.10'
diff --git a/sonagent/worker.py b/sonagent/worker.py
index f58d431..e2d9243 100644
--- a/sonagent/worker.py
+++ b/sonagent/worker.py
@@ -4,16 +4,15 @@
 from os import getpid
 from typing import Any, Callable, Dict, Optional
 
-
 import sdnotify
 
 from sonagent import __version__
-from sonagent.sonbot import SonBot
+from sonagent.constants import PROCESS_THROTTLE_SECS, RETRY_TIMEOUT
 from sonagent.enums.enums import State
 from sonagent.enums.rpcmessagetype import RPCMessageType
-from sonagent.constants import PROCESS_THROTTLE_SECS, RETRY_TIMEOUT
 from sonagent.exceptions import OperationalException, TemporaryError
-
+from sonagent.immune.immune import ImmuneSystem
+from sonagent.sonbot import SonBot
 
 logger = logging.getLogger(__name__)
 
@@ -30,10 +29,12 @@ def __init__(self, args: Dict[str, Any], config: Optional[dict] = None) -> None:
         self._init(False)
 
         self._heartbeat_msg: float = 0
+        self._immune = ImmuneSystem()
 
         # Tell systemd that we completed initialization phase
         self._notify("READY=1")
 
+        
     def _init(self, reconfig: bool) -> None:
         # Init the instance of the bot
         self.sonbot = SonBot(self._config, args=self._args)
@@ -108,6 +109,9 @@ def _worker(self, old_state: Optional[State]) -> State:
                 )
                 self._heartbeat_msg = now
 
+                # Ping Immune System for scan
+                self._immune.immune_scan()
+
         return state
 
     def _throttle(
diff --git a/user_data/config.json b/user_data/config.json
index 4fa3eb2..3a94b59 100644
--- a/user_data/config.json
+++ b/user_data/config.json
@@ -1,3 +1,4 @@
+
 {
     "initial_state": "running",
     "api_server": {
@@ -20,10 +21,29 @@
         "token": "",
         "chat_id": ""
     },
-    "openai": {
+    "llm": {
         "enabled": true,
         "api_type": "openai",
-        "api_key": ""
+        "api_key": "",
+        "params": {
+            "model": "gpt-3.5-turbo",
+            "temperature": 0.5,
+            "max_tokens": 100,
+            "top_p": 1,
+            "frequency_penalty": 0,
+            "presence_penalty": 0
+        }
+    },
+    "vector_memory": {
+        "type": "file",
+        "path": "./user_data/memory",
+        "collection": "memory",
+        "host": "localhost",
+        "port": 8000,
+        "embedding":  "openai"
+    },
+    "skills": {
+        "path": "skills/skills.yaml"
     },
     "skills_file_path": "skills/skills.yaml",
     "github": {
diff --git a/user_data/skills/TextPrinter.py b/user_data/skills/TextPrinter.py
index c5b9463..6d4b107 100644
--- a/user_data/skills/TextPrinter.py
+++ b/user_data/skills/TextPrinter.py
@@ -1,4 +1,5 @@
 from pydantic import BaseModel
+
 from sonagent.rpc import IOMsg
 
 


Test patch:
diff --git a/examples/semantic_kernel_test.ipynb b/examples/semantic_kernel_test.ipynb
deleted file mode 100644
index 780224e..0000000
--- a/examples/semantic_kernel_test.ipynb
+++ /dev/null
@@ -1,315 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Collecting semantic-kernel==0.3.15.dev0\n",
-      "  Obtaining dependency information for semantic-kernel==0.3.15.dev0 from https://files.pythonhosted.org/packages/6b/69/4cab833fe486f394d8aeac13ebc31f36fdf4bfafb0abee7b8f6638ae1231/semantic_kernel-0.3.15.dev0-py3-none-any.whl.metadata\n",
-      "  Downloading semantic_kernel-0.3.15.dev0-py3-none-any.whl.metadata (2.1 kB)\n",
-      "Collecting aiofiles<24.0.0,>=23.1.0 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for aiofiles<24.0.0,>=23.1.0 from https://files.pythonhosted.org/packages/c5/19/5af6804c4cc0fed83f47bff6e413a98a36618e7d40185cd36e69737f3b0e/aiofiles-23.2.1-py3-none-any.whl.metadata\n",
-      "  Downloading aiofiles-23.2.1-py3-none-any.whl.metadata (9.7 kB)\n",
-      "Collecting motor<4.0.0,>=3.3.1 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for motor<4.0.0,>=3.3.1 from https://files.pythonhosted.org/packages/3f/9a/1a43a329dffbd1a631c52e64c1e9c036621afdfd7f42096ae4bf2de4132b/motor-3.3.2-py3-none-any.whl.metadata\n",
-      "  Downloading motor-3.3.2-py3-none-any.whl.metadata (20 kB)\n",
-      "Collecting numpy<2.0.0,>=1.24.2 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for numpy<2.0.0,>=1.24.2 from https://files.pythonhosted.org/packages/2a/17/1fdc154e75d24d8c20c42b71bae1b5cf752453f0fc3a2504bbb810293dd1/numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl.metadata\n",
-      "  Downloading numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl.metadata (61 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m61.2/61.2 kB\u001b[0m \u001b[31m1.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hCollecting openai<0.29,>=0.27 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for openai<0.29,>=0.27 from https://files.pythonhosted.org/packages/1e/9f/385c25502f437686e4aa715969e5eaf5c2cb5e5ffa7c5cdd52f3c6ae967a/openai-0.28.1-py3-none-any.whl.metadata\n",
-      "  Downloading openai-0.28.1-py3-none-any.whl.metadata (11 kB)\n",
-      "Collecting openapi_core<0.19.0,>=0.18.0 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for openapi_core<0.19.0,>=0.18.0 from https://files.pythonhosted.org/packages/3c/b0/7e386f89c336d21577e01b77efbba60edfe1b5732124b746bc1d02efdd72/openapi_core-0.18.2-py3-none-any.whl.metadata\n",
-      "  Downloading openapi_core-0.18.2-py3-none-any.whl.metadata (6.3 kB)\n",
-      "Collecting prance<24.0.0.0,>=23.6.21.0 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for prance<24.0.0.0,>=23.6.21.0 from https://files.pythonhosted.org/packages/c9/db/4fb4901ee61274d0ab97746461fc5f2637e5d73aa73f34ee28e941a699a1/prance-23.6.21.0-py3-none-any.whl.metadata\n",
-      "  Downloading prance-23.6.21.0-py3-none-any.whl.metadata (13 kB)\n",
-      "Collecting pydantic<2 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for pydantic<2 from https://files.pythonhosted.org/packages/39/9f/ab6d19c5d3fccc1e3e0d835ac773031388802b31d93937daf878465c2ecf/pydantic-1.10.13-py3-none-any.whl.metadata\n",
-      "  Downloading pydantic-1.10.13-py3-none-any.whl.metadata (149 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m149.6/149.6 kB\u001b[0m \u001b[31m2.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hCollecting python-dotenv==1.0.0 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Using cached python_dotenv-1.0.0-py3-none-any.whl (19 kB)\n",
-      "Collecting regex<2024.0.0,>=2023.6.3 (from semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for regex<2024.0.0,>=2023.6.3 from https://files.pythonhosted.org/packages/c6/a9/d543130248a2ceba74787518aea5d4a9f9373fb09fa860283fb0afa2718b/regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl.metadata\n",
-      "  Downloading regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl.metadata (40 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m40.9/40.9 kB\u001b[0m \u001b[31m795.3 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hCollecting pymongo<5,>=4.5 (from motor<4.0.0,>=3.3.1->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for pymongo<5,>=4.5 from https://files.pythonhosted.org/packages/f0/7e/076144a8deaf9ad41411852be2d65fbb033e899bfd297975496acc5bc7be/pymongo-4.6.1-cp312-cp312-macosx_10_9_universal2.whl.metadata\n",
-      "  Downloading pymongo-4.6.1-cp312-cp312-macosx_10_9_universal2.whl.metadata (22 kB)\n",
-      "Requirement already satisfied: requests>=2.20 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0) (2.31.0)\n",
-      "Collecting tqdm (from openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for tqdm from https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl.metadata\n",
-      "  Downloading tqdm-4.66.1-py3-none-any.whl.metadata (57 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m57.6/57.6 kB\u001b[0m \u001b[31m1.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hCollecting aiohttp (from openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for aiohttp from https://files.pythonhosted.org/packages/cf/45/580b5a6abb70530cea7f6e697227c61e0001eff75d50b897a62b66c6d3b7/aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl.metadata\n",
-      "  Downloading aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl.metadata (7.4 kB)\n",
-      "Collecting asgiref<4.0.0,>=3.6.0 (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for asgiref<4.0.0,>=3.6.0 from https://files.pythonhosted.org/packages/9b/80/b9051a4a07ad231558fcd8ffc89232711b4e618c15cb7a392a17384bbeef/asgiref-3.7.2-py3-none-any.whl.metadata\n",
-      "  Downloading asgiref-3.7.2-py3-none-any.whl.metadata (9.2 kB)\n",
-      "Collecting isodate (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Downloading isodate-0.6.1-py2.py3-none-any.whl (41 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.7/41.7 kB\u001b[0m \u001b[31m4.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hRequirement already satisfied: jsonschema<5.0.0,>=4.18.0 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (4.20.0)\n",
-      "Collecting jsonschema-spec<0.3.0,>=0.2.3 (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for jsonschema-spec<0.3.0,>=0.2.3 from https://files.pythonhosted.org/packages/d9/a2/7759a4268e1d6d74559de8fb5be6c77d621b822ae64d28ab4f7467c22f63/jsonschema_spec-0.2.4-py3-none-any.whl.metadata\n",
-      "  Downloading jsonschema_spec-0.2.4-py3-none-any.whl.metadata (4.3 kB)\n",
-      "Requirement already satisfied: more-itertools in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (10.1.0)\n",
-      "Collecting openapi-schema-validator<0.7.0,>=0.6.0 (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for openapi-schema-validator<0.7.0,>=0.6.0 from https://files.pythonhosted.org/packages/b3/dc/9aefae8891454130968ff079ece851d1ae9ccf6fb7965761f47c50c04853/openapi_schema_validator-0.6.2-py3-none-any.whl.metadata\n",
-      "  Downloading openapi_schema_validator-0.6.2-py3-none-any.whl.metadata (5.3 kB)\n",
-      "Collecting openapi-spec-validator<0.8.0,>=0.7.1 (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for openapi-spec-validator<0.8.0,>=0.7.1 from https://files.pythonhosted.org/packages/2b/4d/e744fff95aaf3aeafc968d5ba7297c8cda0d1ecb8e3acd21b25adae4d835/openapi_spec_validator-0.7.1-py3-none-any.whl.metadata\n",
-      "  Downloading openapi_spec_validator-0.7.1-py3-none-any.whl.metadata (5.7 kB)\n",
-      "Collecting parse (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for parse from https://files.pythonhosted.org/packages/27/da/2c9c45c3cca6ef6ebf8b4974bf211b523ad8064a315448372f3088a2193e/parse-1.20.0-py2.py3-none-any.whl.metadata\n",
-      "  Downloading parse-1.20.0-py2.py3-none-any.whl.metadata (21 kB)\n",
-      "Collecting werkzeug (from openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for werkzeug from https://files.pythonhosted.org/packages/c3/fc/254c3e9b5feb89ff5b9076a23218dafbc99c96ac5941e900b71206e6313b/werkzeug-3.0.1-py3-none-any.whl.metadata\n",
-      "  Downloading werkzeug-3.0.1-py3-none-any.whl.metadata (4.1 kB)\n",
-      "Collecting chardet>=3.0 (from prance<24.0.0.0,>=23.6.21.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for chardet>=3.0 from https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl.metadata\n",
-      "  Downloading chardet-5.2.0-py3-none-any.whl.metadata (3.4 kB)\n",
-      "Collecting ruamel.yaml>=0.17.10 (from prance<24.0.0.0,>=23.6.21.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for ruamel.yaml>=0.17.10 from https://files.pythonhosted.org/packages/57/db/4b74a29f5fd175aea3ff0d95f8230d9bb8a54e38d963c6f96065b9e2eef3/ruamel.yaml-0.18.5-py3-none-any.whl.metadata\n",
-      "  Downloading ruamel.yaml-0.18.5-py3-none-any.whl.metadata (23 kB)\n",
-      "Requirement already satisfied: six~=1.15 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from prance<24.0.0.0,>=23.6.21.0->semantic-kernel==0.3.15.dev0) (1.16.0)\n",
-      "Requirement already satisfied: packaging>=21.3 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from prance<24.0.0.0,>=23.6.21.0->semantic-kernel==0.3.15.dev0) (23.2)\n",
-      "Requirement already satisfied: typing-extensions>=4.2.0 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from pydantic<2->semantic-kernel==0.3.15.dev0) (4.9.0)\n",
-      "Requirement already satisfied: attrs>=22.2.0 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from jsonschema<5.0.0,>=4.18.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (23.1.0)\n",
-      "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from jsonschema<5.0.0,>=4.18.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (2023.11.2)\n",
-      "Requirement already satisfied: referencing>=0.28.4 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from jsonschema<5.0.0,>=4.18.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (0.31.1)\n",
-      "Requirement already satisfied: rpds-py>=0.7.1 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from jsonschema<5.0.0,>=4.18.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (0.13.2)\n",
-      "Requirement already satisfied: PyYAML>=5.1 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from jsonschema-spec<0.3.0,>=0.2.3->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (6.0.1)\n",
-      "Collecting pathable<0.5.0,>=0.4.1 (from jsonschema-spec<0.3.0,>=0.2.3->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Downloading pathable-0.4.3-py3-none-any.whl (9.6 kB)\n",
-      "Collecting referencing>=0.28.4 (from jsonschema<5.0.0,>=4.18.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for referencing>=0.28.4 from https://files.pythonhosted.org/packages/be/8e/56d6f1e2d591f4d6cbcba446cac4a1b0dc4f584537e2071d9bcee8eeab6b/referencing-0.30.2-py3-none-any.whl.metadata\n",
-      "  Using cached referencing-0.30.2-py3-none-any.whl.metadata (2.6 kB)\n",
-      "Collecting rfc3339-validator (from openapi-schema-validator<0.7.0,>=0.6.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Downloading rfc3339_validator-0.1.4-py2.py3-none-any.whl (3.5 kB)\n",
-      "Collecting jsonschema-path<0.4.0,>=0.3.1 (from openapi-spec-validator<0.8.0,>=0.7.1->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for jsonschema-path<0.4.0,>=0.3.1 from https://files.pythonhosted.org/packages/7f/5a/f405ced79c55191e460fc6d17a14845fddf09f601e39cfcab28cc1d3ff1c/jsonschema_path-0.3.2-py3-none-any.whl.metadata\n",
-      "  Downloading jsonschema_path-0.3.2-py3-none-any.whl.metadata (4.3 kB)\n",
-      "Collecting lazy-object-proxy<2.0.0,>=1.7.1 (from openapi-spec-validator<0.8.0,>=0.7.1->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Downloading lazy-object-proxy-1.9.0.tar.gz (42 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m42.8/42.8 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25h  Installing build dependencies ... \u001b[?25ldone\n",
-      "\u001b[?25h  Getting requirements to build wheel ... \u001b[?25ldone\n",
-      "\u001b[?25h  Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n",
-      "\u001b[?25hCollecting dnspython<3.0.0,>=1.16.0 (from pymongo<5,>=4.5->motor<4.0.0,>=3.3.1->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for dnspython<3.0.0,>=1.16.0 from https://files.pythonhosted.org/packages/f6/b4/0a9bee52c50f226a3cbfb54263d02bb421c7f2adc136520729c2c689c1e5/dnspython-2.4.2-py3-none-any.whl.metadata\n",
-      "  Downloading dnspython-2.4.2-py3-none-any.whl.metadata (4.9 kB)\n",
-      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from requests>=2.20->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0) (3.3.2)\n",
-      "Requirement already satisfied: idna<4,>=2.5 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from requests>=2.20->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0) (3.6)\n",
-      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from requests>=2.20->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0) (2.1.0)\n",
-      "Requirement already satisfied: certifi>=2017.4.17 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from requests>=2.20->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0) (2023.11.17)\n",
-      "Collecting ruamel.yaml.clib>=0.2.7 (from ruamel.yaml>=0.17.10->prance<24.0.0.0,>=23.6.21.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for ruamel.yaml.clib>=0.2.7 from https://files.pythonhosted.org/packages/66/98/8de4f22bbfd9135deb3422e96d450c4bc0a57d38c25976119307d2efe0aa/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl.metadata\n",
-      "  Downloading ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl.metadata (2.2 kB)\n",
-      "Collecting multidict<7.0,>=4.5 (from aiohttp->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0)\n",
-      "  Downloading multidict-6.0.4.tar.gz (51 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m51.3/51.3 kB\u001b[0m \u001b[31m1.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25h  Installing build dependencies ... \u001b[?25ldone\n",
-      "\u001b[?25h  Getting requirements to build wheel ... \u001b[?25ldone\n",
-      "\u001b[?25h  Installing backend dependencies ... \u001b[?25ldone\n",
-      "\u001b[?25h  Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n",
-      "\u001b[?25hCollecting yarl<2.0,>=1.0 (from aiohttp->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for yarl<2.0,>=1.0 from https://files.pythonhosted.org/packages/54/99/ed3c92c38f421ba6e36caf6aa91c34118771d252dce800118fa2f44d7962/yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl.metadata\n",
-      "  Downloading yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl.metadata (31 kB)\n",
-      "Collecting frozenlist>=1.1.1 (from aiohttp->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0)\n",
-      "  Downloading frozenlist-1.4.0.tar.gz (90 kB)\n",
-      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m90.7/90.7 kB\u001b[0m \u001b[31m2.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25h  Installing build dependencies ... \u001b[?25ldone\n",
-      "\u001b[?25h  Getting requirements to build wheel ... \u001b[?25ldone\n",
-      "\u001b[?25h  Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n",
-      "\u001b[?25hCollecting aiosignal>=1.1.2 (from aiohttp->openai<0.29,>=0.27->semantic-kernel==0.3.15.dev0)\n",
-      "  Using cached aiosignal-1.3.1-py3-none-any.whl (7.6 kB)\n",
-      "Requirement already satisfied: MarkupSafe>=2.1.1 in /Users/admin/miniforge3/envs/sonagent/lib/python3.12/site-packages (from werkzeug->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0) (2.1.3)\n",
-      "INFO: pip is looking at multiple versions of jsonschema-specifications to determine which version is compatible with other requirements. This could take a while.\n",
-      "Collecting jsonschema-specifications>=2023.03.6 (from jsonschema<5.0.0,>=4.18.0->openapi_core<0.19.0,>=0.18.0->semantic-kernel==0.3.15.dev0)\n",
-      "  Obtaining dependency information for jsonschema-specifications>=2023.03.6 from https://files.pythonhosted.org/packages/20/a9/384ec45013ab883d7c2bf120f2988682986fdead973decf0bae28a4523e7/jsonschema_specifications-2023.11.1-py3-none-any.whl.metadata\n",
-      "  Downloading jsonschema_specifications-2023.11.1-py3-none-any.whl.metadata (2.8 kB)\n",
-      "  Obtaining dependency information for jsonschema-specifications>=2023.03.6 from https://files.pythonhosted.org/packages/1c/24/83349ac2189cc2435e84da3f69ba3c97314d3c0622628e55171c6798ed80/jsonschema_specifications-2023.7.1-py3-none-any.whl.metadata\n",
-      "  Using cached jsonschema_specifications-2023.7.1-py3-none-any.whl.metadata (2.8 kB)\n",
-      "Downloading semantic_kernel-0.3.15.dev0-py3-none-any.whl (200 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m200.7/200.7 kB\u001b[0m \u001b[31m2.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hDownloading aiofiles-23.2.1-py3-none-any.whl (15 kB)\n",
-      "Downloading motor-3.3.2-py3-none-any.whl (70 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m70.6/70.6 kB\u001b[0m \u001b[31m6.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mta \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hDownloading numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl (13.7 MB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m13.7/13.7 MB\u001b[0m \u001b[31m8.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
-      "\u001b[?25hDownloading openai-0.28.1-py3-none-any.whl (76 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m77.0/77.0 kB\u001b[0m \u001b[31m2.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading openapi_core-0.18.2-py3-none-any.whl (82 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m82.4/82.4 kB\u001b[0m \u001b[31m2.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading prance-23.6.21.0-py3-none-any.whl (36 kB)\n",
-      "Downloading pydantic-1.10.13-py3-none-any.whl (158 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m158.6/158.6 kB\u001b[0m \u001b[31m4.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl (292 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m292.2/292.2 kB\u001b[0m \u001b[31m9.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading asgiref-3.7.2-py3-none-any.whl (24 kB)\n",
-      "Downloading chardet-5.2.0-py3-none-any.whl (199 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m199.4/199.4 kB\u001b[0m \u001b[31m11.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading jsonschema_spec-0.2.4-py3-none-any.whl (14 kB)\n",
-      "Downloading openapi_schema_validator-0.6.2-py3-none-any.whl (8.8 kB)\n",
-      "Downloading openapi_spec_validator-0.7.1-py3-none-any.whl (38 kB)\n",
-      "Downloading pymongo-4.6.1-cp312-cp312-macosx_10_9_universal2.whl (533 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m533.4/533.4 kB\u001b[0m \u001b[31m3.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hDownloading ruamel.yaml-0.18.5-py3-none-any.whl (116 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m116.4/116.4 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl (388 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m388.9/388.9 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hDownloading parse-1.20.0-py2.py3-none-any.whl (19 kB)\n",
-      "Downloading tqdm-4.66.1-py3-none-any.whl (78 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m78.3/78.3 kB\u001b[0m \u001b[31m3.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading werkzeug-3.0.1-py3-none-any.whl (226 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m226.7/226.7 kB\u001b[0m \u001b[31m4.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hDownloading dnspython-2.4.2-py3-none-any.whl (300 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m300.4/300.4 kB\u001b[0m \u001b[31m5.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
-      "\u001b[?25hDownloading jsonschema_path-0.3.2-py3-none-any.whl (14 kB)\n",
-      "Using cached jsonschema_specifications-2023.7.1-py3-none-any.whl (17 kB)\n",
-      "Using cached referencing-0.30.2-py3-none-any.whl (25 kB)\n",
-      "Downloading ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl (135 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m135.7/135.7 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hDownloading yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl (79 kB)\n",
-      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m79.4/79.4 kB\u001b[0m \u001b[31m2.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
-      "\u001b[?25hBuilding wheels for collected packages: frozenlist, lazy-object-proxy, multidict\n",
-      "  Building wheel for frozenlist (pyproject.toml) ... \u001b[?25ldone\n",
-      "\u001b[?25h  Created wheel for frozenlist: filename=frozenlist-1.4.0-cp312-cp312-macosx_11_0_arm64.whl size=43351 sha256=e006e8cffd27f3bdcaded9c80dffcfa63e685c24f4345dca35b303ad2b008d74\n",
-      "  Stored in directory: /Users/admin/Library/Caches/pip/wheels/f1/9c/94/9386cb0ea511a93226456388d41d35f1c24ba15a62ffd7b1ef\n",
-      "  Building wheel for lazy-object-proxy (pyproject.toml) ... \u001b[?25ldone\n",
-      "\u001b[?25h  Created wheel for lazy-object-proxy: filename=lazy_object_proxy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl size=20581 sha256=c0ca9f1a8e6a7bc024b863be74960d7e023b13361cc74ff04cc3f67263e2092c\n",
-      "  Stored in directory: /Users/admin/Library/Caches/pip/wheels/7d/51/68/bdceebf943cb8671e0202d5b0c59883aab206b7f2ed18cd287\n",
-      "  Building wheel for multidict (pyproject.toml) ... \u001b[?25ldone\n",
-      "\u001b[?25h  Created wheel for multidict: filename=multidict-6.0.4-cp312-cp312-macosx_11_0_arm64.whl size=27114 sha256=a089c166333d69e6cafb7140f58cc947193bee937ea1fc05f7e10baaecc2951d\n",
-      "  Stored in directory: /Users/admin/Library/Caches/pip/wheels/f6/d8/ff/3c14a64b8f2ab1aa94ba2888f5a988be6ab446ec5c8d1a82da\n",
-      "Successfully built frozenlist lazy-object-proxy multidict\n",
-      "Installing collected packages: parse, werkzeug, tqdm, ruamel.yaml.clib, rfc3339-validator, regex, referencing, python-dotenv, pydantic, pathable, numpy, multidict, lazy-object-proxy, isodate, frozenlist, dnspython, chardet, asgiref, aiofiles, yarl, ruamel.yaml, pymongo, jsonschema-specifications, jsonschema-spec, jsonschema-path, aiosignal, prance, motor, aiohttp, openapi-schema-validator, openai, openapi-spec-validator, openapi_core, semantic-kernel\n",
-      "  Attempting uninstall: referencing\n",
-      "    Found existing installation: referencing 0.31.1\n",
-      "    Uninstalling referencing-0.31.1:\n",
-      "      Successfully uninstalled referencing-0.31.1\n",
-      "  Attempting uninstall: jsonschema-specifications\n",
-      "    Found existing installation: jsonschema-specifications 2023.11.2\n",
-      "    Uninstalling jsonschema-specifications-2023.11.2:\n",
-      "      Successfully uninstalled jsonschema-specifications-2023.11.2\n",
-      "Successfully installed aiofiles-23.2.1 aiohttp-3.9.1 aiosignal-1.3.1 asgiref-3.7.2 chardet-5.2.0 dnspython-2.4.2 frozenlist-1.4.0 isodate-0.6.1 jsonschema-path-0.3.2 jsonschema-spec-0.2.4 jsonschema-specifications-2023.7.1 lazy-object-proxy-1.9.0 motor-3.3.2 multidict-6.0.4 numpy-1.26.2 openai-0.28.1 openapi-schema-validator-0.6.2 openapi-spec-validator-0.7.1 openapi_core-0.18.2 parse-1.20.0 pathable-0.4.3 prance-23.6.21.0 pydantic-1.10.13 pymongo-4.6.1 python-dotenv-1.0.0 referencing-0.30.2 regex-2023.10.3 rfc3339-validator-0.1.4 ruamel.yaml-0.18.5 ruamel.yaml.clib-0.2.8 semantic-kernel-0.3.15.dev0 tqdm-4.66.1 werkzeug-3.0.1 yarl-1.9.4\n"
-     ]
-    }
-   ],
-   "source": [
-    "!python -m pip install semantic-kernel==0.3.15.dev0"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import semantic_kernel as sk\n",
-    "\n",
-    "kernel = sk.Kernel()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
-    "\n",
-    "deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
-    "\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "<semantic_kernel.kernel.Kernel at 0x11d9d3110>"
-      ]
-     },
-     "execution_count": 3,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "kernel.add_chat_service(\"chat_completion\", AzureChatCompletion(deployment, endpoint, api_key))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Why did the T-Rex go to the dentist in the future? \n",
-      "Because he had a dino-cavity from eating too many time travelers!\n"
-     ]
-    }
-   ],
-   "source": [
-    "skill = kernel.import_semantic_skill_from_directory(\"/Users/admin/Desktop/SonAgent/examples\", \"FunSkill\")\n",
-    "joke_function = skill[\"Joke\"]\n",
-    "\n",
-    "print(joke_function(\"time travel to dinosaur age\"))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from semantic_kernel.kernel import Kernel\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "sonagent",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.12.0"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/tests/test_utils.py b/tests/test_utils.py
new file mode 100644
index 0000000..d78d6ee
--- /dev/null
+++ b/tests/test_utils.py
@@ -0,0 +1,5 @@
+from sonagent.utils.utils import hash_str
+
+
+def test_hash_str():
+    assert hash_str('test') == '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'