From 0ddb1dd0b5dc641ff5bc3a03e22621b07f4b712f Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:27 +0000 Subject: [PATCH 1/9] AI: improve Python file core\task_router.py --- core/task_router.py | 30 ++++++++++++++++++++++++++ core/task_router.py.bak.20260313151920 | 12 +++++++++++ 2 files changed, 42 insertions(+) create mode 100644 core/task_router.py.bak.20260313151920 diff --git a/core/task_router.py b/core/task_router.py index a9ba048..f5411e4 100644 --- a/core/task_router.py +++ b/core/task_router.py @@ -1,12 +1,42 @@ +```python class TaskRouter: + """ + A task router class that manages a queue of tasks and assigns them to agents. + """ + def __init__(self): + """ + Initializes the task router with an empty task queue. + """ + # Initialize an empty list to store tasks self.tasks = [] def submit_task(self, task): + """ + Adds a task to the task queue. + + Args: + task (str): The task to be added to the queue. + """ + # Append the task to the end of the queue self.tasks.append(task) def claim_task(self, agent_name): + """ + Claims the next task in the queue for the given agent. + + Args: + agent_name (str): The name of the agent claiming the task. + + Returns: + dict or None: A dictionary containing the agent's name and the claimed task, or None if the queue is empty. + """ + # Check if the task queue is empty if not self.tasks: + # If the queue is empty, return None return None + # Remove and return the first task from the queue task = self.tasks.pop(0) + # Return a dictionary containing the agent's name and the claimed task return {"agent": agent_name, "task": task} +``` \ No newline at end of file diff --git a/core/task_router.py.bak.20260313151920 b/core/task_router.py.bak.20260313151920 new file mode 100644 index 0000000..a9ba048 --- /dev/null +++ b/core/task_router.py.bak.20260313151920 @@ -0,0 +1,12 @@ +class TaskRouter: + def __init__(self): + self.tasks = [] + + def submit_task(self, task): + self.tasks.append(task) + + def claim_task(self, agent_name): + if not self.tasks: + return None + task = self.tasks.pop(0) + return {"agent": agent_name, "task": task} From 5abd5909598c5c866031c05f10565d1f03dacbcf Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:34 +0000 Subject: [PATCH 2/9] AI: improve Python file examples\demo.py --- examples/demo.py | 86 +++++++++++++++++++++++++++-- examples/demo.py.bak.20260313151927 | 10 ++++ 2 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 examples/demo.py.bak.20260313151927 diff --git a/examples/demo.py b/examples/demo.py index 9d27895..caf70da 100644 --- a/examples/demo.py +++ b/examples/demo.py @@ -1,10 +1,84 @@ +```python from core.task_router import TaskRouter -router = TaskRouter() +def main(): + """ + Demonstrates the usage of the TaskRouter class. + """ + # Initialize the task router + task_router = TaskRouter() -router.submit_task("analyze_market_data") -router.submit_task("generate_report") + # Submit tasks to the task router + tasks_to_submit = ["analyze_market_data", "generate_report"] + for task in tasks_to_submit: + task_router.submit_task(task) -print("Agent claim 1:", router.claim_task("analysis_agent")) -print("Agent claim 2:", router.claim_task("report_agent")) -print("Agent claim 3:", router.claim_task("idle_agent")) + # Attempt to claim tasks by agent name + agents = ["analysis_agent", "report_agent", "idle_agent"] + for agent in agents: + print(f"Agent claim {agents.index(agent) + 1}: {task_router.claim_task(agent)}") + +if __name__ == "__main__": + main() +``` + +```python +# core/task_router.py +class TaskRouter: + """ + A class responsible for routing tasks to agents. + + Attributes: + tasks (dict): A dictionary mapping task names to agent names. + """ + + def __init__(self): + """ + Initializes the task router with an empty task dictionary. + """ + self.tasks = {} + + def submit_task(self, task_name): + """ + Submits a task to the task router. + + Args: + task_name (str): The name of the task to submit. + + Returns: + None + """ + # For demonstration purposes, we'll just assign the task to the first available agent + # In a real implementation, this would likely involve more complex logic + self.tasks[task_name] = self.get_first_available_agent() + + def claim_task(self, agent_name): + """ + Attempts to claim a task by agent name. + + Args: + agent_name (str): The name of the agent attempting to claim the task. + + Returns: + str: The name of the task claimed by the agent, or None if no task is available. + """ + # For demonstration purposes, we'll just return a task name if the agent is available + # In a real implementation, this would likely involve more complex logic + if agent_name in self.tasks.values(): + for task, agent in self.tasks.items(): + if agent == agent_name: + del self.tasks[task] + return task + return None + + def get_first_available_agent(self): + """ + Returns the name of the first available agent. + + Returns: + str: The name of the first available agent. + """ + # For demonstration purposes, we'll just return the first agent in the list + # In a real implementation, this would likely involve more complex logic + return "analysis_agent" +``` \ No newline at end of file diff --git a/examples/demo.py.bak.20260313151927 b/examples/demo.py.bak.20260313151927 new file mode 100644 index 0000000..9d27895 --- /dev/null +++ b/examples/demo.py.bak.20260313151927 @@ -0,0 +1,10 @@ +from core.task_router import TaskRouter + +router = TaskRouter() + +router.submit_task("analyze_market_data") +router.submit_task("generate_report") + +print("Agent claim 1:", router.claim_task("analysis_agent")) +print("Agent claim 2:", router.claim_task("report_agent")) +print("Agent claim 3:", router.claim_task("idle_agent")) From 7ab59738d79a4c7718b15c53440f3cbc339e55f5 Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:40 +0000 Subject: [PATCH 3/9] AI: improve README README.md --- README.md | 103 +++++++++++++++++++++-------------- README.md.bak.20260313151934 | 74 +++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 README.md.bak.20260313151934 diff --git a/README.md b/README.md index 9a87550..d30f6e9 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,95 @@ # TaskMesh +================ -![License](https://img.shields.io/badge/license-Apache--2.0-blue) -![Python](https://img.shields.io/badge/python-3.9+-blue) -![Status](https://img.shields.io/badge/build-experimental-orange) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE) +[![Python](https://img.shields.io/badge/python-3.9+-blue)](https://www.python.org/) +[![Status](https://img.shields.io/badge/build-experimental-orange)](https://github.com/joshuamlamerton/taskmesh/actions) -TaskMesh is a lightweight task routing layer for AI agents. +## Overview +----------- -It allows agents to publish tasks and other agents to claim them based on capability or availability. +TaskMesh is a lightweight, open-source task routing layer designed for AI agents. It enables agents to publish tasks and other agents to claim them based on their capabilities or availability. ## Quick Start +------------- -Clone the repository and run the demo. +Get started with TaskMesh by cloning the repository and running the demo. + +### Installation ```bash git clone https://github.com/joshuamlamerton/taskmesh cd taskmesh +``` + +### Running the Demo + +```bash python examples/demo.py ``` -## Architecture +This will launch the demo, showcasing the following features: -```mermaid -flowchart TB +* Task submission +* Agent task claiming +* Task assignment by the router -A[Task Producer Agent] -B[TaskMesh Router] -C[Worker Agent 1] -D[Worker Agent 2] +## Architecture +------------- -A --> B -B --> C -B --> D -``` +TaskMesh consists of the following components: -## What it does +* **Task Producer Agent**: Publishes tasks to the TaskMesh router. +* **TaskMesh Router**: Routes tasks to available worker agents based on their capabilities or availability. +* **Worker Agent**: Claims tasks from the TaskMesh router and performs the assigned work. -The demo shows: +The following Mermaid diagram illustrates the architecture: -- a task being submitted -- agents claiming tasks -- the router assigning work +```mermaid +graph LR + A[Task Producer Agent] --> B[TaskMesh Router] + B --> C[Worker Agent 1] + B --> D[Worker Agent 2] +``` ## Repository Structure +------------------------ -```text +The TaskMesh repository is organized as follows: + +```markdown taskmesh +├── README.md +├── LICENSE +├── docs +│ └── architecture.md +├── core +│ └── task_router.py +├── examples +│ └── demo.py +``` -README.md -LICENSE +## Roadmap +------------ -docs - architecture.md +TaskMesh is currently in the experimental phase and is being developed in stages. The following roadmap outlines the planned features and milestones: -core - task_router.py +### Phase 1: Basic Task Queue -examples - demo.py -``` +* Implement a basic task queue to store and retrieve tasks. +* Agents can submit and claim tasks from the queue. -## Roadmap +### Phase 2: Capability-Based Routing + +* Introduce capability-based routing to match tasks with agents that possess the required skills. +* Agents can claim tasks based on their capabilities. -Phase 1 -Basic task queue +### Phase 3: Priority and Retry Logic -Phase 2 -Capability-based routing +* Implement priority-based task assignment to ensure critical tasks are completed first. +* Introduce retry logic to handle task failures and ensure task completion. -Phase 3 -Priority and retry logic +### Phase 4: Multi-Agent Coordination Features -Phase 4 -Multi-agent coordination features +* Develop features to enable multi-agent coordination, such as task delegation and agent collaboration. +* Enhance the TaskMesh router to manage complex task workflows and agent interactions. \ No newline at end of file diff --git a/README.md.bak.20260313151934 b/README.md.bak.20260313151934 new file mode 100644 index 0000000..9a87550 --- /dev/null +++ b/README.md.bak.20260313151934 @@ -0,0 +1,74 @@ +# TaskMesh + +![License](https://img.shields.io/badge/license-Apache--2.0-blue) +![Python](https://img.shields.io/badge/python-3.9+-blue) +![Status](https://img.shields.io/badge/build-experimental-orange) + +TaskMesh is a lightweight task routing layer for AI agents. + +It allows agents to publish tasks and other agents to claim them based on capability or availability. + +## Quick Start + +Clone the repository and run the demo. + +```bash +git clone https://github.com/joshuamlamerton/taskmesh +cd taskmesh +python examples/demo.py +``` + +## Architecture + +```mermaid +flowchart TB + +A[Task Producer Agent] +B[TaskMesh Router] +C[Worker Agent 1] +D[Worker Agent 2] + +A --> B +B --> C +B --> D +``` + +## What it does + +The demo shows: + +- a task being submitted +- agents claiming tasks +- the router assigning work + +## Repository Structure + +```text +taskmesh + +README.md +LICENSE + +docs + architecture.md + +core + task_router.py + +examples + demo.py +``` + +## Roadmap + +Phase 1 +Basic task queue + +Phase 2 +Capability-based routing + +Phase 3 +Priority and retry logic + +Phase 4 +Multi-agent coordination features From cadce547a2e13f926858b7a34908d2a3a68824c2 Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:47 +0000 Subject: [PATCH 4/9] AI: add tests tests\test_task_router.py --- tests/test_task_router.py | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/test_task_router.py diff --git a/tests/test_task_router.py b/tests/test_task_router.py new file mode 100644 index 0000000..61177b9 --- /dev/null +++ b/tests/test_task_router.py @@ -0,0 +1,78 @@ +import pytest +from your_module import TaskRouter # Import the module under test + +def test_task_router_init(): + """Test that the task router is initialized correctly.""" + router = TaskRouter() + assert router.tasks == [] + +def test_submit_task(): + """Test that tasks are added to the queue correctly.""" + router = TaskRouter() + router.submit_task("Task 1") + router.submit_task("Task 2") + assert router.tasks == ["Task 1", "Task 2"] + +def test_submit_task_multiple(): + """Test that multiple tasks can be added to the queue.""" + router = TaskRouter() + for i in range(10): + router.submit_task(f"Task {i+1}") + assert len(router.tasks) == 10 + +def test_claim_task_empty_queue(): + """Test that claiming a task from an empty queue returns None.""" + router = TaskRouter() + assert router.claim_task("Agent 1") is None + +def test_claim_task_single_task(): + """Test that claiming a task from a single-task queue returns the task.""" + router = TaskRouter() + router.submit_task("Task 1") + task = router.claim_task("Agent 1") + assert task == {"agent": "Agent 1", "task": "Task 1"} + +def test_claim_task_multiple_tasks(): + """Test that claiming tasks from a multi-task queue returns the tasks in order.""" + router = TaskRouter() + for i in range(3): + router.submit_task(f"Task {i+1}") + tasks = [] + for _ in range(3): + task = router.claim_task("Agent 1") + assert task is not None + tasks.append(task) + assert tasks == [ + {"agent": "Agent 1", "task": "Task 1"}, + {"agent": "Agent 1", "task": "Task 2"}, + {"agent": "Agent 1", "task": "Task 3"} + ] + +def test_claim_task_multiple_agents(): + """Test that claiming tasks from a multi-task queue returns the tasks in order across multiple agents.""" + router = TaskRouter() + for i in range(6): + router.submit_task(f"Task {i+1}") + tasks = [] + for i in range(3): + task = router.claim_task("Agent 1") + assert task is not None + tasks.append(task) + task = router.claim_task("Agent 2") + assert task is not None + tasks.append(task) + assert tasks == [ + {"agent": "Agent 1", "task": "Task 1"}, + {"agent": "Agent 2", "task": "Task 2"}, + {"agent": "Agent 1", "task": "Task 3"}, + {"agent": "Agent 2", "task": "Task 4"}, + {"agent": "Agent 1", "task": "Task 5"}, + {"agent": "Agent 2", "task": "Task 6"} + ] + +def test_claim_task_invalid_agent_name(): + """Test that claiming a task with an invalid agent name raises no error.""" + router = TaskRouter() + router.submit_task("Task 1") + task = router.claim_task(None) + assert task == {"agent": "Agent 1", "task": "Task 1"} \ No newline at end of file From a2e16549978bc27bb409a1638696c94df407a0ae Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:48 +0000 Subject: [PATCH 5/9] AI: add notebook experiments\data_exploration.ipynb --- experiments/data_exploration.ipynb | 130 +++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 experiments/data_exploration.ipynb diff --git a/experiments/data_exploration.ipynb b/experiments/data_exploration.ipynb new file mode 100644 index 0000000..71f8466 --- /dev/null +++ b/experiments/data_exploration.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "51fd6d65", + "metadata": {}, + "source": [ + "# Data Exploration\n", + "\n", + "This notebook performs exploratory data analysis on the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a8c6c90", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "# Configure plotting defaults\n", + "plt.style.use('seaborn-v0_8-whitegrid')\n", + "sns.set_palette('husl')\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "b40f0796", + "metadata": {}, + "source": [ + "## Load Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a4f3544", + "metadata": {}, + "outputs": [], + "source": [ + "# Replace 'data.csv' with the actual dataset path\n", + "df = pd.read_csv('data.csv')\n", + "print(f'Shape: {df.shape}')\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "d091f385", + "metadata": {}, + "source": [ + "## Dataset Statistics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17e3172e", + "metadata": {}, + "outputs": [], + "source": [ + "# Summary statistics for numeric columns\n", + "df.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93e12d89", + "metadata": {}, + "outputs": [], + "source": [ + "# Missing values per column\n", + "df.isnull().sum().sort_values(ascending=False)" + ] + }, + { + "cell_type": "markdown", + "id": "1671fbdf", + "metadata": {}, + "source": [ + "## Distributions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efa4796a", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot histograms for all numeric columns\n", + "numeric_cols = df.select_dtypes(include='number').columns\n", + "df[numeric_cols].hist(figsize=(14, 10), bins=30)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "5537ada9", + "metadata": {}, + "source": [ + "## Correlation Matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d042b4c0", + "metadata": {}, + "outputs": [], + "source": [ + "corr = df[numeric_cols].corr()\n", + "plt.figure(figsize=(10, 8))\n", + "sns.heatmap(corr, annot=True, fmt='.2f', cmap='coolwarm')\n", + "plt.title('Feature Correlation Matrix')\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} From 07ec07e7efa829396757d61f4fde6fcacde9a385 Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:48 +0000 Subject: [PATCH 6/9] AI: add notebook experiments\linear_regression.ipynb --- experiments/linear_regression.ipynb | 124 ++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 experiments/linear_regression.ipynb diff --git a/experiments/linear_regression.ipynb b/experiments/linear_regression.ipynb new file mode 100644 index 0000000..4fe16a0 --- /dev/null +++ b/experiments/linear_regression.ipynb @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a9f5f13c", + "metadata": {}, + "source": [ + "# Linear Regression Experiment\n", + "\n", + "Train a simple linear regression model and evaluate its performance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "174e750a", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.metrics import mean_squared_error, r2_score\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "2fabfe99", + "metadata": {}, + "source": [ + "## Load and Prepare Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae8c5e86", + "metadata": {}, + "outputs": [], + "source": [ + "# Replace with your dataset\n", + "df = pd.read_csv('data.csv')\n", + "print(f'Shape: {df.shape}')\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba6b065e", + "metadata": {}, + "outputs": [], + "source": [ + "# Define features and target — adapt column names to your data\n", + "feature_cols = df.select_dtypes(include='number').columns.tolist()\n", + "target_col = feature_cols.pop() # last numeric column as default target\n", + "\n", + "X = df[feature_cols].dropna()\n", + "y = df.loc[X.index, target_col]\n", + "\n", + "X_train, X_test, y_train, y_test = train_test_split(\n", + " X, y, test_size=0.2, random_state=42\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f81504b7", + "metadata": {}, + "source": [ + "## Train Model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8880a18f", + "metadata": {}, + "outputs": [], + "source": [ + "model = LinearRegression()\n", + "model.fit(X_train, y_train)\n", + "\n", + "y_pred = model.predict(X_test)\n", + "\n", + "print(f'R² Score: {r2_score(y_test, y_pred):.4f}')\n", + "print(f'RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}')" + ] + }, + { + "cell_type": "markdown", + "id": "8e355bbe", + "metadata": {}, + "source": [ + "## Predictions vs Actual" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f2bcb3d", + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(figsize=(8, 6))\n", + "plt.scatter(y_test, y_pred, alpha=0.5)\n", + "plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()],\n", + " 'r--', lw=2)\n", + "plt.xlabel('Actual')\n", + "plt.ylabel('Predicted')\n", + "plt.title('Linear Regression: Predicted vs Actual')\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} From 7b49e4ba44a1ee40fd261f67d26b26e64bce0849 Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:49 +0000 Subject: [PATCH 7/9] AI: add notebook experiments\logistic_regression.ipynb --- experiments/logistic_regression.ipynb | 124 ++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 experiments/logistic_regression.ipynb diff --git a/experiments/logistic_regression.ipynb b/experiments/logistic_regression.ipynb new file mode 100644 index 0000000..93beaf7 --- /dev/null +++ b/experiments/logistic_regression.ipynb @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "849e9e2b", + "metadata": {}, + "source": [ + "# Logistic Regression Experiment\n", + "\n", + "Train a logistic regression classifier and evaluate with common metrics." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "222e8dca", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import (\n", + " accuracy_score, classification_report, confusion_matrix, ConfusionMatrixDisplay\n", + ")\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "42a4bded", + "metadata": {}, + "source": [ + "## Load and Prepare Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "728fe175", + "metadata": {}, + "outputs": [], + "source": [ + "# Replace with your dataset\n", + "df = pd.read_csv('data.csv')\n", + "print(f'Shape: {df.shape}')\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb6cdf0b", + "metadata": {}, + "outputs": [], + "source": [ + "# Define features and target — adapt to your data\n", + "feature_cols = df.select_dtypes(include='number').columns.tolist()\n", + "target_col = feature_cols.pop() # last numeric column as default target\n", + "\n", + "X = df[feature_cols].dropna()\n", + "y = df.loc[X.index, target_col]\n", + "\n", + "X_train, X_test, y_train, y_test = train_test_split(\n", + " X, y, test_size=0.2, random_state=42\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "331b5931", + "metadata": {}, + "source": [ + "## Train Model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66faa648", + "metadata": {}, + "outputs": [], + "source": [ + "model = LogisticRegression(max_iter=1000, random_state=42)\n", + "model.fit(X_train, y_train)\n", + "\n", + "y_pred = model.predict(X_test)\n", + "\n", + "print(f'Accuracy: {accuracy_score(y_test, y_pred):.4f}')\n", + "print()\n", + "print(classification_report(y_test, y_pred))" + ] + }, + { + "cell_type": "markdown", + "id": "da3274e7", + "metadata": {}, + "source": [ + "## Confusion Matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e764915", + "metadata": {}, + "outputs": [], + "source": [ + "cm = confusion_matrix(y_test, y_pred)\n", + "disp = ConfusionMatrixDisplay(confusion_matrix=cm)\n", + "disp.plot(cmap='Blues')\n", + "plt.title('Confusion Matrix')\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} From 177b6277295b868da9ca385ff180c78ec3ef6371 Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:50 +0000 Subject: [PATCH 8/9] AI: add notebook experiments\visualization.ipynb --- experiments/visualization.ipynb | 121 ++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 experiments/visualization.ipynb diff --git a/experiments/visualization.ipynb b/experiments/visualization.ipynb new file mode 100644 index 0000000..ff7dc61 --- /dev/null +++ b/experiments/visualization.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e576b6ef", + "metadata": {}, + "source": [ + "# Data Visualization\n", + "\n", + "Generate various plots to understand the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d109f42", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "plt.style.use('seaborn-v0_8-whitegrid')\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "9314236c", + "metadata": {}, + "source": [ + "## Load Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5c4eb09", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv('data.csv')\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "8f45214f", + "metadata": {}, + "source": [ + "## Pair Plot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb16ec22", + "metadata": {}, + "outputs": [], + "source": [ + "numeric_cols = df.select_dtypes(include='number').columns[:5] # first 5 numeric\n", + "sns.pairplot(df[numeric_cols])\n", + "plt.suptitle('Pairwise Relationships', y=1.02)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "948d3a96", + "metadata": {}, + "source": [ + "## Box Plots" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5b63145", + "metadata": {}, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(1, min(4, len(numeric_cols)), figsize=(16, 4))\n", + "if not hasattr(axes, '__len__'):\n", + " axes = [axes]\n", + "for ax, col in zip(axes, numeric_cols):\n", + " sns.boxplot(y=df[col], ax=ax)\n", + " ax.set_title(col)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "323b9641", + "metadata": {}, + "source": [ + "## Value Counts for Categorical Columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1554ae61", + "metadata": {}, + "outputs": [], + "source": [ + "cat_cols = df.select_dtypes(include='object').columns\n", + "for col in cat_cols[:3]: # first 3 categorical\n", + " plt.figure(figsize=(8, 4))\n", + " df[col].value_counts().head(15).plot(kind='bar')\n", + " plt.title(f'Top values: {col}')\n", + " plt.tight_layout()\n", + " plt.show()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} From de0cff4abec86c7753f83336cc5fdcd5449c6227 Mon Sep 17 00:00:00 2001 From: Ilyas Fardaoui Date: Fri, 13 Mar 2026 15:19:53 +0000 Subject: [PATCH 9/9] AI: apply Black formatting --- tests/test_task_router.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/test_task_router.py b/tests/test_task_router.py index 61177b9..cee1bb9 100644 --- a/tests/test_task_router.py +++ b/tests/test_task_router.py @@ -1,11 +1,13 @@ import pytest from your_module import TaskRouter # Import the module under test + def test_task_router_init(): """Test that the task router is initialized correctly.""" router = TaskRouter() assert router.tasks == [] + def test_submit_task(): """Test that tasks are added to the queue correctly.""" router = TaskRouter() @@ -13,6 +15,7 @@ def test_submit_task(): router.submit_task("Task 2") assert router.tasks == ["Task 1", "Task 2"] + def test_submit_task_multiple(): """Test that multiple tasks can be added to the queue.""" router = TaskRouter() @@ -20,11 +23,13 @@ def test_submit_task_multiple(): router.submit_task(f"Task {i+1}") assert len(router.tasks) == 10 + def test_claim_task_empty_queue(): """Test that claiming a task from an empty queue returns None.""" router = TaskRouter() assert router.claim_task("Agent 1") is None + def test_claim_task_single_task(): """Test that claiming a task from a single-task queue returns the task.""" router = TaskRouter() @@ -32,6 +37,7 @@ def test_claim_task_single_task(): task = router.claim_task("Agent 1") assert task == {"agent": "Agent 1", "task": "Task 1"} + def test_claim_task_multiple_tasks(): """Test that claiming tasks from a multi-task queue returns the tasks in order.""" router = TaskRouter() @@ -45,9 +51,10 @@ def test_claim_task_multiple_tasks(): assert tasks == [ {"agent": "Agent 1", "task": "Task 1"}, {"agent": "Agent 1", "task": "Task 2"}, - {"agent": "Agent 1", "task": "Task 3"} + {"agent": "Agent 1", "task": "Task 3"}, ] + def test_claim_task_multiple_agents(): """Test that claiming tasks from a multi-task queue returns the tasks in order across multiple agents.""" router = TaskRouter() @@ -67,12 +74,13 @@ def test_claim_task_multiple_agents(): {"agent": "Agent 1", "task": "Task 3"}, {"agent": "Agent 2", "task": "Task 4"}, {"agent": "Agent 1", "task": "Task 5"}, - {"agent": "Agent 2", "task": "Task 6"} + {"agent": "Agent 2", "task": "Task 6"}, ] + def test_claim_task_invalid_agent_name(): """Test that claiming a task with an invalid agent name raises no error.""" router = TaskRouter() router.submit_task("Task 1") task = router.claim_task(None) - assert task == {"agent": "Agent 1", "task": "Task 1"} \ No newline at end of file + assert task == {"agent": "Agent 1", "task": "Task 1"}