Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ABB-Manual-Assistant/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Linamar-Vector-Bootcamp

## Applying agentic ai to robot troubleshooting.
Empty file.
67 changes: 67 additions & 0 deletions ABB-Manual-Assistant/agent_utils/memory_store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import datetime
import os
import sqlite3
import uuid


class MemoryStore:
def __init__(self, db_path="data/memory.db"):
os.makedirs(os.path.dirname(db_path), exist_ok=True)
self.conn = sqlite3.connect(db_path, check_same_thread=False)
self._init_db()

def _init_db(self):
cur = self.conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS conversations (
id TEXT PRIMARY KEY,
title TEXT,
created_at TEXT
)
""")
cur.execute("""
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id TEXT,
role TEXT,
content TEXT,
timestamp TEXT
)
""")
self.conn.commit()

def create_conversation(self, title=None):
cid = str(uuid.uuid4())
if not title:
title = f"Chat {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}"
self.conn.execute(
"INSERT INTO conversations VALUES (?, ?, ?)", (cid, title, datetime.datetime.now().isoformat())
)
self.conn.commit()
return cid

def list_conversations(self):
return self.conn.execute("SELECT id, title, created_at FROM conversations ORDER BY created_at DESC").fetchall()

def get_history(self, conversation_id, limit=100):
rows = self.conn.execute(
"SELECT role, content FROM messages WHERE conversation_id=? ORDER BY id ASC LIMIT ?",
(conversation_id, limit),
).fetchall()
return [{"role": r[0], "content": r[1]} for r in rows]

def log_message(self, conversation_id, role, content):
self.conn.execute(
"INSERT INTO messages (conversation_id, role, content, timestamp) VALUES (?, ?, ?, ?)",
(conversation_id, role, content, datetime.datetime.now().isoformat()),
)
self.conn.commit()

def rename_conversation(self, conversation_id, new_title):
self.conn.execute("UPDATE conversations SET title=? WHERE id=?", (new_title, conversation_id))
self.conn.commit()

def delete_conversation(self, conversation_id):
self.conn.execute("DELETE FROM messages WHERE conversation_id=?", (conversation_id,))
self.conn.execute("DELETE FROM conversations WHERE id=?", (conversation_id,))
self.conn.commit()
73 changes: 73 additions & 0 deletions ABB-Manual-Assistant/conversation_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# agents/conversation_manager.py
from __future__ import annotations

from typing import Any, Dict, List, Optional

from agent_utils.memory_store import MemoryStore


class ConversationManagerAgent:
"""
Minimal 'agent' wrapper around MemoryStore so other agents/tools
can call a stable interface. Keeps things simple:
- make sure a conversation exists
- append user/assistant turns
- read history
- rename/delete/list conversations
- optional: keep assistant partials in RAM; persist only on finalize
"""

def __init__(self, store: Optional[MemoryStore] = None):
self.store = store or MemoryStore()
# simple in-RAM buffer for current assistant partials per conversation
self._partials: Dict[str, str] = {}

# ---- conversation mgmt ----
def ensure_conversation(self, conversation_id: Optional[str]) -> str:
rows = self.store.list_conversations()
if not rows:
return self.store.create_conversation()
if conversation_id:
return conversation_id
# default to newest (list_conversations should return DESC by created_at)
return rows[0][0]

def list_conversations(self) -> List[Dict[str, Any]]:
rows = self.store.list_conversations()
return [{"id": r[0], "title": r[1], "created_at": r[2]} for r in rows]

def rename(self, conversation_id: str, title: str) -> Dict[str, Any]:
self.store.rename_conversation(conversation_id, title)
return {"ok": True, "conversation_id": conversation_id, "title": title}

def delete(self, conversation_id: str) -> Dict[str, Any]:
self.store.delete_conversation(conversation_id)
self._partials.pop(conversation_id, None)
return {"ok": True}

def create(self, title: Optional[str] = None) -> Dict[str, Any]:
cid = self.store.create_conversation(title)
return {"ok": True, "conversation_id": cid}

# ---- messages ----
def save_user(self, conversation_id: str, content: str) -> Dict[str, Any]:
cid = self.ensure_conversation(conversation_id)
self.store.log_message(cid, "user", content)
return {"ok": True, "conversation_id": cid}

def set_assistant_partial(self, conversation_id: str, partial_text: str) -> Dict[str, Any]:
# Keep partials in RAM for simplicity/quickness
cid = self.ensure_conversation(conversation_id)
self._partials[cid] = partial_text
return {"ok": True, "conversation_id": cid}

def finalize_assistant(self, conversation_id: str) -> Dict[str, Any]:
cid = self.ensure_conversation(conversation_id)
final_text = self._partials.pop(cid, "")
# Only persist once at the end of the stream
self.store.log_message(cid, "assistant", final_text)
return {"ok": True, "conversation_id": cid, "content_len": len(final_text)}

def get_history_messages(self, conversation_id: str, limit: int = 1000) -> List[Dict[str, Any]]:
cid = self.ensure_conversation(conversation_id)
return self.store.get_history(cid, limit=limit)
212 changes: 212 additions & 0 deletions ABB-Manual-Assistant/gitignore-2025.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*$py.class

# C extensions
*.so

# Distribution / packaging
scrape_with_LLM/
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
#poetry.toml

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
#pdm.lock
#pdm.toml
.pdm-python
.pdm-build/

# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
#pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.envrc
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Max Added
.venv_temp
scrape_with_LLM/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/

# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/

# Ruff stuff:
.ruff_cache/

# PyPI configuration file
.pypirc

# Cursor
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
# refer to https://docs.cursor.com/context/ignore-files
.cursorignore
.cursorindexingignore

# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/
Loading