From 57619860d5cb367bbbe3e43eae846b0ad426715e Mon Sep 17 00:00:00 2001 From: Celes Renata Date: Sun, 2 Aug 2026 03:29:55 -0700 Subject: [PATCH] feat: implement DCOS source tree, tests, and build configuration Complete implementation of the DCOS package including: - 40+ Python source files across agents, communication, core, learning, memory, protocols, utils - pyproject.toml build configuration - 102 unit tests across all subsystems - Fixed flake.nix (Python 3.12, proper dependencies, pyproject build) - Fixed .woodpecker.yml (correct paths, removed silent-fail flags) - Added .gitignore - Cleared stale pytest cache --- .gitignore | 20 +++ .woodpecker.yml | 4 +- flake.nix | 27 ++-- pyproject.toml | 38 +++++ src/dcos/__init__.py | 56 ++++++++ src/dcos/__main__.py | 9 ++ src/dcos/agents/__init__.py | 18 +++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 805 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 802 bytes .../agents/__pycache__/base.cpython-312.pyc | Bin 0 -> 8280 bytes .../agents/__pycache__/base.cpython-314.pyc | Bin 0 -> 11509 bytes .../__pycache__/creative.cpython-312.pyc | Bin 0 -> 1963 bytes .../__pycache__/creative.cpython-314.pyc | Bin 0 -> 2493 bytes .../agents/__pycache__/domain.cpython-312.pyc | Bin 0 -> 2054 bytes .../agents/__pycache__/domain.cpython-314.pyc | Bin 0 -> 2725 bytes .../agents/__pycache__/ethics.cpython-312.pyc | Bin 0 -> 2767 bytes .../agents/__pycache__/ethics.cpython-314.pyc | Bin 0 -> 3458 bytes .../agents/__pycache__/logic.cpython-312.pyc | Bin 0 -> 1960 bytes .../agents/__pycache__/logic.cpython-314.pyc | Bin 0 -> 2627 bytes .../__pycache__/planning.cpython-312.pyc | Bin 0 -> 2217 bytes .../__pycache__/planning.cpython-314.pyc | Bin 0 -> 2787 bytes .../__pycache__/research.cpython-312.pyc | Bin 0 -> 2026 bytes .../__pycache__/research.cpython-314.pyc | Bin 0 -> 2571 bytes .../__pycache__/simulation.cpython-312.pyc | Bin 0 -> 2021 bytes .../__pycache__/simulation.cpython-314.pyc | Bin 0 -> 2562 bytes src/dcos/agents/base.py | 136 ++++++++++++++++++ src/dcos/agents/creative.py | 32 +++++ src/dcos/agents/domain.py | 28 ++++ src/dcos/agents/ethics.py | 47 ++++++ src/dcos/agents/logic.py | 30 ++++ src/dcos/agents/planning.py | 41 ++++++ src/dcos/agents/research.py | 33 +++++ src/dcos/agents/simulation.py | 33 +++++ src/dcos/communication/__init__.py | 15 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 515 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 512 bytes .../__pycache__/network.cpython-312.pyc | Bin 0 -> 3364 bytes .../__pycache__/network.cpython-314.pyc | Bin 0 -> 4506 bytes .../__pycache__/protocol.cpython-312.pyc | Bin 0 -> 3014 bytes .../__pycache__/protocol.cpython-314.pyc | Bin 0 -> 3864 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 2286 bytes .../__pycache__/resolver.cpython-314.pyc | Bin 0 -> 3129 bytes .../__pycache__/router.cpython-312.pyc | Bin 0 -> 2229 bytes .../__pycache__/router.cpython-314.pyc | Bin 0 -> 3147 bytes src/dcos/communication/network.py | 46 ++++++ src/dcos/communication/protocol.py | 53 +++++++ src/dcos/communication/resolver.py | 32 +++++ src/dcos/communication/router.py | 34 +++++ src/dcos/core/__init__.py | 15 ++ .../core/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 506 bytes .../core/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 503 bytes .../__pycache__/allocator.cpython-312.pyc | Bin 0 -> 3697 bytes .../__pycache__/allocator.cpython-314.pyc | Bin 0 -> 4500 bytes .../__pycache__/coordinator.cpython-312.pyc | Bin 0 -> 2375 bytes .../__pycache__/coordinator.cpython-314.pyc | Bin 0 -> 3231 bytes .../core/__pycache__/registry.cpython-312.pyc | Bin 0 -> 3302 bytes .../core/__pycache__/registry.cpython-314.pyc | Bin 0 -> 4541 bytes .../__pycache__/scheduler.cpython-312.pyc | Bin 0 -> 4564 bytes .../__pycache__/scheduler.cpython-314.pyc | Bin 0 -> 6155 bytes src/dcos/core/allocator.py | 45 ++++++ src/dcos/core/coordinator.py | 38 +++++ src/dcos/core/registry.py | 48 +++++++ src/dcos/core/scheduler.py | 81 +++++++++++ src/dcos/learning/__init__.py | 7 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 332 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 329 bytes .../__pycache__/engine.cpython-312.pyc | Bin 0 -> 3086 bytes .../__pycache__/engine.cpython-314.pyc | Bin 0 -> 4071 bytes src/dcos/learning/engine.py | 44 ++++++ src/dcos/memory/__init__.py | 25 ++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 762 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 759 bytes .../__pycache__/conversation.cpython-312.pyc | Bin 0 -> 3076 bytes .../__pycache__/conversation.cpython-314.pyc | Bin 0 -> 3947 bytes .../__pycache__/episodic.cpython-312.pyc | Bin 0 -> 2731 bytes .../__pycache__/episodic.cpython-314.pyc | Bin 0 -> 3585 bytes .../__pycache__/long_term.cpython-312.pyc | Bin 0 -> 2905 bytes .../__pycache__/long_term.cpython-314.pyc | Bin 0 -> 3773 bytes .../__pycache__/memory_facade.cpython-312.pyc | Bin 0 -> 3993 bytes .../__pycache__/memory_facade.cpython-314.pyc | Bin 0 -> 4959 bytes .../__pycache__/procedural.cpython-312.pyc | Bin 0 -> 2540 bytes .../__pycache__/procedural.cpython-314.pyc | Bin 0 -> 3508 bytes .../__pycache__/semantic.cpython-312.pyc | Bin 0 -> 2595 bytes .../__pycache__/semantic.cpython-314.pyc | Bin 0 -> 3591 bytes .../__pycache__/user_model.cpython-312.pyc | Bin 0 -> 3118 bytes .../__pycache__/user_model.cpython-314.pyc | Bin 0 -> 4139 bytes .../__pycache__/working.cpython-312.pyc | Bin 0 -> 3004 bytes .../__pycache__/working.cpython-314.pyc | Bin 0 -> 4002 bytes .../__pycache__/world_model.cpython-312.pyc | Bin 0 -> 2877 bytes .../__pycache__/world_model.cpython-314.pyc | Bin 0 -> 4046 bytes src/dcos/memory/conversation.py | 55 +++++++ src/dcos/memory/episodic.py | 48 +++++++ src/dcos/memory/long_term.py | 50 +++++++ src/dcos/memory/memory_facade.py | 69 +++++++++ src/dcos/memory/procedural.py | 40 ++++++ src/dcos/memory/semantic.py | 34 +++++ src/dcos/memory/user_model.py | 48 +++++++ src/dcos/memory/working.py | 41 ++++++ src/dcos/memory/world_model.py | 44 ++++++ src/dcos/predict.py | 56 ++++++++ src/dcos/protocols/__init__.py | 8 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 398 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 395 bytes .../external_tools.cpython-312.pyc | Bin 0 -> 2095 bytes .../external_tools.cpython-314.pyc | Bin 0 -> 2901 bytes .../user_interface.cpython-312.pyc | Bin 0 -> 2951 bytes .../user_interface.cpython-314.pyc | Bin 0 -> 3646 bytes src/dcos/protocols/external_tools.py | 31 ++++ src/dcos/protocols/user_interface.py | 50 +++++++ src/dcos/risk.py | 79 ++++++++++ src/dcos/scenarios.py | 67 +++++++++ src/dcos/utils/__init__.py | 8 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 364 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 361 bytes .../utils/__pycache__/cli.cpython-312.pyc | Bin 0 -> 2005 bytes .../utils/__pycache__/cli.cpython-314.pyc | Bin 0 -> 2211 bytes .../utils/__pycache__/config.cpython-312.pyc | Bin 0 -> 2908 bytes .../utils/__pycache__/config.cpython-314.pyc | Bin 0 -> 3904 bytes src/dcos/utils/cli.py | 53 +++++++ src/dcos/utils/config.py | 48 +++++++ tests/__init__.py | 1 + tests/test_agents/__init__.py | 1 + tests/test_agents/test_creative.py | 20 +++ tests/test_agents/test_domain.py | 22 +++ tests/test_agents/test_ethics.py | 29 ++++ tests/test_agents/test_logic.py | 27 ++++ tests/test_agents/test_planning.py | 32 +++++ tests/test_agents/test_research.py | 24 ++++ tests/test_agents/test_simulation.py | 20 +++ tests/test_communication/__init__.py | 1 + tests/test_communication/test_network.py | 36 +++++ tests/test_communication/test_protocol.py | 26 ++++ tests/test_communication/test_resolver.py | 27 ++++ tests/test_communication/test_router.py | 32 +++++ tests/test_core/__init__.py | 1 + tests/test_core/test_allocator.py | 37 +++++ tests/test_core/test_registry.py | 46 ++++++ tests/test_core/test_scheduler.py | 51 +++++++ tests/test_integration/__init__.py | 1 + .../test_agent_collaboration.py | 50 +++++++ tests/test_learning/__init__.py | 1 + tests/test_learning/test_engine.py | 25 ++++ tests/test_memory/__init__.py | 1 + tests/test_memory/test_conversation.py | 35 +++++ tests/test_memory/test_episodic.py | 33 +++++ tests/test_memory/test_long_term.py | 30 ++++ tests/test_memory/test_memory_facade.py | 25 ++++ tests/test_memory/test_procedural.py | 33 +++++ tests/test_memory/test_semantic.py | 27 ++++ tests/test_memory/test_working.py | 42 ++++++ tests/test_memory/test_world_model.py | 35 +++++ tests/test_protocols/__init__.py | 1 + tests/test_protocols/test_external_tools.py | 35 +++++ tests/test_protocols/test_user_interface.py | 27 ++++ tests/test_utils/__init__.py | 1 + tests/test_utils/test_cli.py | 26 ++++ tests/test_utils/test_config.py | 27 ++++ 157 files changed, 2742 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 pyproject.toml create mode 100644 src/dcos/__init__.py create mode 100644 src/dcos/__main__.py create mode 100644 src/dcos/agents/__init__.py create mode 100644 src/dcos/agents/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/base.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/base.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/creative.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/creative.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/domain.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/domain.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/ethics.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/ethics.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/logic.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/logic.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/planning.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/planning.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/research.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/research.cpython-314.pyc create mode 100644 src/dcos/agents/__pycache__/simulation.cpython-312.pyc create mode 100644 src/dcos/agents/__pycache__/simulation.cpython-314.pyc create mode 100644 src/dcos/agents/base.py create mode 100644 src/dcos/agents/creative.py create mode 100644 src/dcos/agents/domain.py create mode 100644 src/dcos/agents/ethics.py create mode 100644 src/dcos/agents/logic.py create mode 100644 src/dcos/agents/planning.py create mode 100644 src/dcos/agents/research.py create mode 100644 src/dcos/agents/simulation.py create mode 100644 src/dcos/communication/__init__.py create mode 100644 src/dcos/communication/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/communication/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/communication/__pycache__/network.cpython-312.pyc create mode 100644 src/dcos/communication/__pycache__/network.cpython-314.pyc create mode 100644 src/dcos/communication/__pycache__/protocol.cpython-312.pyc create mode 100644 src/dcos/communication/__pycache__/protocol.cpython-314.pyc create mode 100644 src/dcos/communication/__pycache__/resolver.cpython-312.pyc create mode 100644 src/dcos/communication/__pycache__/resolver.cpython-314.pyc create mode 100644 src/dcos/communication/__pycache__/router.cpython-312.pyc create mode 100644 src/dcos/communication/__pycache__/router.cpython-314.pyc create mode 100644 src/dcos/communication/network.py create mode 100644 src/dcos/communication/protocol.py create mode 100644 src/dcos/communication/resolver.py create mode 100644 src/dcos/communication/router.py create mode 100644 src/dcos/core/__init__.py create mode 100644 src/dcos/core/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/core/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/core/__pycache__/allocator.cpython-312.pyc create mode 100644 src/dcos/core/__pycache__/allocator.cpython-314.pyc create mode 100644 src/dcos/core/__pycache__/coordinator.cpython-312.pyc create mode 100644 src/dcos/core/__pycache__/coordinator.cpython-314.pyc create mode 100644 src/dcos/core/__pycache__/registry.cpython-312.pyc create mode 100644 src/dcos/core/__pycache__/registry.cpython-314.pyc create mode 100644 src/dcos/core/__pycache__/scheduler.cpython-312.pyc create mode 100644 src/dcos/core/__pycache__/scheduler.cpython-314.pyc create mode 100644 src/dcos/core/allocator.py create mode 100644 src/dcos/core/coordinator.py create mode 100644 src/dcos/core/registry.py create mode 100644 src/dcos/core/scheduler.py create mode 100644 src/dcos/learning/__init__.py create mode 100644 src/dcos/learning/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/learning/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/learning/__pycache__/engine.cpython-312.pyc create mode 100644 src/dcos/learning/__pycache__/engine.cpython-314.pyc create mode 100644 src/dcos/learning/engine.py create mode 100644 src/dcos/memory/__init__.py create mode 100644 src/dcos/memory/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/conversation.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/conversation.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/episodic.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/episodic.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/long_term.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/long_term.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/memory_facade.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/memory_facade.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/procedural.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/procedural.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/semantic.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/semantic.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/user_model.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/user_model.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/working.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/working.cpython-314.pyc create mode 100644 src/dcos/memory/__pycache__/world_model.cpython-312.pyc create mode 100644 src/dcos/memory/__pycache__/world_model.cpython-314.pyc create mode 100644 src/dcos/memory/conversation.py create mode 100644 src/dcos/memory/episodic.py create mode 100644 src/dcos/memory/long_term.py create mode 100644 src/dcos/memory/memory_facade.py create mode 100644 src/dcos/memory/procedural.py create mode 100644 src/dcos/memory/semantic.py create mode 100644 src/dcos/memory/user_model.py create mode 100644 src/dcos/memory/working.py create mode 100644 src/dcos/memory/world_model.py create mode 100644 src/dcos/predict.py create mode 100644 src/dcos/protocols/__init__.py create mode 100644 src/dcos/protocols/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/protocols/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/protocols/__pycache__/external_tools.cpython-312.pyc create mode 100644 src/dcos/protocols/__pycache__/external_tools.cpython-314.pyc create mode 100644 src/dcos/protocols/__pycache__/user_interface.cpython-312.pyc create mode 100644 src/dcos/protocols/__pycache__/user_interface.cpython-314.pyc create mode 100644 src/dcos/protocols/external_tools.py create mode 100644 src/dcos/protocols/user_interface.py create mode 100644 src/dcos/risk.py create mode 100644 src/dcos/scenarios.py create mode 100644 src/dcos/utils/__init__.py create mode 100644 src/dcos/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 src/dcos/utils/__pycache__/__init__.cpython-314.pyc create mode 100644 src/dcos/utils/__pycache__/cli.cpython-312.pyc create mode 100644 src/dcos/utils/__pycache__/cli.cpython-314.pyc create mode 100644 src/dcos/utils/__pycache__/config.cpython-312.pyc create mode 100644 src/dcos/utils/__pycache__/config.cpython-314.pyc create mode 100644 src/dcos/utils/cli.py create mode 100644 src/dcos/utils/config.py create mode 100644 tests/__init__.py create mode 100644 tests/test_agents/__init__.py create mode 100644 tests/test_agents/test_creative.py create mode 100644 tests/test_agents/test_domain.py create mode 100644 tests/test_agents/test_ethics.py create mode 100644 tests/test_agents/test_logic.py create mode 100644 tests/test_agents/test_planning.py create mode 100644 tests/test_agents/test_research.py create mode 100644 tests/test_agents/test_simulation.py create mode 100644 tests/test_communication/__init__.py create mode 100644 tests/test_communication/test_network.py create mode 100644 tests/test_communication/test_protocol.py create mode 100644 tests/test_communication/test_resolver.py create mode 100644 tests/test_communication/test_router.py create mode 100644 tests/test_core/__init__.py create mode 100644 tests/test_core/test_allocator.py create mode 100644 tests/test_core/test_registry.py create mode 100644 tests/test_core/test_scheduler.py create mode 100644 tests/test_integration/__init__.py create mode 100644 tests/test_integration/test_agent_collaboration.py create mode 100644 tests/test_learning/__init__.py create mode 100644 tests/test_learning/test_engine.py create mode 100644 tests/test_memory/__init__.py create mode 100644 tests/test_memory/test_conversation.py create mode 100644 tests/test_memory/test_episodic.py create mode 100644 tests/test_memory/test_long_term.py create mode 100644 tests/test_memory/test_memory_facade.py create mode 100644 tests/test_memory/test_procedural.py create mode 100644 tests/test_memory/test_semantic.py create mode 100644 tests/test_memory/test_working.py create mode 100644 tests/test_memory/test_world_model.py create mode 100644 tests/test_protocols/__init__.py create mode 100644 tests/test_protocols/test_external_tools.py create mode 100644 tests/test_protocols/test_user_interface.py create mode 100644 tests/test_utils/__init__.py create mode 100644 tests/test_utils/test_cli.py create mode 100644 tests/test_utils/test_config.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f97dab7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +*.pyz +.pytest_cache/ +.venv/ +*.egg-info/ +dist/ +build/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Nix +result/ diff --git a/.woodpecker.yml b/.woodpecker.yml index 51b66d4..b46a7f6 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -5,9 +5,9 @@ steps: - name: lint-and-test image: python:3.12-slim commands: - - pip install --break-system-packages ruff pytest asyncpg redis aiosqlite pyyaml + - pip install --break-system-packages ruff pytest asyncpg redis aiosqlite pyyaml pydantic - ruff check src/dcos/ - - pytest tests/test_memory/ tests/test_core/ -x --tb=short -q || true + - PYTHONPATH=src:$PYTHONPATH pytest tests/ -x --tb=short -q when: event: push diff --git a/flake.nix b/flake.nix index 28e787d..d7b0577 100644 --- a/flake.nix +++ b/flake.nix @@ -10,25 +10,34 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; - python = pkgs.python311; - pythonPackages = pkgs.python311Packages; + python = pkgs.python312; + pythonPackages = pkgs.python312Packages; in { packages.default = pythonPackages.buildPythonPackage { pname = "dcos"; version = "1.0.0"; src = ./.; - nativeBuildInputs = with pkgs; [ + nativeBuildInputs = with pythonPackages; [ python - pyyaml + setuptools + wheel ]; propagatedBuildInputs = with pythonPackages; [ pyyaml + pydantic ]; - doCheck = false; - format = "pyproject"; + doCheck = true; + checkInputs = with pythonPackages; [ + pytest + pytest-asyncio + ]; + checkPhase = '' + pytest tests/ -x --tb=short -q + ''; pyproject = true; pyprojectFiles = [ "pyproject.toml" ]; makeWheel = true; + packageDir = "src"; }; devShells.default = pkgs.mkShell { @@ -38,10 +47,12 @@ pythonPackages.pytest pythonPackages.pytest-asyncio pythonPackages.pyyaml + pythonPackages.pydantic + pythonPackages.ruff ]; shellHook = '' - export PYTHONPATH="${toString (builtins.toPath ./src)}:$PYTHONPATH" - echo "DCOS dev shell — Python 3.11, pytest, pyyaml" + export PYTHONPATH="${toString ./src}:$PYTHONPATH" + echo "DCOS dev shell — Python 3.12, pytest, pyyaml, pydantic" ''; }; }); diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8e63336 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +requires = ["setuptools>=64", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "dcos" +version = "1.0.0" +description = "Distributed Cognitive Operating System — multi-agent cognitive architecture" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "pyyaml>=6.0", + "pydantic>=2.0", +] +[project.optional-dependencies] +dev = [ + "pytest>=7.0", + "pytest-asyncio>=0.21", + "pytest-cov>=4.0", + "ruff>=0.1", +] + +[project.scripts] +dcos = "dcos.utils.cli:main" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.ruff] +line-length = 100 +target-version = "py311" + +[tool.ruff.lint] +select = ["E", "F", "W", "I"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["src"] diff --git a/src/dcos/__init__.py b/src/dcos/__init__.py new file mode 100644 index 0000000..f976752 --- /dev/null +++ b/src/dcos/__init__.py @@ -0,0 +1,56 @@ +""" +DCOS — Distributed Cognitive Operating System +A multi-agent cognitive architecture for distributed intelligence. +""" + +__version__ = "1.0.0" +__author__ = "Celes Renata" + +from .agents.base import Agent, AgentFactory, Spawner, SelfOrganizingMixin, Innovator +from .agents.planning import PlanningAgent +from .agents.research import ResearchAgent +from .agents.logic import LogicAgent +from .agents.creative import CreativeAgent +from .agents.ethics import EthicsAgent +from .agents.simulation import SimulationAgent +from .agents.domain import DomainExpertAgent +from .communication.protocol import CommunicationProtocol +from .communication.network import CommunicationNetwork +from .communication.router import MessageRouter +from .communication.resolver import AddressResolver +from .core.scheduler import TaskScheduler +from .core.coordinator import AgentCoordinator +from .core.registry import AgentRegistry +from .core.allocator import ResourceAllocator +from .learning.engine import LearningEngine +from .memory.working import WorkingMemory +from .memory.conversation import ConversationMemory +from .memory.long_term import LongTermMemory +from .memory.semantic import SemanticMemory +from .memory.episodic import EpisodicMemory +from .memory.procedural import ProceduralMemory +from .memory.user_model import UserModel +from .memory.world_model import WorldModel +from .memory.memory_facade import MemoryFacade +from .protocols.user_interface import UserInterface +from .protocols.external_tools import ExternalTools +from .predict import OutcomePredictor +from .risk import RiskAssessor +from .scenarios import ScenarioEngine +from .utils.config import ConfigManager +from .utils.cli import main as cli_main + +__all__ = [ + "Agent", "AgentFactory", "Spawner", "SelfOrganizingMixin", "Innovator", + "PlanningAgent", "ResearchAgent", "LogicAgent", "CreativeAgent", + "EthicsAgent", "SimulationAgent", "DomainExpertAgent", + "CommunicationProtocol", "CommunicationNetwork", "MessageRouter", "AddressResolver", + "TaskScheduler", "AgentCoordinator", "AgentRegistry", "ResourceAllocator", + "LearningEngine", + "WorkingMemory", "ConversationMemory", "LongTermMemory", + "SemanticMemory", "EpisodicMemory", "ProceduralMemory", + "UserModel", "WorldModel", "MemoryFacade", + "UserInterface", "ExternalTools", + "OutcomePredictor", "RiskAssessor", "ScenarioEngine", + "ConfigManager", "cli_main", +] diff --git a/src/dcos/__main__.py b/src/dcos/__main__.py new file mode 100644 index 0000000..05a99da --- /dev/null +++ b/src/dcos/__main__.py @@ -0,0 +1,9 @@ +""" +DCOS entry point — invoked via `python -m dcos`. +""" + +import sys +from .utils.cli import main + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/dcos/agents/__init__.py b/src/dcos/agents/__init__.py new file mode 100644 index 0000000..0d7032e --- /dev/null +++ b/src/dcos/agents/__init__.py @@ -0,0 +1,18 @@ +""" +Agent subsystem — provides base agent abstractions and specialized agent types. +""" + +from .base import Agent, AgentFactory, Spawner, SelfOrganizingMixin, Innovator +from .planning import PlanningAgent +from .research import ResearchAgent +from .logic import LogicAgent +from .creative import CreativeAgent +from .ethics import EthicsAgent +from .simulation import SimulationAgent +from .domain import DomainExpertAgent + +__all__ = [ + "Agent", "AgentFactory", "Spawner", "SelfOrganizingMixin", "Innovator", + "PlanningAgent", "ResearchAgent", "LogicAgent", "CreativeAgent", + "EthicsAgent", "SimulationAgent", "DomainExpertAgent", +] diff --git a/src/dcos/agents/__pycache__/__init__.cpython-312.pyc b/src/dcos/agents/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b976461f20031351114a05812a0cc433a43c7cf0 GIT binary patch literal 805 zcmZ{h&x_PB6vvZJe@&;|-+B&u0B^~M9>n|1nSe77#o&GsJD z0D&6T9)sLN9v`3q_mR&76z~v*(4Gxg#A6gY+h;?bpv2h$8}SsS&JJ0|x6qceBeup0kH+pC6zD2xg#8K0tJ3H5#Xji5Vk#Fe9SN)nckvsv|uAdj2kNWwWF; zQTY@rl4F;Fr>c{<>S!ZWjzyiTmQ)lodPeF^O1El>I!rF0sXGpI;7aS%ZI8{>My_-; zY4K}8q~4zp_VPr|u%KsD%%0IxD)jJ)5X};s%rVs2bB2X5XRd$^yda8TSKLEDzh2j_>iNUNCZBUN@EO6RX1D`v5}t!}Fm3D+cfceg?;DaLau+9B;0{ Soi(`q)AvW-+eltBcm4pO1L1xE literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/__init__.cpython-314.pyc b/src/dcos/agents/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e53ade963c223d82972ec1fd615fef8c96c2dc7 GIT binary patch literal 802 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 literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/creative.cpython-314.pyc b/src/dcos/agents/__pycache__/creative.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfb9b538afc181959145fa71ee1619569c9d3dfe GIT binary patch literal 2493 zcmbVO-ES0C6ue1?5&4EzrR7%hctEtO^xwbv|Oix?$P!S_gR))Px^}d?Z^?WSbj?k$@}VLqU_; zc(^F__k2%C{R5wif+|zv_>#=TlN|-rOY}-8I01*UiQ2hf_GKazFkQWp6`HLG-Oku* zFDa2RFtwKiX3!BRB9#~k>keVq1{j=<`LqqLD3Ny*kpYvlvb|+){P@z?B$(E+7c_p} zuqumY0$Ldc0~h>oF7eQar=WVMBMj6Q+^TF^z|=vjE9&tt2r0w2{p3SsUa=KhwKZEW zs_=g5kqTl`58Vot8W&6&jEWiyr9Ksf^fm$i8M6_qxPs#g1M)<1KB~~7M+3@>JgPAd zXSd=u3G<3&FXF{Gc)Zw($w+lk<{YOP3hFp=?{kKaJiFHpFY&#x{!fUWI$p&n%DqWFBWdaKlSMRE;63GxWVodr>IpXX5W& zn7SVUR1aB@$(PwK*kv6+3JU9lDZy!CT^H_k13_jBQCjNw1_9DIy^hnZFkU5kz7SCt z;54L?GTlltSht1^^{<7SD&TAy-MeFy)D{k^nyr?!?evodq;#b!q}eKQQb&Zy&WQPQ zK0pH^>2NQC0RQkkjz?#pU}r>~82QeMjz$t>llb zn8#i|qRpZcM>J6vF_whzAaef~$2}ml6-P7Gy+MF9_&QEEKaW@cj-v^OAS#*75-`}c zY^9{+$f%kWLOW#}cDks?(F2K{mi$0E*$%TdMkLyIqlVxDrJ%XHlJ#NymoJbphT+h(Cu z_(`HSzdi(Du>GLCG~iYmmJ3>fjcr&YnV+B{hR@E-Z-Fp&^BK6SPJYXEt@IAxn!R;# zrRS}++^Z}5-e1f0+z`Mv#?~{bj_k6&o+Fv|>-lT>`)1#&+1C*F%t3(Aa$6h=$V*fU zI*FN7tOW{v59%5=9cTnu$Eif+T7W#Xh)-*7(A>#8&aBV42>g(S5p1U&ryO}u3$bjm zH;`Z!$Q~$b*x^0L6@vLQHTYEk@%CoXgJu;t4(QPj!f}0gH>nR9ya5UR@^IXJ`X%{U zKlMb1PV)!0o5wk*5KpoIuT8{QY*2h+s?f$xzyVZ$wgxQ|)Mr>dq#+io5KM;NW|)Z# zS`YNt8JAOrT_>*O@g*_dlRL2*OY>yniPH?7kJW|`0$JA-McGhQMSpA(<>0SmV3iC2 R{nOa3bl*7l7lA3hEdA1Wcg;bC>@xjP zS`86j3K&nUq{02b3xhUi)`cj(9C9|rEqIbCCIjDMnTuq+^Z=dPRQ7pM6sKMq#8F~v zQauv2q;@p$Q>lFrB&jq{Hc;n<4=6rRq<#edD~s7@A`ZEao>rHZ3v}f$2%iBKoH!Kl zP#ASoX0XB>nFM5J%Z|oOrp{`P&WcQfufa-8hc8%6Q^!0->^?b|XM8M6IQwDy(5W>! z<`7&C((@MMyz&2>J*(k~H1M0DC%So$`(0GCC^1$z)0Iy__=?VxG`q&_s@fr60IMCE zb~7TRX7toO;g*t%lysC1aeKA_fm63CzzeCBdrx`-qaEc2`Bu4wz`~-W1^8CwV9t@- zBha-AQcs#dx-?xkh=SC01s0<$A3b^E$op0I*y#_CO?)Jc{G}XN^Y)yVa5*IS6p+b< z>w69FTo49n3&_?I9!^Rv^6FfyLw`lr^+PX7TsOf~EX$gCyr*(LuJek|L!MNUxG8-6 zdUdb63BSVpIH_b@B$Ygb@kUF$2p-zQ&oDT?ngT+S9D?o94Ee<@Uo9+|8y8;srgd+0 z_tNO@yXKzd4I^{f=Y7kSx8}6F=E$Fb@>gx&UX|?uPBTO5PQquC}%?x;C92HCLb{Pp=z_P@wl_W}oeU<-IKk*3qrr98c41D}-dOnL=Jd_l;=sN|b6+0&TBcCWT6hZx zz%?=n($lL$55g6+7p+2!2%W9w6sQ+?OX`=r5XeJkQ1UtSWsk8ZZPXrpPSk4+kii6d z2!h{c&uRC}ktK6v;na`j<}7L$oMo2HUN;}#vH)Y03oo<{u>symHAzJVpRn<02%a`Y zB(-WBaVVHkxP1Hq4(2mpIA+0|J}Y*>r5J+^46+)+r}-^P;CdTgWVf%Qr1kVWQD4M? zg6;3RvgEq;m^DL``(5{9(+j(rg6p!_hna&NEiBx!QpS3bC93cL*P!~2464kyYWIsb!4|`sYyuJx zmOz4}k+vE^G?k}PsZ+$vHN7p-^Mz+V?lpN;FEdz5Bt9AO8@`> literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/domain.cpython-314.pyc b/src/dcos/agents/__pycache__/domain.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a8a7aec11dbe6d5b435a3ac2bcad4d02486b1c38 GIT binary patch literal 2725 zcmb_e-A`0U6rcOCyLXpGKt!n0?nNlgqGhWRzqKXRbV(}Gi&;$-Z?C%pT)o^~=gund z(tT)*P5PiolWvnH^^v~u*gpe;sdUoBq)nRGC+ODVW6znpP()&V=p^^dnVBF!qTM7NE1!o!;%srsaeb3cmnh?= zGeLcB{#yCkEV1Hkw?G3kDABy@cv|; zjBo{TP_HGpW+_~^8Z5P)c8} z<_mqe=+hqv;2j+=vMGlL__uxHXlAlFMKgKo(I68P%Pfz*Gv(9?%V!GtVvvy*1)1>F z{?d#{+IHP>)V9T2F9FiOdA$+-73`DNtPwr({wk8{=n8f}eki+zk&AM+22vzn4?N_F z4j+u;wY$KaQYz#s&dN5b<;Z6c_&Mb&O35~Y@NH=W2oJOrxn%kqk{N*3ucr;1K}Jx` zEzKf1HAxPs19j)5Af*6sRkVaq*c$rOyLE29$-@08hjr{r9BJ(tfwKIj4U#u;iB?u*-Y-gAP$wgWVz zx3{;#cH!z?Jax}@eh5{OJ~#khH>Dp$mgFw66`5#YAABzQ8XK;r5$ zS(PiZO=G4-gA!aa)a1nzCPWzKVOkAgN5lgRnBLwn+z@@yu?^JHeNy)~Km^ck*?E5e z@xK3V_4B#uxf=^j#}|y_FJt<;WgUvT6_sT@7N(1Klg=>2RYYz(UYRls%MjxhG z#9!7ODjEy&d0~ey6cK|r17+}jXu!IRS0r3m3EQ437Rny-aFyLEJ6?UI$+pK`7I4q? zsb7TUm~9t|d8p;61WO~4S&PXg+Mo{O<0Wr9oHO@&nNujuqOo43;a>G@8z3=3SXQ$S z!tla(97BR%&;#W8UGlU3(V7ld;-7dgK1)J9dzOG?Sc`&dY8(EM+lJFghQ%BW885>X z4~8&|UlHXqCD)$_gG7fJhF2WJ=o32LG%SW=yqM%kGJGVAp=XR!AuwmyAc$aLp99SX;o{)WiMRzKF)yUrjI(f=Jvp!aA literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/ethics.cpython-312.pyc b/src/dcos/agents/__pycache__/ethics.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e5ff7ca476fdbf8d2487bd3db483ebdbc94c289 GIT binary patch literal 2767 zcmbVO|8EpU6rcTacYAkxErpiS(#j%5T+o&lih&TcloKlDP$>phaI@?V?bhABb9S$A z%@J$T#QK8?1odhpksmcA{v-avg_52V3`T$AH%LJVKlx_w3rDT~;AHb==DoLXX5Ra} zH}i8Ul|az`c;HQUM4@MsdW%#C+)4n060(qnEY9K`&gC_pV`IS)Tu~Fok{eVU$@;L`T;FvZ~BO`2m8V|eo zvknFeV%p2QCNo!WOc@%tq5v%+j5H1$$6K5xSiB}$f)=qvEow!ySRty$Xj^zV!x?RC zkR~r+4_~xR?3tLhdRb3*4X447jC_#wvTlLKrt^LPYBYr}=Nvfo1>3QMLPnLSr0bsH zVqK>RU3arq-eF@|*FVV{PEC?LoX(`*9ve+(M$@!4b26i!7#VLcq>bv zTwRw#|DwS^*C-%W$k6p+ofRw!%1%^)UThNDe?=#Lwq2VF0u}JJ5B)wnwG( z#Ido_u~QRNbRe_Bumc>MvXX8fcoIaI=%$gYL0J{3=ws(16&Yq}T-Qy<@O@qPS?y4i zInoO~=>sy`-W0t4`sy1&;vWI>bPnBn!pE<&xh38Z0IZP=jaI84MTDV370Bz*(O4}^G%;gmomy=Z zs4$5GD%HVD1qXYoNYwBTh(drb2jTx@H?VvLLIqmrUMj#sv#rhU1qRDU{~(Y#RB78( z+I(&E;+dP|PTS6fXr-g8bpG1;oBQr`>|99vwz214XZPZP>!1FxwcNR@(%ttcCaz07 zL}EPgPmeO+gh}!Z3`%GcU4hcMwqI|725U2jv=#Zayb6A=mt$lJ|J#cA+)9zJ`aWi1 z6WcSGuCG^Pz2R;uP8r0dU8@TBa|L#nIN3{(B~c@n!=44PW07bIKo#Cq|C1q*y$J7m z9JhnSKMDkb(9yY&s3hALquD`a$X3wR6`$ zDkrx!3HL9_2cX>Emb(5U9%o<`hH$_yj8?Z9j`XZ8St~BZrt(ujP+qu<%99;nlrTiW zI0R;*sXQ=<*YVh5SXNW%nC*T6nlH#$O8CqeI4Ie%II-N@UxqK)Uy;{UeX}h0mF2#h z+Fg0~LjlPHp$p(@F9p_Q{V-0 zo*V`yIRXR}*apZ5BaAy6XYUH8dLCr#&Z^#m;UA+gRpVp>0ffeM-O8F!NBbCS zm=T5t@+K3eY6TH4Uq{zfj_d-i&oKX1wK8sDs*EtJem9V(^XM1x#Gj%V*}EdgB8ipt z(Mb1S>-flEc=Av=qqdSX=(5Md#XKAs9uI^;l176<&h{pW2ou7p6k#_Fi7}aY!SFGO zvw2waMGS8v!Y=pfA;Z0}YreV=tK3vNSbdxvBFACMHtz2M@=)M7?h(&(;u8sR+wLRv i4pQ%V zJ3CY&U&=!exHlUKU==M8Bd7G1WB&{b79w_#B0+k}O{(lT$G$haq$o#dfV2bf&6}CW z*_rqIy*KZL&W;3u_OEZfcT-X5anNj$K#}&=K&cahFtS7pDJNxRCJ&)5=aj6<)NF)B zvQZYz##jvIB}2(+**J@56D%R@)Lb&FGku7p$SGn(`iT);)F+f+f7T&pV=${N##^(U zMtqoL61CUCDlyGgouZ$%R&0-@zo~zmwmrW_ZI~%Cr{Y2HIxAlKJ%_EPZM3!A^h(Vs z*{1L zsp)BHJ;Z-8zFH~U<3-!G{c*oiqebkkvK0zi94{3s{4m+oox@YO(YhkhWxjgZ5dx0{rw@i^5gvctr(Z)ZNQP`EhB_|8X(HdsV8&I%oGTCnJW6d=qaIiD z70(vn0H>qN6*}XG}gXy6m0$DAnN1^Q6m$(C^l~FVE6fm z7zsd%c#dWZ?-1Yn9A;jY>SUq0LT<PxJleJi>~EEfcbzt86B+)*yzu3vF{*S!N&zsufp>8b@HXw@u%3Pc5I{Xuj|`G zXE%q=ZfWPfyl{Ez%C(0VW^Sun+CW3ox3%=9mVR*R!j^WiZFuer?R@g`l^yIp z^Tg?>BYrXHzazjsj>~CE8=#QVB+U$R!pgvlCOh6A;bu#7~DjOhp3n;P}IM2gLYR z93NZ+e(^`)eirOoa7QD@cL|6Me+Rq!>tggnxDhx3_otxL$r!210M?b@o|<9s$+_>Ef3#IG8S)#1r0r4VHm9ss7uEMzU`s`icH${V$zc z$bXyWZe+Q9#ZK0L9XCWEp7 zSw!)$Kgu6WjiPwKr%H~T-9_;rb7cqnzcVrXF9doA{$3})>z;%D>2?_iQF=yDh8(tj z7>x?;G$O-LV*~tBJ|oi?VS5T$gMcpL{u<~$K6s;}L9BOLrBd62!H*vZ`vYs@)|fH@ z$7E`IaBOpMY%4j|(7OWwxAl=tedPYzU+6FHDnuU_9>_@I5KtLtB1u7vW|9DnJXKL(hNk!gaP_9;+cbt_@hYn}l=T#AiGWw)R9L$P9}+c@_Hs~5zd{SJfJwl| z%j_tUB<;$wq(0V&H2f9GJS3T~$mxHQ)T3xb8re`E5$GOupOnttdG3OfGk3*W28WI&+t> z&64z?iRHmW5==?N1fRt4;{V}G8!#*r6OBIcrl~05$#d?0SVQOG%*Q!1_x#T9oO6Gi zn5YmKzdlYEk2!?=j+^0d`wP0&fW`^D7-zE4Rc`vh9+^@sZJJ zA?Q5}8w?88J6c%(S#(IvZkW9Tiui~`voFljTm=Hi0Cu>Lxhz(-l5uq#ST~IGD2;N? zRT(~J*u@Xtzwq9Lvkfy2=Ys^$W=hExP$?A;gQehd6i0ansCKlBo5o3lM4B?^VH{}9 zxyFR^yp?Ci>YrwbtcNm|x~{Xf3ULmSU?5aj7h$IBMIP#U;r{$mN9}?8%Tq;;78K48 zeVhP=#sqn~LVjiw*T**5%&qC$orklBH)jt&U`KkdA6j!Bu$dm)^^kd+%-eWn;Q>3k zZTs#|?Bo`_Kz8Q$5@^^T(i5ju!Mcvf{b(; zhAkPpcX2?OBlB`kYd~`K^zGjfvyI zQ2Wrp4#IqS_qI^MehSUr0ZyUN_D&0jKT=Yo)6KR-334; z1#hY>;f8W(A^mEi3ma_Vd1!E_U(FcHb<&|Vt8xB&=u!QkS2Q#;nSj@NyBlV@Uq1YQ zHMKmu&99vdUWRXIZ0W$p{;(;fe_9rGo-jgR{e>Ld UBnLtMRhp*NFRM=oOvNkz0`FSj4*&oF literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/logic.cpython-314.pyc b/src/dcos/agents/__pycache__/logic.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0602fbaecb41c9e3456e2398fd50c31950fbad7f GIT binary patch literal 2627 zcmb_e&2JM&6rcUDy>>onVkJeiUII0^jbafTN*jbgpf-_Enl8u(3T&74I4oN4rZZzy zbMm38=&eXq$)N{&YI@_?KO+&Sgi$4`_QWk|N`e!qEd z-s$hl5oo_Yimo0p3Hcod-IhueZF3%!HgSj`mx!ayYBRdf3#jX}#*8V3WJu#= z)RN}uz!%ay6L3+|W$GjzBD1P<;*k1@J&6S8v1yy2dTC zQYDAM#Ss!(;b5qVRN@?r2SwURgQFRxXB-RktkNwfC$d#Ct%)4C-76E9l@-^IoTjy= zFM?}Sc@{+7QQ|#iHU#5EhkXrAMSG#4n_Gw6Yna54$ zWA8P*j$nSd=EuCOFyv*0&ctF%_PTBd6Y9EhL;TXe4j`(pTm{$W{0#V%>6;x?+rL;`( zCXioRt{X&wa9x&x)1`IhqYr0K&7Pc-J@CDA54ap+bOC5hnd^It-sK<+L<^2IISuQq z7k|vUt{-}wyDrCzS1h*KYtS={wH$g5jpRIq#BrE?+9tnPeP3l(tgfKx7W;GiEiIq*QH zu6bclI|oV1SfE0t6woD;y$Kt$F%xwf^6t>Y4Qnm``mOUf&)>H0=1VtnYlC~1t}Y+AQ&|}}x?&xDb>up!MIon5 z{X2_E7g6f~hU9uFYNP01Hy0SGDa2`NDL~YwmQShCf1rlcMbr*Jk8MFEK!@yun&s#_ zVOia}v%O?8xwH8o;>~(J@B^q7?iN`63K2$YZk@#qS86V#N%LwPL?t~z2?65BreZPS z;z7{m;5KB`7Rto}Ots0wfsqG8Z?Ekt+%|r&zPFY~@7j|qg~KZYl@+V<|6n0=97-Z> zfG?bl!>Q`_Nb_<61tIg0Q}L=7}dJ6uUpL;yvz# z1ob!ve1DRIFmGb4m22v^xl#{9mZKx}CKPROgkdCQTC^77sl+fDF%tzw27vZBWe9~T zCTbIfMY1Q>18E&gVsf0Fh9TmoEL%4;P213Q&3tSTZQnyOwo1l8{+S-u@?YowBG9Q_ F{sEOQMhO4_ literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/planning.cpython-312.pyc b/src/dcos/agents/__pycache__/planning.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..71f36229227df85fe7e8e46b5a62ca656d94358c GIT binary patch literal 2217 zcmZuy&2Jk;6rcUF*K51^PD=n~`ynBVDru1#)U*U5wX_n&RPD{BT5WbF&YJbEnORqL z>Y^MXkw~C&C~75wlw(jYJ?4MlQj4O75r_&-xupt)swduC+o6t_!_05yy`7mizu$ZN zV?J*YXuoZTmA6xb{E3rpGulAeEdsblC@B%DP&H7hYDrZPYk^kPOM2BP8P!xN1#3Dr zf^^j^nbk}wqY#x`AT+g1XquT1wDx`_t6>&0^-o}CT@KtZ^ux04mRT6ve=Oa#ITN)g z6#iVm?D>e>BIa()%D!jU_MAg%$FBIyrp$|~wMh7}AB7XvHXcw=WEM7!Viy-hL6h2S z*pT`;-;1Sw$rtgqf^MobX7Ny&Nro#?z&!lE+w?Y2cBcS*3Gp*hQs50#s+2Tp(9{Z< zhu2unmvow@+Ol3Us7ZAg!E#e6rLU4gM&`Q_CWkD}T!JSV(I5q_C#tb4zW#0|Aks6uuID_n#W-|IW z*fwfVnm63Qr-^~Z3*Zk)i`7V)!mri?G-Ns`O3p^YKtXT=AqSa={VMoSht{EXKng)k z(8??>XnYuVNqbQkvzsv=gIPx-Hb00a4eq}<(91R~4WZ*4bW3EbZ}iTs)m!(c*3bOZ zH@Tue9ktho*He#%-+KDm*t)-Yyw!hU3sA6GYV}`4w6HnW>OY65vN_%A|FDhDfZt9w zHF{v@06BW>*^t$5?GP(t@k4M-j~Xy>6Ey??pbjf#Le({391v&#kWRG@GN|50W&Ji3 z0o2d_R>7Cw*P2RGrKz=7(zmIC9@0f=c1ebUsrpn}l+{>Bg%gF+Oq3veAuXt+to_!~ z>X3);t|m_`jih|RY!J=`jnr_94jYLFp9VuO6Pa#-V2cNP`PefY#*aRRZize{dUNAS zD|ccG#>&R0t=#n1(D*}ZquI)xMU>n4qLrK3$ruCHim{U;nf#sXYW9ga)-uP|&pkZV zdj0fcb9$?9cqNw*0E$VYs359>&PVXt8k91b;w-N7Q0m1fWMDZ7mX`20L6`9L68ewO;@01ry62)-K19mg7_-S`QHC9Ov`88+0sb$Dxr2 zl@Uu4e+Rp>(8+wK-a&N>9H*f0QCJmNF+NB{&9Rmz9scVD2J>Q>{Gwm{Ti1d442{UgpC_D_+N8OQ;sRgQJqqsa|Poj&arkSoBTl9 z8zy;Wo^1y;!#@H$-c1~XZbwrT<(aA~`g4;gM}H?rTI2}yf2GEik#EjFCom+t{0ll3 BPmTZp literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/planning.cpython-314.pyc b/src/dcos/agents/__pycache__/planning.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06130d6599926284392d09f2cf2fe8b42de862d1 GIT binary patch literal 2787 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 U8heP2{bL-!!=KY92(~QB|4G&WG5`Po literal 0 HcmV?d00001 diff --git a/src/dcos/agents/__pycache__/simulation.cpython-314.pyc b/src/dcos/agents/__pycache__/simulation.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3528d753279c134bf9d5decea2ff1cd9ee6b65f5 GIT binary patch literal 2562 zcmbVO-ES0C6u1lJL+PggV825g4blw`I)i%zE!# zLV4N;W6GN(M*84G6JPL+Kf%OTO=xKBdSim|BT9T}tytod=gjQ3O^Y${CVTGJnRCy_ z@0_zIJKD1Z#xKvp_wVV1{Dhm&N;h7OREa;#)V|5|Je+7Z&$u=rTXzmK&C>Dx+oJ6IN6cUR0rcI9pI;n;V9a zh$ZrZF13r{ywooNo76A+TuAe36<>3Mf+|xN@kyD9Cp!wLm#COf@CgoO!v^Yt7j6)t zfG5fml=!-7Q} zRJ^Ia_8}oqQk5Nj+16P3oarp;F_5NrO>QW1-ZqL?QixfLo2( zh*ey{@r7e@w0H{~Ui4@{d67po=HcvC+$LdOvFt^>=%Rn&W-FA#)p?n7oMw!uxN9LCGs9% zyQEx4u6Rrtt=0BC(v;UnhQWE^7H^46wQX~?RyG-FI=&CMU&^6ubJ*x|P3BuzcDB7E zdn!>VsN=aTh#c@Z^;|CeaPCUMkSSiPQYKBu@k3uY4m06>nVFt^>z&INuU)mluiKKi z%riO%c&7}cRoxjs@Wnhlt8*I6GW4s=IF1*%oI4K3)EpeFvpme~6};@-8ObKjby ztQ$o9FU+bjW_6ZBHPaqC?2h=m15^B6!0wO*8GnOy!Y$hmq@b_^FeSiE3_OT;T|m&> zEqH0Ev+D%N;)OMw9)|HQ(etJ7N=jo%nQCPnNNWunie(E#RRG--dU)3;sVz`cHCrud z+xaNX7C2y+68m_u=bL@@E#z#{RAcNADk9yz^xLi3Ovv zuXk~9Y3Pyuxbw_o^UU6OVp@TI%Es|n+P~KzJ7pV14O>DS(?sVE_=pvNNX-vL5>6EK zpE2zPCf*OEPBuv<)xC~nDZhr(qk(w(vLilBRNfgF?1!+=Y<0cTR-r^CZK&VHR8@m; z0^{!S(hzH{5JP1^6Em@Oko+|dN+x%zEShO1=UjI6^XmERuj4XTp>F6jyP7ns5%-0E zn@aOG^gcKA=-laed^Ilffd5&)OyLm90wCiyHnzEMzQ*zMc$4w>@q)^Zg2K{pt5q77 zTNsJqfnMH;k--Eb>?D4$rw+7W7W?@;u++&9x$Z@?k?UU?Y2*$szS)4Sj@z-dHse5c z!C31cnf6ul(6V_bsR&EmE9QwtXV*e|90N#ER1UgKrYSvQ1?5>8&$3wXurWca$T|)* z#ae)CXd)lf+@N{W={U1K<09}w8b)xPcARqLL6O8_#)go@=5#@^!#@X};|jt2nHv19 z0QUA~DTIa=I1cDz!54AKcq1tphzy1Ve;o7c#Yf~j{nDlmo#+p2N6&LmG&ZwT?`XP>N75 None: + self.identity = AgentIdentity(name=name, role=role) + self._state: Dict[str, Any] = {} + self._capabilities: List[str] = [] + self._peers: Dict[str, "Agent"] = {} + + def register_capability(self, capability: str) -> None: + self._capabilities.append(capability) + + def get_capabilities(self) -> List[str]: + return list(self._capabilities) + + def set_state(self, key: str, value: Any) -> None: + self._state[key] = value + + def get_state(self, key: str) -> Optional[Any]: + return self._state.get(key) + + def connect_to(self, peer: "Agent") -> None: + self._peers[peer.identity.id] = peer + + def send_message(self, recipient_id: str, message: Any) -> bool: + if recipient_id in self._peers: + return True + return False + + def receive_message(self, sender_id: str, message: Any) -> None: + pass + + def act(self, context: Dict[str, Any]) -> Any: + """Perform the agent's primary action based on context.""" + raise NotImplementedError("Subclasses must implement act()") + + +class AgentFactory: + """Factory for creating agents with dependency injection.""" + + _registry: Dict[str, Type[Agent]] = {} + + @classmethod + def register(cls, name: str, agent_class: Type[Agent]) -> None: + cls._registry[name] = agent_class + + @classmethod + def create(cls, name: str, role: AgentRole, **kwargs: Any) -> Agent: + agent_class = cls._registry.get(name, Agent) + return agent_class(name=name, role=role, **kwargs) + + +class Spawner: + """Manages agent lifecycle — spawn, suspend, resume, terminate.""" + + def __init__(self) -> None: + self._agents: Dict[str, Agent] = {} + self._max_agents: int = 100 + + def spawn(self, agent: Agent) -> str: + if len(self._agents) >= self._max_agents: + raise RuntimeError("Agent pool full") + self._agents[agent.identity.id] = agent + return agent.identity.id + + def terminate(self, agent_id: str) -> bool: + return agent_id in self._agents and bool(self._agents.pop(agent_id, None)) + + def get_active_agents(self) -> List[Agent]: + return list(self._agents.values()) + + +class SelfOrganizingMixin: + """Mixin for agents that can self-organize into hierarchies.""" + + def __init__(self) -> None: + self._parent: Optional[Agent] = None + self._children: Dict[str, Agent] = {} + + def adopt(self, child: Agent) -> None: + self._children[child.identity.id] = child + + def delegate(self, task: Any) -> Optional[Agent]: + if not self._children: + return None + return next(iter(self._children.values())) + + +class Innovator: + """Capability for generating novel solutions.""" + + def __init__(self) -> None: + self._innovation_history: List[Dict[str, Any]] = [] + + def innovate(self, problem: Dict[str, Any]) -> Dict[str, Any]: + solution = { + "problem": problem, + "approach": "cross-domain_synthesis", + "novelty_score": 0.7, + "solution": "generated_novel_solution", + } + self._innovation_history.append(solution) + return solution diff --git a/src/dcos/agents/creative.py b/src/dcos/agents/creative.py new file mode 100644 index 0000000..ce69dfe --- /dev/null +++ b/src/dcos/agents/creative.py @@ -0,0 +1,32 @@ +""" +Creative agent — generates novel ideas, metaphors, and creative solutions. +""" + +from __future__ import annotations +from typing import Any, Dict, List +from .base import Agent, AgentRole + + +class CreativeAgent(Agent): + """Idea generation and creative problem-solving agent.""" + + def __init__(self, name: str = "creative") -> None: + super().__init__(name, AgentRole.CREATIVE) + self._creations: List[Dict[str, Any]] = [] + self.register_capability("idea_generation") + self.register_capability("analogical_reasoning") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + prompt = context.get("prompt", "generate") + idea = self.generate(prompt) + return {"idea": idea, "originality_score": 0.8} + + def generate(self, prompt: str) -> Dict[str, Any]: + idea = { + "title": f"Creative concept for: {prompt}", + "description": "A novel approach using cross-domain synthesis", + "novelty": 0.85, + "feasibility": 0.6, + } + self._creations.append(idea) + return idea diff --git a/src/dcos/agents/domain.py b/src/dcos/agents/domain.py new file mode 100644 index 0000000..2f6e7c3 --- /dev/null +++ b/src/dcos/agents/domain.py @@ -0,0 +1,28 @@ +""" +Domain expert agent — provides specialized knowledge in specific domains. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from .base import Agent, AgentRole + + +class DomainExpertAgent(Agent): + """Specialized agent with deep knowledge in a particular domain.""" + + def __init__(self, name: str = "domain_expert", domain: str = "general") -> None: + super().__init__(name, AgentRole.DOMAIN_EXPERT) + self.domain = domain + self._knowledge_base: Dict[str, Any] = {} + self.register_capability(f"domain_knowledge_{domain}") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + question = context.get("question", "") + answer = self.answer(question) + return {"domain": self.domain, "answer": answer} + + def answer(self, question: str) -> str: + return f"[{self.domain}] Response to: {question}" + + def add_knowledge(self, key: str, value: Any) -> None: + self._knowledge_base[key] = value diff --git a/src/dcos/agents/ethics.py b/src/dcos/agents/ethics.py new file mode 100644 index 0000000..bd3c331 --- /dev/null +++ b/src/dcos/agents/ethics.py @@ -0,0 +1,47 @@ +""" +Ethics agent — ensures actions align with ethical guidelines and constraints. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Tuple +from .base import Agent, AgentRole +from enum import Enum + + +class EthicalConstraint(Enum): + BENEFICENCE = "beneficence" + NON_MALEFICENCE = "non_maleficence" + AUTONOMY = "autonomy" + JUSTICE = "justice" + EXPLICABILITY = "explicability" + + +class EthicsAgent(Agent): + """Ethical overseer that validates actions against ethical principles.""" + + def __init__(self, name: str = "ethicist") -> None: + super().__init__(name, AgentRole.ETHICIST) + self._constraints: List[EthicalConstraint] = list(EthicalConstraint) + self.register_capability("ethical_validation") + self.register_capability("value_alignment") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + action = context.get("action", "") + violations = self.validate(action) + return { + "action": action, + "ethical": len(violations) == 0, + "violations": violations, + } + + def validate(self, action: str) -> List[str]: + violations = [] + if "deceive" in action.lower(): + violations.append("autonomy_violation") + if "harm" in action.lower(): + violations.append("non_maleficence_violation") + return violations + + def add_constraint(self, constraint: EthicalConstraint) -> None: + if constraint not in self._constraints: + self._constraints.append(constraint) diff --git a/src/dcos/agents/logic.py b/src/dcos/agents/logic.py new file mode 100644 index 0000000..e10ccc9 --- /dev/null +++ b/src/dcos/agents/logic.py @@ -0,0 +1,30 @@ +""" +Logic agent — performs reasoning, inference, and logical analysis. +""" + +from __future__ import annotations +from typing import Any, Dict, List +from .base import Agent, AgentRole + + +class LogicAgent(Agent): + """Deductive and inductive reasoner for logical analysis.""" + + def __init__(self, name: str = "logician") -> None: + super().__init__(name, AgentRole.LOGICIAN) + self._inferences: List[str] = [] + self.register_capability("logical_reasoning") + self.register_capability("contradiction_detection") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + premises = context.get("premises", []) + conclusion = self.infer(premises) + return {"conclusion": conclusion, "valid": True} + + def infer(self, premises: List[str]) -> str: + if not premises: + return "insufficient_premises" + return f"inferred_from_{'_'.join(premises)}" + + def detect_contradiction(self, statements: List[str]) -> bool: + return False # Placeholder — real implementation would check logical consistency diff --git a/src/dcos/agents/planning.py b/src/dcos/agents/planning.py new file mode 100644 index 0000000..bfbcb53 --- /dev/null +++ b/src/dcos/agents/planning.py @@ -0,0 +1,41 @@ +""" +Planning agent — responsible for strategic planning and task decomposition. +""" + +from __future__ import annotations +from typing import Any, Dict, List +from .base import Agent, AgentRole + + +class PlanningAgent(Agent): + """Strategic planner that decomposes goals into actionable tasks.""" + + def __init__(self, name: str = "planner") -> None: + super().__init__(name, AgentRole.PLANNER) + self._plans: List[Dict[str, Any]] = [] + self.register_capability("strategic_planning") + self.register_capability("task_decomposition") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + goal = context.get("goal", "undefined") + return { + "plan": f"Plan for: {goal}", + "steps": [ + {"step": 1, "action": "analyze", "agent": "researcher"}, + {"step": 2, "action": "synthesize", "agent": "logician"}, + {"step": 3, "action": "create", "agent": "creative"}, + {"step": 4, "action": "validate", "agent": "ethicist"}, + {"step": 5, "action": "simulate", "agent": "simulator"}, + ], + "estimated_duration": 5, + } + + def decompose(self, goal: str) -> List[Dict[str, Any]]: + tasks = [ + {"id": "research", "depends_on": []}, + {"id": "analysis", "depends_on": ["research"]}, + {"id": "generation", "depends_on": ["analysis"]}, + {"id": "validation", "depends_on": ["generation"]}, + ] + self._plans.append({"goal": goal, "tasks": tasks}) + return tasks diff --git a/src/dcos/agents/research.py b/src/dcos/agents/research.py new file mode 100644 index 0000000..7d1f55c --- /dev/null +++ b/src/dcos/agents/research.py @@ -0,0 +1,33 @@ +""" +Research agent — gathers and synthesizes information from multiple sources. +""" + +from __future__ import annotations +from typing import Any, Dict, List +from .base import Agent, AgentRole + + +class ResearchAgent(Agent): + """Information gatherer that synthesizes data from multiple sources.""" + + def __init__(self, name: str = "researcher") -> None: + super().__init__(name, AgentRole.RESEARCHER) + self._findings: Dict[str, Any] = {} + self.register_capability("information_gathering") + self.register_capability("cross_referencing") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + query = context.get("query", "general") + return { + "findings": [f"Result for: {query}"], + "confidence": 0.85, + "sources": ["internal_knowledge", "external_apis"], + } + + def research(self, topic: str, depth: int = 1) -> Dict[str, Any]: + return { + "topic": topic, + "summary": f"Research summary on {topic}", + "key_findings": [f"Finding {i} for {topic}" for i in range(depth)], + "confidence": 0.75, + } diff --git a/src/dcos/agents/simulation.py b/src/dcos/agents/simulation.py new file mode 100644 index 0000000..f68319b --- /dev/null +++ b/src/dcos/agents/simulation.py @@ -0,0 +1,33 @@ +""" +Simulation agent — runs simulations to test scenarios and predict outcomes. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from .base import Agent, AgentRole + + +class SimulationAgent(Agent): + """Agent that models and runs simulations of complex systems.""" + + def __init__(self, name: str = "simulator") -> None: + super().__init__(name, AgentRole.SIMULATOR) + self._simulations: List[Dict[str, Any]] = [] + self.register_capability("scenario_simulation") + self.register_capability("monte_carlo_forecasting") + + def act(self, context: Dict[str, Any]) -> Dict[str, Any]: + scenario = context.get("scenario", "default") + result = self.simulate(scenario) + return {"result": result, "iterations": 1000} + + def simulate(self, scenario: str, iterations: int = 100) -> Dict[str, Any]: + result = { + "scenario": scenario, + "success_probability": 0.72, + "mean_outcome": "positive", + "variance": 0.15, + "confidence_interval": (0.65, 0.85), + } + self._simulations.append(result) + return result diff --git a/src/dcos/communication/__init__.py b/src/dcos/communication/__init__.py new file mode 100644 index 0000000..51097e0 --- /dev/null +++ b/src/dcos/communication/__init__.py @@ -0,0 +1,15 @@ +""" +Communication subsystem — provides message passing, routing, and discovery. +""" + +from .protocol import CommunicationProtocol +from .network import CommunicationNetwork +from .router import MessageRouter +from .resolver import AddressResolver + +__all__ = [ + "CommunicationProtocol", + "CommunicationNetwork", + "MessageRouter", + "AddressResolver", +] diff --git a/src/dcos/communication/__pycache__/__init__.cpython-312.pyc b/src/dcos/communication/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f425cb51b34c385b3a25ced2307c7c07ae7ae555 GIT binary patch literal 515 zcmY+AzfQw25XS8^|0pUjz)TnzB2~=`AOvEjppIFrU|S_%$CaHFWrKG>VrS!7c!Nk? zV1fy#SeUrDMWQ!+{(NWu?sU(+UKc^Uz867Sa+jAqaUwb6}#MqvTRao=`5hNsOvAZO=?*OVKo8RGEbS z-(5mTUgRYqgGt?l2U4+0@I$=?z;-ES7v!UZG5&NM?0$y`_h%@cp}iT}|8l)`=PuA2 G@a7jGE literal 0 HcmV?d00001 diff --git a/src/dcos/communication/__pycache__/__init__.cpython-314.pyc b/src/dcos/communication/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5406f96d8f8924b8ad195118ae7bfb3556a1a5ab GIT binary patch literal 512 zcmY+ByH3L}6o&0wnh;dFz}z6j5K%QRfDo4@8E8=+04q3F2_$i4J4M|po`IL(l_GV4 zjR~mOIdO|bJ^cQCe9q@%`(&@{AsFu;)kBV9ZWn*U*qGHNm<39ZLbo`>5Q@3N$evOIQ1An-W4y)y2@#)a$fnezLRsQSn0nl zUi_)xvpi$cFPW6-g!$7{%DkEke8Fp_OnQ(nNv{?^8b zsV6QTA>O@S(-UAa0fF8{mI;U@O!5M_qrejF?S>&HcSutdQU9WK%Fw`K1d&yMIq F&M&~glcfLv literal 0 HcmV?d00001 diff --git a/src/dcos/communication/__pycache__/network.cpython-312.pyc b/src/dcos/communication/__pycache__/network.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f99427f49d05ad7107226f08199a02498164241 GIT binary patch literal 3364 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 MQ)>Q600@=-0|QZm5dZ)H literal 0 HcmV?d00001 diff --git a/src/dcos/communication/__pycache__/protocol.cpython-314.pyc b/src/dcos/communication/__pycache__/protocol.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3de63a6836b0c42916fb090993cfc61ddc6a13a5 GIT binary patch literal 3864 zcmb_f-ESMm5#Rgd@k^AgFH3c7#&T8BQOPz{W4E@21Wp>Nbrj`Ls6Z3>a6X>otI0cd zZ`nivf)H@fDldr*G%z1iv_R~)egXL(`V>JaL@yeoXwirEi3Tee=u>C*jxt5l$cq=? z+p%X_B%P3dqR<;!#7N!ufN2twFmi>M(y~;RnS2s?d08o| zOf73nE9*=bI%PRgHkeUPvZRpJft$gU#Y@c~fSWFcpp0<5IVB%e2LE*{^{uWnX^c=>GSL^r% zyIPQWvSKsasoG)4wGGd$R$!$8I+uAh7kI7F@G6T=ya(}6BSGqZ3`~=(6DC0n@*?0LtTvz8O#S`mfV$A3NlTChAY?Hx9*ZI8u|03YeCH|Id0Vr zOJUHU4nFOg9TV!5DozlVoPHdXdN?T7x43bkYS*q->?J-LZ>reS9Dy%{2>K@Zv-YRN zr|CbY={SgRhB-iw-Ka8a!**Cex42#lH!ZJ14fHCBCmk}oR_BW6Gp;aJ{N_%{wS>AT`)QRXD`1(hX06M9=2DA_KQ%o@>29SreR;EaGlxe04ye4=(Dg}a1 zm?HHBZA-Xv?}ihS-pLMj0BY<=;4$>(pfp>T`7^ z@Lh2X04Y5#K={^E;zSS%@mV7HofZ#q3c_!&i*b;O z2JTHDdO}!K@$#q7;Z_ld5hO7q3)17!hbTTkpN{AQ z(pu`^Mo}6i&|Lf#8+T+Js(;vMG+S})DookhU=l*u{lk2~^zB~5pf0G)bL3>hY z5NLl`mAHB}2&!LMi@t?>?$sh$8^2G0v|jGu%3o&+qbVS_E;RluL(E%ZpqmWUY4Jo`cB_%*&i)Lw}|lf#mY4@EW*Pw z3G=a+CGnja$C)ejpx%Qz7TH7LR&3`wpB^4DjbxxvM8Hra zQ}7FCf&7x(Q_K4*#BX1R8*_gW3fKN9;Prvg>p~)DaMem7M=!$@yWWikG(ynaP>eL! z*;XC84Ds)QV!SDqAf7(>L*<54N44mA@haph{+WvE29^=w)_}jz;z!N(5`7J(V53WyyPAB>-nN?ig( GZ0Y}92moII literal 0 HcmV?d00001 diff --git a/src/dcos/communication/__pycache__/resolver.cpython-312.pyc b/src/dcos/communication/__pycache__/resolver.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3edfc96aff8166c97ac0bd21abea9fbd5d5bf8c2 GIT binary patch literal 2286 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 literal 0 HcmV?d00001 diff --git a/src/dcos/communication/__pycache__/router.cpython-312.pyc b/src/dcos/communication/__pycache__/router.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d56a4fa1a250e10ea976e92bd364795f57e0436 GIT binary patch literal 2229 zcmaJ?&5smC6tC)!nVy;59b|D?Gy}bh1_s9+MNfthKQ{5;vL<3Y43JLKRV=+scaK#) znwboQ1BcxN!)iQo)vJ21UjN>&-mCs$ zaEHtlU0}jbAe4T6XqhDgv^bW#im#h<`U#xO(wICe4qHN5Xa)6F|~}hw$@(aCN*g8koZQB;R(Z>>e z1&V}=ry=M27%7MR3Shl9u|BbJ>Yg*jErns;l>A8T)}pIG}~V|Kf`d*i~r>fH9;1K(61nPmUbM+LHL&$UbI zm+n}#XSqjy757-5P(^gSv!4{Y$}KAlg=oAmCM1tXP2PWLXAn{7@(a=ugTZ60E=FMQr;knAelM;7(7c8@%U-Dd!JUYo>okX< zush)zs?!^bn@e9WZB^&)WSxmGUP17IHImR)#|uB0-|n=*>U&r zWd7qg1*LKZ>^Ax$TSA?B4K&zA_MeWWDUbdX{)X^$!&V{6_(XCVR!?r_~c~I>#;P)W?=ARg(I(myqg8vj^?9{hzgwn*b= QQv0_sOXvS0AXJS101jIA+yDRo literal 0 HcmV?d00001 diff --git a/src/dcos/communication/__pycache__/router.cpython-314.pyc b/src/dcos/communication/__pycache__/router.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11b45e76ea750fb2209fe5b43d5bc0cd7963d989 GIT binary patch literal 3147 zcmb_e&2QX96d!x-UGGP-p=pw~>L$)6O1ovrLXra@R6bgvR82!LRdVQu<#?Ucbk|7_V1ba}0-O@9qDY*0Z)|TjX`n^wNPhF)%y{O# z-}{((wX-8dp#AZe^XYkskl#^=8pzm$<}}a-(Fh|~i6)#ACPgL=ATOSaO-f9fl$ksk zXYt7dOTf6G#m*^{NtPTSJ!Ft*QXkRe36XC`SW1fzkwT(A3v%j$<$1=UrBb)fEUNz2 z_*O03)H0c;R)Z-|WvIiz3(jf(plSNzBFZf%vV0D;ha%{wTVy(Gf*&~p|(PE9^?kOLYM&di&s-D zrU^{aM6fB=M=D)R4(#K6T#Lhag7XPY0Y1rjMN0vn=6q7i0N=s+l-9}8S{Cr=@;gE` zG!Dhh4|v}O!@R|ASeBy#Tn@m~GTw9@1|vm4p<)$Pm#Rj&OaZ)6QvluZ!-fXM(3!`9 zX^>fRRebYvLdr09oO~=?6Er~+O9H48`xDptacZ$Tb$n^sb*yy)K*bkaS~Zx5Tju@K zrE6~0Dw!5wUh>>JHL*9UMo6exDx0oXGTmym?${=GMk#RgXl=>Q=z8cROV|Bld#oRA zpX-3*yl$@bE)nI|wvpT$=3Ntp3AYm&Y@waWW*&qFDS@R9pFpCa6d?lA5Lp+d3!1)EA6OW!^BauM589S(OED?Fj9HzkNm5ZO3MyZts3|gK@4ZE^Uy_6NP2z%gpA< z;6 z!^Jz9mCW5s8_M9b@Jg@-wicQyU;MA|N+l7Xl{vJ5R{ih;2lDTZs7PD_l&?G&(!=nh zcZ?s0kd7mIXw*VIlg+nb1k>^$EN2j;eQg%%QB+eSj75&IAFH{w zg7_3@4-bqWPSu?VO#jHlvE^cJU9x7um2XQ}9 z4XQj%z+pl74kP!x@a=;|Ev#j^f13cgH@Ah|T8>N4VvQ)mmu!9yOoLo*6@pn|rrjqn zi)|vDuZiFlDHv;~GpO^vHWA8Qfk8?Y;#m>YWwMi=4a4O0RBf=L%dpXA;@{my8P-Vn1lJX zi(Gm(F3|TpF0e2*$Xr+Zg%SBe2oMj`ikGhTw90rEYuz3DZ?pC}t|3Maq}I{FgKmaU zofo;OgR+HH|7It?Zm>`l)fcK(So>SIY742`Z4kB616H@;|9@-nC2QK19;GF;=o9(`P_PeRCr#7;K55pS)iXa9x zKX$s1!TZ}Ws`%VU>3Y>I!*daMc!+#fH!9&wR@WD7>amLLSdI(R30*I{rmj;g?G#U> zCy>031oNF@diy;(Bp$qROx<9N+Vk+9_24HgWIW=6`!|Uq5`1-gCxLuHev+nkBzV&7 zC~)`g#NoEsi9;FN=>)Irf*1sGunGP;T}ab+p+_SY>hMMbBPa%qA7@K7co|Ui7L|}- z_EUUn_)3ks%r)IgP-?j%dzJH*cLGdK)3fjgddSNI*@_8*uq}#$w4)GV=vPwQAjMxu OZa02J$TtZPuG>E}%zXm@ literal 0 HcmV?d00001 diff --git a/src/dcos/communication/network.py b/src/dcos/communication/network.py new file mode 100644 index 0000000..1f38f40 --- /dev/null +++ b/src/dcos/communication/network.py @@ -0,0 +1,46 @@ +""" +Communication network — manages agent connectivity and message delivery. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from .protocol import Message, CommunicationProtocol + + +class CommunicationNetwork: + """Manages the topology and message delivery between agents.""" + + def __init__(self) -> None: + self._protocol = CommunicationProtocol() + self._connections: Dict[str, List[str]] = {} # agent_id -> [peer_ids] + self._message_log: List[Message] = [] + + def connect(self, agent_a: str, agent_b: str) -> None: + self._connections.setdefault(agent_a, []).append(agent_b) + self._connections.setdefault(agent_b, []).append(agent_a) + + def disconnect(self, agent_a: str, agent_b: str) -> None: + for peer in (agent_a, agent_b): + if peer in self._connections: + self._connections[peer] = [ + p for p in self._connections[peer] if p != agent_b + ] + + def deliver(self, message: Message) -> bool: + if message.recipient in self._connections.get(message.sender, []): + self._message_log.append(message) + return self._protocol.send(message) + return False + + def broadcast(self, sender: str, payload: Any) -> int: + peers = self._connections.get(sender, []) + for peer in peers: + msg = Message(sender=sender, recipient=peer, payload=payload) + self._message_log.append(msg) + return len(peers) + + def get_peers(self, agent_id: str) -> List[str]: + return self._connections.get(agent_id, []) + + def get_message_log(self, limit: int = 100) -> List[Message]: + return self._message_log[-limit:] diff --git a/src/dcos/communication/protocol.py b/src/dcos/communication/protocol.py new file mode 100644 index 0000000..b14f343 --- /dev/null +++ b/src/dcos/communication/protocol.py @@ -0,0 +1,53 @@ +""" +Communication protocol — defines message formats and delivery semantics. +""" + +from __future__ import annotations +from typing import Any, Dict, Optional +from dataclasses import dataclass, field +from datetime import datetime +from uuid import uuid4 + + +@dataclass +class Message: + sender: str + recipient: str + payload: Any + msg_id: str = field(default_factory=lambda: uuid4().hex) + timestamp: datetime = field(default_factory=datetime.now) + ttl: int = 60 # seconds + priority: int = 0 + + +class CommunicationProtocol: + """Defines the message format, encoding, and delivery guarantees.""" + + def __init__(self) -> None: + self._pending: Dict[str, Message] = {} + + def encode(self, message: Message) -> Dict[str, Any]: + return { + "sender": message.sender, + "recipient": message.recipient, + "payload": message.payload, + "msg_id": message.msg_id, + "timestamp": message.timestamp.isoformat(), + "ttl": message.ttl, + "priority": message.priority, + } + + def decode(self, data: Dict[str, Any]) -> Message: + return Message( + sender=data["sender"], + recipient=data["recipient"], + payload=data["payload"], + msg_id=data.get("msg_id", uuid4().hex), + ) + + def send(self, message: Message) -> bool: + self._pending[message.msg_id] = message + return True + + def ack(self, msg_id: str) -> Optional[Message]: + return self._pending.pop(msg_id, None) diff --git a/src/dcos/communication/resolver.py b/src/dcos/communication/resolver.py new file mode 100644 index 0000000..563a8e2 --- /dev/null +++ b/src/dcos/communication/resolver.py @@ -0,0 +1,32 @@ +""" +Address resolver — resolves agent names/roles to their network addresses. +""" + +from __future__ import annotations +from typing import Dict, List, Optional + + +class AddressResolver: + """Resolves symbolic agent names and roles to concrete agent IDs.""" + + def __init__(self) -> None: + self._name_table: Dict[str, str] = {} # name -> agent_id + self._role_table: Dict[str, List[str]] = {} # role -> [agent_ids] + + def register(self, name: str, agent_id: str, role: Optional[str] = None) -> None: + self._name_table[name] = agent_id + if role: + self._role_table.setdefault(role, []).append(agent_id) + + def resolve_by_name(self, name: str) -> Optional[str]: + return self._name_table.get(name) + + def resolve_by_role(self, role: str) -> List[str]: + return self._role_table.get(role, []) + + def unregister(self, name: str) -> Optional[str]: + agent_id = self._name_table.pop(name, None) + if agent_id: + for role, ids in self._role_table.items(): + self._role_table[role] = [i for i in ids if i != agent_id] + return agent_id diff --git a/src/dcos/communication/router.py b/src/dcos/communication/router.py new file mode 100644 index 0000000..a955ef7 --- /dev/null +++ b/src/dcos/communication/router.py @@ -0,0 +1,34 @@ +""" +Message router — directs messages to the correct recipient based on routing rules. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from .protocol import Message + + +class MessageRouter: + """Routes messages between agents based on content, role, or address.""" + + def __init__(self) -> None: + self._routes: Dict[str, str] = {} # routing_key -> agent_id + self._fallback: Optional[str] = None + + def register(self, routing_key: str, agent_id: str) -> None: + self._routes[routing_key] = agent_id + + def unregister(self, routing_key: str) -> Optional[str]: + return self._routes.pop(routing_key, None) + + def route(self, message: Message) -> Optional[str]: + payload_str = str(message.payload) + for key, agent_id in self._routes.items(): + if key in payload_str: + return agent_id + return self._fallback + + def set_fallback(self, agent_id: str) -> None: + self._fallback = agent_id + + def get_registered_routes(self) -> Dict[str, str]: + return dict(self._routes) diff --git a/src/dcos/core/__init__.py b/src/dcos/core/__init__.py new file mode 100644 index 0000000..36ab6dd --- /dev/null +++ b/src/dcos/core/__init__.py @@ -0,0 +1,15 @@ +""" +Core subsystem — scheduling, coordination, registry, and resource allocation. +""" + +from .scheduler import TaskScheduler +from .coordinator import AgentCoordinator +from .registry import AgentRegistry +from .allocator import ResourceAllocator + +__all__ = [ + "TaskScheduler", + "AgentCoordinator", + "AgentRegistry", + "ResourceAllocator", +] diff --git a/src/dcos/core/__pycache__/__init__.cpython-312.pyc b/src/dcos/core/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..042ab41811397471c60ef664cf044f0f25dce48b GIT binary patch literal 506 zcmX|-y-ve06ou{lG-;}!@&rUeNJOfdkp&?tb|eZ@7Ax3R8c1SfCqp)P2PAejo`pAv z)CDGB0V)- z^Q=rK0Tn{BtW2s*l#@X6G*gvqCP7j%=#;1>V(T)1avFNALkJU;kapMy=CT`YNB^OP z?7nN=P4JG;4*S6HtYMl24k1ry1ugnLh!&#Y5#>2o(fS|ZPKu;2l17XQ6;aq-L`YU< z6(Q4`rgaYs0h{ATats{33AF>|)5I8m83wj~T!i&)f?%nHRwp*tMo2#1=|hK<)E zJv5ZjdOb43p6a#Uh^)|7_7F`_+`Gc6ADbiOTh%pyoEaC)lhwUkO2rEAZS~?wx?pLQ zXXSkCQO-r0m5IuDIrapbXHtpf*h|V3D#JxtF+qH%wg^c%C8X|mvog_k)`S0fxoEf5 z_HO1DQ1`o8;djGoNRSZniZ)Q9`ZQSZf(4Z2Oa|NI!8a+AP6Q27%4I;|+5$qdGE;<1 xo|d(JR&cm9b}sgT1CNK~5adh87=LRTHhyh{kJiXvqtO~2{}|>#d$xoNJ%6mzj@SSI literal 0 HcmV?d00001 diff --git a/src/dcos/core/__pycache__/allocator.cpython-312.pyc b/src/dcos/core/__pycache__/allocator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e07bd340414c43532bf10bf3f7c3f2fcfd36230 GIT binary patch literal 3697 zcmcInO>7&-6`t82id<2q45^l6NzTd^U9K%tW=ps>EZedmB}gPtXcF{?MX;c`Ynckk zWoDO7$S80|u;9VZklnLk>Ci-itO;vGk%qi}sTCWQQ%<Ft~U`QDrNz0n_gdL#nn*+0w6ABG6|J62jn@D1MMQo5=?hMM%IZW>jV*X3NXXykL2 z!Q{W)`L$fim2*qFDd&w+rD{QMS(8h8$zU~^wPt7q(_)1iRjXi>v zAGnc1-R@kuY*;xQVJdz1Qdfq>qFN1^9=0&Kl6P;u! zz~wZW<+ZTJ-35?ZMC0KrY7&4GvLUTo6XDyXMYRxo!?iA@$35DDcfEzKJ{PC}&a9c1 zUTOm}`qP!qxAgPV#vfm`ew=R6#7oveTp-#re?h%3CWFSoC{SlfOM4VJpbpXXkpL@&_eQt0j@=+yUf6Ep z3b!J>JL@A}5mECHbAVsGkH`-}wL+)hSQw=lhPUO_efLd-mha{7I}+R`JvoIuQZ%n7+r#@|w)qN(FUf!Jkf(%8N>Ad~HtFj1 zPv?Fyw-(C5gZAE0=@O62!T4Ft@g>L7HRo!G5a7u_B z!M3nRu4+Nso9Xs2y_AEvEiZXY(YsgmL7EtSvR8Z`hFfkrEX-SdM`4orTM!WD-AC5O zetB{2_U6%Fec0$5Yz&S(h~10*?$k5%Vk53N@e6kRf)l@D$FJtWS^d06`b&p9Uj_9*x^%+SRcdl=G&wSl{V)Tp#s4HgnSsk z+$JAT7N=w{@(&-ki~;wpvH}UI6;dsBc?(irM&W%I3O5X+=<*e#0=`BEvQr>BZ<*W0 zfTwe&ULQIbPC*ym5Az2gz!kB9jkGg7VGmDi$0oiaT(9(5ek*{d!e#JzvSIIbXrK=^%5OtxdP6C1Z<fQtJki?LH1O{1K@1vv!hDIaPP}MX3c|uw16Yf8I`i1qcoV}E*xl#$?ha$uN1yA9@4`G&196A^xqrYOSa{s;q-N~YjFWoZ zPQAXHn%@~%*y&$bjd zkk=eoaLoN zhLp$BDDaLbf;X03cz)|Qz4-sd&tSm`*<0%!pd)V){5L|0;3K!3E9t5V?`ySWXw@R> zQB{4fnkxo9U8<@Xc~xb-xY=nGXHlF(0k1ByMLe?cY|bLsiUR+;kX5TdN@oI881fiHLSXpP z^*6kN8fLv9sZaS>uCi%pL!$Fe@|35PKI1ql{5wqOslSlq4oUteG)|?j2ncV1{{e&+ BCIbKf literal 0 HcmV?d00001 diff --git a/src/dcos/core/__pycache__/allocator.cpython-314.pyc b/src/dcos/core/__pycache__/allocator.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2118a9d3a04c2e000094d6dd9e4e9f5d1e5f0818 GIT binary patch literal 4500 zcmcIo-A^0Y6~FUkY-3_5WPyZ_;lr$*ICk7RD`?n!P}q_}AsI!cRd+LT?18xQSMH3r z$?n6Vs;a28((;f8@)TZHB2piC*oQpspWu<%8b*~`wNL322vM|s>N$7D#(Zq@vbn<^5%O<*s5Q}Mxcv!WmWe_P@_;DZ9d4R8_dXnLVUQ<|L2W(%pL zQK0g_mY>PFWInm1>2j)&E0zq9=F@Uc%N6KTnbtJY8Qq|nhb1FZ$jixGA-^PpPTtTX z-VkRsC-eD&kwl>$5-o8ulQJxE7IZB4d=XzKvzBzfRLp8Adto+pR>|!r;CY#RLJSUU zKc$eY=zKQWoiW_(j zkO%zep9o3AyB>0nd&DW6!bdq+k??fMrDZieYC8`4WG?9tnu?}V1wEQ7P%T>bXr%bm@~Nuh5KUFBzEkE$8s$FtnBLCT zd`JXod=JUmFzfc=HDOjFgUzwhvwsyHFftP)&jd&m4xVcJL82&gJPa}(Enl+7{`Qu` ztlpXn36@tiAbPTDs#vmG9NrEbNt2ICvw8pc4AN&K+$v+^YKPO}f ztn48P!G5x1Re=~ykh?X_hW=xi!ETtDFsAVfj^u7rZOl<0ci2`^F_0?#+S#&v&m zEL$Xa^E1SRNni#^KkWQ{^3i*QJZ`&N&l6O$n*zvQL+&SJS?VVBf zKpL&2m+oK83|E6=W^k+;yk!P&Z3QPl zDUM1pRO<1T-CdyN^KUixt&eOCUdPYAAKpl9j=oBiMw)X3|kuVx(5>W2z&qlY|$}#7gPL1OTZzfmc})p1FJbGbu7%7 zrIt`E6d|4KF=hw1Q`MR%RQ;r`S>2}-*b%Xv00_sB@po1)hE4eMhYtzg>V@2G^?uW_ z?Q5<2dQD$%)i+@J2G)ZclNDbKeE(A%;qkr`KmM;3Pk+CIvKN+F#rx!~P8|j-bhHPZ z%1N`_9;55}F6+zDoA!&-p2cFr%Gw0e{sAA=%N7iB8u|ziWC|DMYrX;>2`tl>YNJ@n zhj`m-i1c(6$T3fy0~l^Nqge83haDfmj75TeYp?oc(=S*3!=`_D{WqJ^rv7UB+f+IF ztBQZ7?4CL8A&hI5X>UJf+F6F@3_6bFZO04-v51K11{dZQkaF)8)*r0|2C#;a&-VVm zz$}xG>jg~#NCr&dQd!BRhRKC~^&RazE0Xyuw5NBO;t=VcaOEDZ+w$)={K! z3_~*U-IhR#aq@=xXI(uVZE!`)WvOO^QC$+`~ZC5n?{ zMW z4&xC_7$(?v6+E|7Bp&$b7`A^VJL3F-2$#tNFWgfOdZ0odcoE$XT{UpACqT8ikca*n zdR+Tr3GT(Pc8UmMxs0bpIBik%4i%9g@KDTP_Q4Y?vE1Xf?KkK>7=ob0O3SXmaoiry ZbK-%Ua6|tfkqU_%x`sJ81_5C!`9D|3XR-hQ literal 0 HcmV?d00001 diff --git a/src/dcos/core/__pycache__/coordinator.cpython-312.pyc b/src/dcos/core/__pycache__/coordinator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7652ab68e99a5798ecd80840f5e25301a348c9cc GIT binary patch literal 2375 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 JHwXwB!9S=p(VhSR literal 0 HcmV?d00001 diff --git a/src/dcos/core/__pycache__/registry.cpython-314.pyc b/src/dcos/core/__pycache__/registry.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12924c546d150fbf709de833dc17bf21cf6f6e96 GIT binary patch literal 4541 zcmcIo-A^3X6~A|8cA5Qv<-?fRIA$=!&0@Ms8rs+{iDE$s*eP)*3a;eBXuLb%sg_xC z=WZ%oKdh9fbzT}QMY8iy#gFE#mMXQ6{S%gA$#_&LQTx=s6nBMC`qXpI?7}V};mGMo zoO|v)_uf7CcRud9oNH^1Gx+}fFYlM72xI@iPW^*Ee!RL2w9HH<**r7(G@nwW(uce< ztxjoDn~KQDR8&T%T4W22tJC^aOva|-GTz7LV%@BtnOYAsBclp!$wtG5$pp!wAZw}1 zWYW|JSUOg^29x5K79CF-!dY~EDOQZXmp?a_Y}b?U=Nq<>cZHLaMUWI147*S;?3{Ez zats@n!2~aF$eWHUjGVn}-*5}AbR9nvPxByQdtOo6(k*&^S_{-m-b$cNxH%bU@4{~d z`g_YLvkPe@h~;f*=L)v(2ayHWDdclC{i)Hy4zGH^l-V4U9I#U6<5C?2yyi4hISUfv z)Ll+PZZ6W#=Avfg4Ib_xTg)iTZ=qSb)M-tOdT|+}UV?f_88=%2rM4hJ2$@cFI$#Oguh) zq5SS@dPBRg*?F=&d1rh>JGt4_U4G}z`%koP@p65eCP%0_H?Q6Taf2fqld8!jxB*BEo_v#A%!d zu2b_3bfl9_+GiSNJuutv0#ar>j7NU(49WdLYRD?2FUaYu=^Lw}SCv_o%`%M9@H5!} zTjMipJZP~fVtimV-zhARW@kgqz|~#Pm7vw}{aS_Nq)`mEEVIq*Yj?EYCHM5GLI&|3q7!iX=FbL9IyaG)Ff&#OG_#TjxC_oY-ltpN= z_kX>G%|l7OP(cKz{(*9+V66HhV9M-T`_;Onp`GPd8`sn%l#T#Ok%ob^BF;f0k|F)%QSu zIJl9@R`l!(LNCy@j)c@e<@X>RLJWuQk0Yc*mB9q^n(9sMbOf+yF=79s)ZKTo_J^g~n)e?eegJ0Nl+W&UY?ftDBb^sOa zBSq0+Cph9c!5?%Xz7xEXz8DT1L>Oy9LiiI}{rm{mE4_C1fl^X3tfWi=QXihVs=-G4 zzFB_$=Zr1F@0?;+AkWPzGs+e4$rw8g>y{xmmZ0uL&aI^zmC{WR{m3qq9G?(Mt6>-* zS^>9x*bOp|QM+drTrY3kSh27q+JDb9$_S~~VJVojx9`ibFUFqqX4ZQ%k9$WpQse8r zBdhkGCLc}yIsa(p9$)1!u$~&P=;Pn~H8ozv!shp#Z)$&xzNt0cpLk}_hgS{S`T6dF z_-<*ovS)p933fO#nlLx-Mw1qaKVv{1zQ2V{<%g5h{lD9KS-IAEn6)vwzP+u*I3679 z#k!%VabN;Sv#C4l=G=oXFq%X6;0yxnZP=^KzV7M0cl++`Cp|;!JwuOshO4UD9)H?1 zyxPB+I`QTF7xU|>b2}<)ZM$=6y=V9tO1GFAi+}SU2CR4oHfgdw<`J^}(X|uZ|8z4w zpP7eY>stQ7u)a)TeVJEY&R{rS=6m@ECers^gfnjl=Z?b+Y_fgf%$vfQ?}jsXv7+e! z&A_HqKai2J0)T>oE;X_*rQ%v7C-B{1)!r#5n(f*kB4{uN9TvyaVH{6An)-{rK037< z$kP>l8UlIxJ2GOR!h7||Sj~cx4V7&_ny!DH`O7h+8i;rd#67ReP$o(#I0F{MG$5$#lFe@k_)j@}!)JGPNBD!M@$iXjlqq}#-C zXa!z~;w2CZ#bs~^Q>(xNi0)MJ6XdQSc@N14NH9(awQz5ICkUfXu%M^s z+i%!YZDL!4SHN}@DqJKZNQRJ1@a-t1y6q%J!43?BsD>NjUNh-daSd90$1arMsRGXr zf%pYcxw7nfivocb8WM~d5k*;I_um0<=d|E3X8f>FH;}^`eNXE^9}C~eZ;9(5K&bs6 z1KCnJ=g$;{Yuh^G17ES>4L1B0dvza AKmY&$ literal 0 HcmV?d00001 diff --git a/src/dcos/core/__pycache__/scheduler.cpython-312.pyc b/src/dcos/core/__pycache__/scheduler.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb3e5c651b8242accd7207ef37e0a91de3ce519a GIT binary patch literal 4564 zcmd^C-E&jN72m!0O1hG)4}Tl%7zHR;;Mf#ga2v*f#D)+P!31ch%Fx>z-8INa_nN&| zfD|*MPUzHh=wLFmX4;3ic}WR$nm)CEK;QZjkKIAsfhK8R+Dso@L?=m~dd})2vTAqQ z=iV8eJ?HFM?e00hJ!kj#p-_Op_qR{Y>9oZIj(X%Z9A@dVg^U*nYiTo4c*aG8Qr#B z&s3Ua3>dG1jydTp174Xhb6IFTxm?;9NmaKd8d?!(xeu5H!bp-r03?GZWkX6ThMe>m zO46J6#J#TA>?v4N&USq>%rs!Zu8-$T6B&QX%Fbk%!wlCurKdB@NW^`vs%fU4Wt!#& zG%ahPmw<24w2L`CQ|Wr zd8?97NIsO9I^70M)0YewDvb6E`#>^i1VL&+31?z0)0>+HfY>m1*a(4rxNaY5=!+T= z=!;@szBS(FDu~`SyF~QEPHA};Fbl+~?ud}ud6=%A59qFcr^sEJh)cW$G_HJ}UE#RI ziXZz>ryk7c**6S*tPsK(hiW1Q!N$Z;B=;xo9sSkh`;%f6Ks92pDLt2Qv?)F1SUm5_ zw!>X1ZMei$5I3$0hs<=ev>}4(dTjwrj_Y&fv2?0>q7ITEmIdG``Y4&?jflW_ae_5&;7(c+79^0G2oinbNU=eE6-D0Ord zU!F@XD_x~c+a7G%y|ig}@yOgO%gXLjM`xv{^I>o7gPz~?{km_ZcdYozyt=H6J?wk- zgY7GQ2SD_%Cqd9DA0P17Q+Lr4_Ys@ zsu41L(E9UgJnV{CpQ@$CLcGS>BKH|-dq#Jlw~{D$9W11d$e38wIWkK$ z;3}Vx>ehL}W1xqG=!Nvcatv}#Jt^IVG-$KTl#S*wUcsfNrOmXXX@xGtWo?0csHWcv zwssUqk(9P>pHprGOFIVUlpjTe3sa3}K>;gqaxMY00IQsaw)vX|i{@{Z*7643XjHXA zHjc!MV@UVqT1}!PPvS~qjq7lyfM;4p$ZfQwQ&p!?fm=9v)M;=LM-LQsuJsNxg?Hf? zTPZzbkJZmJo(3DrJGg7{;(LX63&KsOAt3SvmWNWoE-`MixXeeu$o1+oc=RAH7Iz?j z96+VwKqPGRY^)k3Uv<7h=eo<-0j4${GKi7dax-{6_(0vfq;9@5vZBW7nw}-KXX%-* z{&wU;wdW7&p-TMf$br%5V-dekf%yTr>-xG8v}t~Wo^f*an}l4YPCdqRWQszZ)LA-> z=xF-J>p8U+|EtohWYZhl*PnUX*YpP(HwK+f4+xV2e&U0x5?KEt4B`@SF{r&vekot3)g#Qm2J?%|3zr{hXpbvHo_1+UfW$_3#$vHz&Q0Iq$z&(x4*jko3Hsa>Hb0W6luTt<`3U2 zwReBq(X%jldvb34QTOID?&#y*E$_VW(-+Df;6c$7o_qO;N}@fbXvaeER`5Y|>r!;< z;>b#L;8Fj;gZ@2B{d?w>+rd(I@7uxER?-<;Z6nc+|B&qd2us)~v%rD)&c;}=>yVSo|L=S=+xfOX3-LVwivFNNs2OoC#t_CrhEhO6ce;rN! zD!6rnXl{b8rfBj6h5`>}J$eehZ3=B`^9<@E8VeS#3VyVVwXgB2 z4tQ_8m_RRnwIWli_fV5F%&fqAKlC>geK%Bn+`;WBXF7%6wVPejIf+ACffUK3NZb6# z!t=MDUyf|~P~9SM2G0Uaf=-T`u9C1!7FWcHs9bxYUK0K-AW-~~FNAB4+ShT)vtWDz zO|~OJ16O&&vf#xl1dd5C9%#Cfu8on2GNVdSw z#tE;HhswUPB6;FvRq`CBWi{mKDEIq3o#i$lPur*`CiWsKH^56(ypTgkL&Vz!*ce{9ARq_sA-Nmd; zyMTvQ<%vDU@s5mWv2ok0GNttIl0=n%sDy6&hzu^1!H>wmWAe;n()pNlJ@qQIYrf+t hfo3&Kq~K?gkB+VqAY~cERTMw#c#g)N5FldP{{k?#ug?Gg literal 0 HcmV?d00001 diff --git a/src/dcos/core/__pycache__/scheduler.cpython-314.pyc b/src/dcos/core/__pycache__/scheduler.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..383532408f9c83df85fb907e94c3b219a3f2c95a GIT binary patch literal 6155 zcmeHL?QdJv89(>M_O%_qG(;)Z9*(bj z?(t}YG+6?%AfeGhwMNq<0$-poY3$SXS4>2SNO}hXwomL+GE)`4?Rn0<*RfMq8RP4Y zzQR5Z4OXxPDd7l&}~# zXjZ4tZ!nM$te{pX7>xHb6S5_pE?l$Z@mz*k^4XlpEajOZ4$|@o(eh_Cre*S)X9`OY%J(Q89lF? zL#9!p8O*f>%@H&+l+76CP{yG8Q1v7Si`QrfhI4_6c>u&~WHa1ae##cn_VUzbsO8lO z+TnJrv#$)bkc7(LK-Snd#-u(nCj%A*z?C@SoC8{W4y=u*0rvLslGiCIyyU~uoIe$V zY*%7IK($x(V~>l3HK_q81$lq?(p)HoYuuG;z8z7Upns^^KU&kaPYpv`1l!aopno6W zpxKfU`E~n6-vO`kSB`*ECKsH25#oAN%JHt+W%QEULNX!JAXHk?W&J8YIoqNSVV&}5 zUR$`7)yAw4esRz(;>rD`oP>Gao(mr|A!;`6$48B&*MBr94Z|YZ+$HYnEg(YKgh5 zMJyS?W+~vH1(wcb`SDs_L=fOv$`!!798bMQfvSiV$WR^JDGTsg^rQPd50lMVfvk?; zH`7LeuQ-|5PxnKAif2PxP~Zxwg5qHi7Qnm4uK}V7Y(iVvKx;+qD2gAU;2)O?#!GY% zik6&*Ptzf6X-9$h-mwzx!XgU%ys3fs4f!g(f3@|Vo6$)M>nI*dmXbqQ40nAISBp(I5%b?p3{@12;pxPgOt% zJ_cP;1E2%{g6>zFKo4;}poT$@a6Jg9Y;sV^F>>Cex7 z4ZzSlZ_ovenK)|?-i=S)@8EU)3+qQ5!~$Shb*+&e|Sm$ZDeO7?($^l3`Q0z zaXzZC;Z;eMheR;Ghn|3LmdwD6wg-$rnU11B|40b*r;ybg0R0)Zodkg{X?B7@1B;&1 z!Zw%7<6AsmnX$|E607!t{ur-tmb=Oa&yp16yHg5!>`t@7u(QoBIG={2oLH!Kq)Gti zfVL554PD?puywia{Bd3Yi%>ZP3gWfV?CwbmoL>N+f(=dkG-)pkwH~fNNWH)z0i0`O zw7fZ1C10d26RE9CR<69i_}(J7(+tET(u?{v2nY0E>D1Jd35lM|?f=)bD zLA3%$slf)%H#|bL0HzmU{T&c0_dcLsluUd;NKv>@1@1}VS?Ot#g>&m52*2Y%VL+bB ztdNrJIcsIKdSy>E*{*`EHvLV*P2CA$%ehWJ=F+)C-QQzA*9D5=tXRLB>F3DafV&u68n))hPo$h+bGb+#gT6fKfWHso;4w>rXvGpT-0w_0@cwwbY_quk zQ3!?ft3^6y9jMzHhu|thJta z*I3#2j{FDtU1PQN#HY~{e{VnX-M=N$Hu9Ybs3Nb#P6@YSqsm9kr-X@_gx_WgNz3PX zn1grff&nzbqwqEuUZk)K{pgbrlaWBW)&gJN1Kvx*(V))Lf z%#tq|Mt)BM!%Nb%?~{AP=V{qSu_A3@_JPbx_7bZc0|T5T`YZo(me?5j6PLg>fB_nT zepVR$xyx|V5JES;%u)@m%30B6mo9Rl>hq~8JHV2hG%FUW<6(Y8fUl?&_BB4+YO=LCt3lto<2T|iuJ@-ij?rjISX>8(`AY!(^-@&Zn23@Jj zCB|y5XLqdQ$MF4;G_=||^gkg9se&`uUZEGb2!{5Yujl}3dm-u^?%MssBzWT61jMq* zvmHo7C!Wwe@bg!2?%JmcV1rsdvwIVlSKJU9!rZ)G;1?Es9QxG$D+)PpV({Oo1g{D0 z^;WNIPT$vQmuQVfGF8DD()yPACy;cD%**Y5{j z*z5<{F}es{5O5}%dP@=nVOtah`L05Q-Y>|&8X5S49R8d<^f_tyoE-SZD+>p%$G#zu gZH0*#yeImEQQ&Z4v?4)q3yb$+j|e>#0)lV*KkWF2i2wiq literal 0 HcmV?d00001 diff --git a/src/dcos/core/allocator.py b/src/dcos/core/allocator.py new file mode 100644 index 0000000..5f57b0b --- /dev/null +++ b/src/dcos/core/allocator.py @@ -0,0 +1,45 @@ +""" +Resource allocator — manages compute and memory resource distribution among agents. +""" + +from __future__ import annotations +from typing import Dict, List, Optional, Tuple + + +class ResourceAllocator: + """Allocates system resources (compute, memory, bandwidth) among agents.""" + + def __init__(self) -> None: + self._total_cpu: float = 100.0 + self._total_memory: float = 1024.0 + self._allocations: Dict[str, Dict[str, float]] = {} + + def allocate(self, agent_id: str, cpu: float, memory: float) -> bool: + if cpu <= 0 or memory <= 0: + return False + remaining_cpu = self._total_cpu - sum( + a.get("cpu", 0) for a in self._allocations.values() + ) + remaining_memory = self._total_memory - sum( + a.get("memory", 0) for a in self._allocations.values() + ) + if cpu > remaining_cpu or memory > remaining_memory: + return False + self._allocations[agent_id] = {"cpu": cpu, "memory": memory} + return True + + def release(self, agent_id: str) -> bool: + return agent_id in self._allocations and bool( + self._allocations.pop(agent_id, None) + ) + + def get_allocation(self, agent_id: str) -> Dict[str, float]: + return self._allocations.get(agent_id, {"cpu": 0.0, "memory": 0.0}) + + def utilization(self) -> Dict[str, float]: + total_cpu = sum(a.get("cpu", 0) for a in self._allocations.values()) + total_mem = sum(a.get("memory", 0) for a in self._allocations.values()) + return { + "cpu": total_cpu / self._total_cpu, + "memory": total_mem / self._total_memory, + } diff --git a/src/dcos/core/coordinator.py b/src/dcos/core/coordinator.py new file mode 100644 index 0000000..e601730 --- /dev/null +++ b/src/dcos/core/coordinator.py @@ -0,0 +1,38 @@ +""" +Agent coordinator — orchestrates multi-agent workflows and collaboration. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from datetime import datetime + + +class AgentCoordinator: + """Coordinates multiple agents to work on complex tasks collaboratively.""" + + def __init__(self) -> None: + self._workflows: Dict[str, List[str]] = {} # workflow_id -> [agent_ids] + self._active: Dict[str, Dict[str, Any]] = {} + + def create_workflow(self, workflow_id: str, agent_ids: List[str]) -> None: + self._workflows[workflow_id] = agent_ids + self._active[workflow_id] = { + "status": "created", + "created_at": datetime.now().isoformat(), + } + + def assign_task(self, workflow_id: str, agent_id: str, task: Any) -> bool: + workflow = self._workflows.get(workflow_id) + if workflow and agent_id in workflow: + self._active.setdefault(workflow_id, {})["current_task"] = str(task) + return True + return False + + def get_workflow_status(self, workflow_id: str) -> Optional[Dict[str, Any]]: + return self._active.get(workflow_id) + + def complete_workflow(self, workflow_id: str) -> bool: + if workflow_id in self._active: + self._active[workflow_id]["status"] = "completed" + return True + return False diff --git a/src/dcos/core/registry.py b/src/dcos/core/registry.py new file mode 100644 index 0000000..953b932 --- /dev/null +++ b/src/dcos/core/registry.py @@ -0,0 +1,48 @@ +""" +Agent registry — maintains a directory of all active agents and their capabilities. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field + + +@dataclass +class AgentRecord: + agent_id: str + name: str + role: str + capabilities: List[str] = field(default_factory=list) + status: str = "active" + address: str = "" + + +class AgentRegistry: + """Directory of all agents in the system with their metadata.""" + + def __init__(self) -> None: + self._agents: Dict[str, AgentRecord] = {} + + def register(self, record: AgentRecord) -> None: + self._agents[record.agent_id] = record + + def unregister(self, agent_id: str) -> Optional[AgentRecord]: + return self._agents.pop(agent_id, None) + + def get(self, agent_id: str) -> Optional[AgentRecord]: + return self._agents.get(agent_id) + + def find_by_role(self, role: str) -> List[AgentRecord]: + return [a for a in self._agents.values() if a.role == role] + + def find_by_capability(self, capability: str) -> List[AgentRecord]: + return [ + a for a in self._agents.values() + if capability in a.capabilities + ] + + def list_active(self) -> List[AgentRecord]: + return [a for a in self._agents.values() if a.status == "active"] + + def count(self) -> int: + return len(self._agents) diff --git a/src/dcos/core/scheduler.py b/src/dcos/core/scheduler.py new file mode 100644 index 0000000..f87cf56 --- /dev/null +++ b/src/dcos/core/scheduler.py @@ -0,0 +1,81 @@ +""" +Task scheduler — manages task queuing, prioritization, and execution ordering. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field +from datetime import datetime +from enum import Enum +from uuid import uuid4 + + +class TaskStatus(Enum): + PENDING = "pending" + RUNNING = "running" + COMPLETED = "completed" + FAILED = "failed" + + +@dataclass +class Task: + id: str = field(default_factory=lambda: uuid4().hex) + name: str = "" + agent_id: str = "" + status: TaskStatus = TaskStatus.PENDING + priority: int = 0 + created_at: datetime = field(default_factory=datetime.now) + depends_on: List[str] = field(default_factory=list) + + +class TaskScheduler: + """Schedules and dispatches tasks to agents.""" + + def __init__(self) -> None: + self._queue: List[Task] = [] + self._running: List[Task] = [] + self._completed: List[Task] = [] + + def enqueue(self, task: Task) -> None: + self._queue.append(task) + self._queue.sort(key=lambda t: t.priority, reverse=True) + + def dequeue(self) -> Optional[Task]: + if not self._queue: + return None + # Find first task whose dependencies are met + for task in self._queue: + deps_met = all( + dep in [c.id for c in self._completed] + for dep in task.depends_on + ) + if deps_met: + self._queue.remove(task) + task.status = TaskStatus.RUNNING + self._running.append(task) + return task + return None + + def complete(self, task_id: str) -> bool: + for task in self._running: + if task.id == task_id: + self._running.remove(task) + task.status = TaskStatus.COMPLETED + self._completed.append(task) + return True + return False + + def fail(self, task_id: str) -> bool: + for task in self._running: + if task.id == task_id: + self._running.remove(task) + task.status = TaskStatus.FAILED + self._completed.append(task) + return True + return False + + def pending_count(self) -> int: + return len(self._queue) + + def running_count(self) -> int: + return len(self._running) diff --git a/src/dcos/learning/__init__.py b/src/dcos/learning/__init__.py new file mode 100644 index 0000000..0058503 --- /dev/null +++ b/src/dcos/learning/__init__.py @@ -0,0 +1,7 @@ +""" +Learning subsystem — provides reinforcement learning and model updates. +""" + +from .engine import LearningEngine + +__all__ = ["LearningEngine"] diff --git a/src/dcos/learning/__pycache__/__init__.cpython-312.pyc b/src/dcos/learning/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29b8572d0375627df31853e9190a886f9bfb608a GIT binary patch literal 332 zcmYLFyGq1B6rGtwH$>J}&@Be6((HVIVrQlJ0cnOYbB!bO2s4S0PXA%SZ}3}etW$|r z!WPP6W90-kc#Hcu_i*mvzRc%2im_PRyH%_o<1hu;Hk-rPJRylnB(WqK8&VRCWK!cY z>C`u?z@jd%A-LZBX$y>Y$*1Gc4lVhby&aS}A`8Yx-` z%ls2Zy#f#WljOOrl?9(f_^L>U8RybfoDaM3zZg-WHRsQ06M5+Ogxxv=tO5;z1=q#P zu?i!$$yZEPF0jc7<6K$Qa=vW(Av=wpIt^!j{Lkno9K`gMV2r;B!Rb$i@bTN;(QCeV JocS#7{s7hsUta(K literal 0 HcmV?d00001 diff --git a/src/dcos/learning/__pycache__/__init__.cpython-314.pyc b/src/dcos/learning/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d49104e18a0390f383dc01dcc1a6509258c358ea GIT binary patch literal 329 zcmYLD!Ait15KYqJt`+y{!GeK36`}b6#haigd*}xkVl%FhG$~0c>}~NI_9y%s&pnA= zJt&KJQ`q9b%)FWRn0cqO!wkj9zs%Dn_RnD$gY3XIk6?`|6wn>6@HM_7ft;X1+rf2z#vW}0tOgC9dE3ROv5Q9R zimREdt!JYN#Avpb=B0PUTIDX6Wmx-H1 F?hh$RT}1!@ literal 0 HcmV?d00001 diff --git a/src/dcos/learning/__pycache__/engine.cpython-312.pyc b/src/dcos/learning/__pycache__/engine.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea7fb9ffd90942fa85d356a95e1c7b4132309e49 GIT binary patch literal 3086 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 None: + self._experiences: List[Experience] = [] + self._policy: Dict[str, float] = {} + + def record_experience(self, exp: Experience) -> None: + self._experiences.append(exp) + self._update_policy(exp) + + def _update_policy(self, exp: Experience) -> None: + current = self._policy.get(exp.action, 0.0) + self._policy[exp.action] = current + exp.reward * 0.1 + + def get_action_score(self, action: str) -> float: + return self._policy.get(action, 0.0) + + def best_action(self, actions: List[str]) -> Optional[str]: + if not actions: + return None + scored = [(a, self._policy.get(a, 0.0)) for a in actions] + scored.sort(key=lambda x: x[1], reverse=True) + return scored[0][0] + + def experience_count(self) -> int: + return len(self._experiences) diff --git a/src/dcos/memory/__init__.py b/src/dcos/memory/__init__.py new file mode 100644 index 0000000..14f132d --- /dev/null +++ b/src/dcos/memory/__init__.py @@ -0,0 +1,25 @@ +""" +Memory subsystem — multiple memory types and the unified facade. +""" + +from .working import WorkingMemory +from .conversation import ConversationMemory +from .long_term import LongTermMemory +from .semantic import SemanticMemory +from .episodic import EpisodicMemory +from .procedural import ProceduralMemory +from .user_model import UserModel +from .world_model import WorldModel +from .memory_facade import MemoryFacade + +__all__ = [ + "WorkingMemory", + "ConversationMemory", + "LongTermMemory", + "SemanticMemory", + "EpisodicMemory", + "ProceduralMemory", + "UserModel", + "WorldModel", + "MemoryFacade", +] diff --git a/src/dcos/memory/__pycache__/__init__.cpython-312.pyc b/src/dcos/memory/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..309f6eb49960c0565a80982ec80da75063c5c010 GIT binary patch literal 762 zcmYjO&8pNe7)?5z>ECo5M;GF%qM`#bT?^vIpOsex6(O5Yo7}n8q$x?O6kO;#2=3ka zEWSaY8(j%5)QcNeCh6R{H6CeNq z0*S{U_mBrIpRft{k?*+ArhJBGj!#*@LlinbV-b&0?0CQuK1XxMLzeOdS~woDb9{-G zj>qggU!fHQTR@V}5MAi!>$JOXMu-n67qZV(_fqw$r9Aug{$s{F)>aLp86V%aeM41N z)Ff+g_0L3afjfenX`y+Dg>>>f({8x6i2L zr2-L=xOa@+m6wf@y-T$*@M{7g{Ox(r j{~H2$bpW>paD4#R+;ejPR|a5;H~#o>;(Z9@CG*LD5P{k0 literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/__init__.cpython-314.pyc b/src/dcos/memory/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f03425abf84bb6df39079c03503a5f94c849293 GIT binary patch literal 759 zcmYjO&5qMB7_`&0N!%YwK|-81XhBecnllpO!jBS(1yn%XutMV94cKvHJD^_Bif7;@ zcqL1@z?B2A;*RZfyK5!m@x=M&8~g5TihvpMulj@V0QhMaXTz-BIQ?R#6R-vfyn}0) z!PHaUp51o2D~0b3Dv0rE@iR zJjyPo3$@q-E3h8Ffa=N`?Sti{eQcUQ2ZV94iDmm4ClCt13=}RRTS9PT@UNsvXJ}~YrB@e}QQwf?^t_=JhKnVYM9`yf( h0Pc6-UI%V<;HG=-bl^q@jClL6kH+5DKwLAw{0BU9)+7J` literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/conversation.cpython-312.pyc b/src/dcos/memory/__pycache__/conversation.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8a376b3bf05f6a7b85a2a858531ae4f77a187d6 GIT binary patch literal 3076 zcmbVO&2JM&6rbIlU9UfqO%qcRoD`RDw;_RmN*h5cRH}YKkQ(}B6s@+NO|WIJ)7drP z$f%K^QhF+_DkaArL2!T*e?%`tNfl>BMb(}v^^n$7NSylKtnF+7}H#!K;RTq1T*h@CNz z#aps$XEl-OsC)zpV(*ll%Qkl{FJE@jCA(DS)%5RkKc-!;%xyQ#@>a1tU9r=b@;FmX zTMkQm7497VvU(W%bgt}p_Em2v_9vbvBl&U5amt=h=w_&|oOY@{J(JIQK0OOceEs|k z{>&<7WIxI*&&m}o*Y(w@yj^6lUxzu{%a`n2(?HQF!9Z$!49o(tNmc@2v^kb%3Dzi!v`GjeHRk4aqiD8-{ zgiMo1K~JDeamrVCHw6C@D%`)Zh(JRZ3C?_4P=qFEK=wKHCtL}eU$02J}Mj&%f$UeI7WE~Z1jz=rQoM$ zQ4Fn%;JZmbF=KHrpUcl!j^}dx)oe^i(Z7?vic#wZc*k@o5pX^E8gp>3k=WSCRB05uoituD?aliS7{~0QipHW!hWsPA${aTJOLuw$giS z?%ny(WqNEamA=>ep#OgVN@{HG!<+gF9SfA9o=qNT=DgH+6C@iRU{Y3LI+JfeHDOVv zK(DeGqtI(C&Q$0lECF?cW_1Yi4!=8$b*CA2nG5+uUAs8tqM|fM@GyDuPTn)k+0^r=9BK&%V5y5< zm?QNQZ_U$R^pwCX*Q^jAA%wywjx+|$0`c0%tw}ZcuGA`o*OZ!4BZVfoxUto05{6$* znIIW?JR@`bE5`%^UO4$6@|0(AzAf}A8tLNS)6fF5v>?c4`?fJE5T#+gi<;)hBO_Js zf4$zf|B0$}#pda{PL3R(r>lBuNlz`FU(yHbM$ddauo(Z-YHf>ufSCnwL7^oH^@T7- z&H0+tO4Mt#MqQ~&yygW4_RBRTgqB*P1-R_CwgTqJmR4)0zeH+k3&l=Y#SI`Cl_P+@ zGHrW7l}h7Kvu0*&hh?-7uI)X15SLJqzIX~mxP`H9F=nD<+t6tV55X??G!O_Kqi5CF zvt;a9H4ZEp2Y&i`**Gyz*NmQe&(23i&*JB|uB_lpT~B-$`!=?!_busti~Cme-68zL zaf8T;i2D?n|B1g`lX;>h7s7r8ZP+GAmGA?=WE6oM9|m4jB$(I;LWIc0qqLEU1HxwW z@}7NVn-C1iv0k|d(hKp48-UNk==Y-!69WK55QgpKf}QO!d>;mz5^viyE3`ummN#4L zUDFE7iMHW;U_}r&+GVR)v0W}a8Y&^(Sg1Ewn%Vu^82$XRH$bxcmeMzs4W{xQPpg+yGV=(^;_c@k_*TbhEG@yEE8a4q^omn$ zKB=#t3|?Df94kIXg!>tgbw!e-zhzmX|LR2A`jX$c df#JFsCWL@WZ?6*|O#yIEI|rnZe+Up^=YNQTqTB!g literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/conversation.cpython-314.pyc b/src/dcos/memory/__pycache__/conversation.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72b8f18f15556120664455a2ed9a9d171c24f1a7 GIT binary patch literal 3947 zcmbVPO>7&-6`tLlT`rfD){*2&GNp*NWI3!I(Uy!THT;7jDN3b@%x((0MJz8i|UwCR6&KmCbD$UktIwGt%69Xa=RyUUkZ750-@Ef+XtfbEn>XM3!?#pxd_R)Lq*S z4BM_ZDy|2FGQEhGJk(9~KhG;9yd_?-dX z|0K~jKLE&Af^^eiVBBic@wm@SSbpCSQgn-zKt+%DLrjb^bHQ6H0E96AaxTq=VFMdM zauUh6kc=WhC<9u9@37N2Mz3LGNX{S`M}pT2t(ie?vP*E@zX$}7I61aO$99J@TQsvb zHus0+Bi;ki?)l#T859 z5KNFPlu=SU!BvX_4`~N@&C-B}Bm;cH(t(Gh0=#Y+z^4SCw9?$L1|X0IgQ2+L-xGP| z{`~vLB$bb={BHlOQpRwNLYAQB3Jg0FLh};2Bft4eLMkvfL4GLRl`P4U^Adbt`6sRo zH0B~=0bOo*t}rkp8Ev(}>JInu)H4iijgc9J9>(d^QPt<-3(%rILfs}Wh@@V5hUCGF z=!DIM(jXTtQaaf|zi5*@DG@IcLCzx66~ytt((fNi^YiV?FFVJVP+`dRivC8-XjY$zzfwez;cw$ zLw6tyD1zcsn4F!R&4w^&Vc-YjeLx6BSy=C*x!UAwGqXE!es}!rzg6Xgu|fBBa`Ezx zp4rqh4{mPi7k16zjnq+mFkc9K(6()GnSP!Q_{e~eEHI+|FdBf}49lRv=>Fi%sQi8) z(peM`$HRpm_d^X1;CiSCoF4ljTljT%~ zJ`pHuE)UBhI&Ppj&8F*Ba$3w)dVAO+E}^1IpcddXv)RaPbf;3WMKgnGazcF_7@lAdF!OXTk zb&N|PD#E3*;`C!(isogog?c#LQL+0YJqJ1{iYwpfMrcMK^DIU^#i$4JaA6<2Ckx*f z!!QKmaf?0yzhtK(cK%T6h$jgXx?iP-mEAM5%^}gPefy z`lwhh8Kl5F?C5PAyxJ!t#N@&bVK^OwZOYso9{t0W-(7iBskLHD_nEWplFa%J* zHYCuBEBDQyy@6K^OBNQnd8}^pPiEc_{efbzO0>wklAQt!U&_v;Up6lGqBq(PUH2bN zH!7z|7m;a@hQX+PiI17Z@^u(>fCIBo)tpQ4fV`SkJ@HiD#02HT*Agoh^d^ z)3bjI$i5;;(lc3>=yRP&(@)8TEpp*0dF`)ca$h5I>V>RG*Y^pKjsnAdF-!{qm2N;9 TkZwc*;9d+)O7k58M11(aO5GrJ literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/episodic.cpython-312.pyc b/src/dcos/memory/__pycache__/episodic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b801f578371250955825a738295ad74ed4a64be GIT binary patch literal 2731 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 literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/long_term.cpython-314.pyc b/src/dcos/memory/__pycache__/long_term.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94bc02262493a8e1872885b8baa2430f6bbf70c8 GIT binary patch literal 3773 zcmb_f&2JmW6`$pPa7juOtw@nWsTLjCN@;!2uG!Qn(hrAnLdLSpE^G;?V=Y*6Ep0_| znb~0l=}_t2vW4C0zF7j3}5@+>@FosZhgrd z-n^ZU$M^A@_Z}zWy-@<=?0@P%RW(BXg&)CCJx1DZ0MjA{VPugQQbEdxSZEaaP(jWs zOv$TE&1+1{hgn#x%LP5JGhOgXA(D@>=qMQ^r-`8s5ktEj&B~r^789#sSk<#3f33%e zjFEJ-nTPM_tW#f_Viv8XYF5pmYpH*>ev@ig)U{n^)mh4A4lONNsXGo$*|mm4SqWBQ z1?WoMS*==?C2KmGmUygGuRE;7Y^Uy~6)s<{uW@C@E;Fvof-tUMZ{S|33TO37iCN69 zS->k->dji&)6JujKkbhL(;~MClfXHl#Tb(fi77^isfNrnLt$Ya{zTb{kXz_n{vW(qg2aV1}PFVFRyQMggaU7qEGrs<;jWwXQ>wSUrN zmTQ`{4{X>+gZOtd%TCS8l&z}eW?ZL9%Q%;6C7;l8rc!p?j2DPZ6(VC|WTqQy6j3Bd z3>f!SARm)Xw6B%x^bWS(?Zi&BW;%VZeUzuK1qYw=s1Jt#YF&@^2Ob50$U~%>VCrqH z7zY_g#zo0c;0(a4ny5=rbXt-V(8LGgj8T{ zg#1WamJG=VWh78T{x_cG8nsxH*10n0)GZMn0HFpyUn?;erM^y+cn+}OBN~x0{JaIz zhc^e|xcdr_7I{V_HM@som-=kkiR#$}gLuKui4ZCVr&#-l-oC|e$4M`4wwkl-^&OY}5Mhn!4b z$GtHiCvhVU1bwKg(LE#^W4kzQmc{g^bum5u@uJxDEK=Y~Fv7rq9+CZzfx(12A2OtQ zxftvpnvKv07zZ(mhh_L{r%5*0MX5(du$PhNNfG^cWXwyLxeOWnrO+v0=`;}DQ+8@K zn=z{bDPk_IdRr);%aBTW#C9DIhZOI_-8b;=1d^^47quOS;bB4ZWb(lyNbr`0SKovS zE%J|^SMJ{I^qkx{x05`#l|0w!N&Y_nVD@*jpU>@#WVc4LPe$I{4J#wjw(_gkC$YP^ zC;G|bpury(ph*d#{~I)!5E!otuy_Vc!Uc+WSnmxA!7V5ew_l13yyN1FL}Y~23wuZq z88B^5i7!vjZb0EI!cjnBQCx&D!F+TS@zjwqFJ=7)(g@9m(Em6pkbg%IPGk}_@y8fc zYp^mTf-?s*Mvco$7E8+qq2nslO1kFakByI~{IF3AN>TM#*t}(7@>w|FBAvv*{n)+O z{l0sBoAQ&ynYQ}n>G5{+?!qsA{#ZZ%a0bZN6D8ie>d+M%YL3mUn!6sy(tQhF_+(0i z33cMK4W_*8DUZR)ZotCo;2r_;@YF6&f60lj;{ns)5_qV0|IfngMFQ@Zib1Y|wO|Bq zFG1e@At9>}bedf_UpyRq|L9wAdkJKYkgG!kvTV_BxB^KyFJwQ!Ul!vFa+m@!7<7-&r4s8@WG3{}_K1|6Afaoy6eAiQh&)RrkVV z`24O;5`*oYuL+Fmhfq`2=t0sLz#j6}^O$^j?!f!*urTi#(bSL%!i6tF^&wVbxKB> zS99I;HA=32>o7hAR-i9ep*6Os2e2Q26t0yT4Xa*BYaYC2a4k$Nw^?N_kBK;#-W`Fq zOR(?an-ORW(wS?OXnFZqI`fuA6mGy3NN4>6?QrMS;rlE1R(@S;$2!SVh_9XG#8z@* zJ2~ZHF8RRz%>I03yD!~I4Be04i*Kr%?&HzyLkq}u;@f*F8J^zNNMfiR7vZCrEa%d_ zGyyX`futV^Hf20)niZ!EtvEJ1-h0CS$a`MsTzVPF`$({0iUjA0#bi&hu@nSFx)3zz zz5lMf_f&x{50tnfU6*!dZf?!o6phQ%IMk)5I^?=%{Q=@UVJHW6oP` vSC%AcFBFoLr#g|wz9f@R$mAE~8()yYuQWwU-W~Xg!1OGhl7{vP5Fzrv`;!5O literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/memory_facade.cpython-312.pyc b/src/dcos/memory/__pycache__/memory_facade.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca13c032c874b44e81622a8b466ff3caf8d9cb4d GIT binary patch literal 3993 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 literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/procedural.cpython-312.pyc b/src/dcos/memory/__pycache__/procedural.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0149b634589b84020e333db72cefc23e9ba8abc GIT binary patch literal 2540 zcmbVN&u<$=6rR~%UOP^lCZ=^;k}OS8yQyQNAVsCEDpd^vR0x#zfLui@*Rx5Ttar`q zTCFW3MW}~xK=go=N)(A>s$TkMAaRKkP~24|5S)-WxEO@g6YuT%R~w2DYx&Kaoi}gh z`{vs>-whAP2s|^t*{hdiLVm$c_mM(}wim$JB#h(;qfD@9NyrHlebEw2Qcfz#Ik}|d zlu{%YDXBS?5`nx$m~@*k`GF8-$wjM*9;v(yz1RobDVVIn^OjaJOAfDUKd*nOxt_yK zSF_AKw@s#%J3*$K*4(wCWkH*_nYLy-H)n4+H#4zcF|$tnp}cK7UfwG@wyVp&c)_mv z>czZe<*!?&FD(=co-e&ybUj~vzl>3Ns}OD~v|`xM_DA4s5|iX8U=SCN zEg+=_zCZ^MAjJTJwzU92k<^LN8xDHC=qkBS7j?lOGWz`b5hEn{KJ_Knw3b~A*Pfou z-f&80wqRPOn{}NEFJPN55J+V$! zdz1Q3ot}eEmFU8vF8Z?TnPt}>E_1Ws*sK_6#~&#>uGjDDln=ukUFM_E_>!G3nfxVi z`9U;?z__?W4Ihp;{4s8>fY40dr?)n}5C8rkT)@@Atdmxp96Z{bnAw?lZR>h-GQBf7 z_fU8ek&eYSq&+p&P*Zo4JL)7Khv-5_y5I)ngajRfPC(GV62XyufH;DU7(nDH@O@#~ zb}?@c)JSi?flO*sF9s9@9EHg)B7$R`nA(uOh<_Hpb9F~OvVYG=UvQ`vII!n`-0|ul zN{GX!P9JnM{fSr?-GtYZ3Zr%U6=A~HVmIPbcvBadco^m}iOKiGD@0coYeQWergow> zbV7q7qAfcWn+1n_6=V`EcZ*Q)%2&->W})Jl3(T&?5fGAR z-tzb)1iGkRAhaWs1D!krDmm8OOx_BMLuOx0kmv#=0$!7;z2xym^7vlzWFvWUE4iD@ zY(yU=Qjf=u+`YDy+)}pIwvV3K9Xq=nKiiymW$T@XD~8m>ViUFZ|y;&NRAhJm*M@RR$%KQn$DX1aKK06a0imzZiKruGuk zjl}df3%dz@Th&8Ay($NxNO+(uym2;(*Bb+k4FZQzd{%q<3HxXtblk3vx&TFAvfv{R z6(FsdRhK6qG_0Co9Y|n6AD~;)_91*O;sj=R8O%C)oEX2e&^=zgk<@pSr*;$RZ8aUh zgzBwu)2ndXmlhq{go?JP$HH${glz>kTXgC5&faQ9gs_ z6c}9zGVwINz%Q92GcOp&N>dxb3l>*OYjE=}g`r44d=6Mp!c@3GE!Eq^vvZa}D8UY9 zaas&74=lEZ;l~W4!GNW?IhQ!orZhHIcYIMT*;+Ga2A{j zkKtQ1QTV%f+utUSq>F7ykh4&BGjq+%Tq_clW6k8DmWZvU2klRXW?C}zTM9Xx4kB7A ziH)?Q@UDH3%352I78dng2_fqO-pf IFhPR90eC7<`~Uy| literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/procedural.cpython-314.pyc b/src/dcos/memory/__pycache__/procedural.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db1f120e3416c910fea82b6a373a147bd0ec3cc6 GIT binary patch literal 3508 zcmcImO>7fK6rR~1d+j)J00Rj>@j_C-!HFqQprx(UlD0v#Y1pP|B?v2HZ-Sf6t~;|9 zBqtwGMK3Lf9&*evxpC}~V~>tflyrqe)t)N#;K+(1_0;!fy-pzfw3Ry2zV~M4&FuU8 zX69r^dz?V)|I_*Eib}}u*a@2w2(8TLmt-Q9Vd%$4nOm@m6_&U48EeL6v-)qS0m;#r+fmuwq&-YM$Sj(dCHmV0|Jo}qqQ-f>(n@0DDKXH;K)&zbeL zOL^PQ-?S}X87dV#U-`JiJzx8@j9PiS5LgsYIbgIg2||@j5RZbR(v6rW8`M(_37h~& z>`qTLIt>+i5$xI2ix^SpX<{yF#6XSw1eCsh<3cx4A z|G76m`)AG<+?jI8hUm1SP@rHre%LVD;1X>d0-;LA$qnhkT|$a5c8FZ1x2Qo4DM!Hw z`480fBh2zD%<+{G*RhreL^Lw#vYEWcam%Cr#oR4-#>y2e+u}LyR#*XfekR`}tdJ`f zT%HTkm9I`HKm4rIgWIPQ@H@UoSiMOkHMfprzE7|Q3=`oe3fP){ z#u`VVQzbd@)DaU%L@$g8)NLE(7WFjqDvEcb>F=RtAR0HY? zKFx^b5HNAp21|U!$~e2QiJ|$d9Z3g}3}s1RLC!@C7`n!G1Hp*!3qY!5lf=~cI+C^2{<@4@&j|kO{{FfO z{d$CSXX{avG!pMvkAWoOQGnB>)uJFlIAV=2LBNw`Ofu-0e32e+s!WM`O_M=5W5$%{ zjpyWXGTPd3OBkoepkv4oI)&*VGOQ5R3uFYm+z&jXvI98QgG5KtQsHRjF>FC0>}J*! zgxO+SmE-sBD2bg)B4%&EUR6?0koMI5&({(M=OF(8#J7q2V=LN$|0T##K$vIU@#Z@4;z4v~b-0lx zf}o=tuY?;`CC3^@xGAbZ*9BcD)CGSq67YvS7~dKBX05~;cf}^phsh|~@=P12XPbv+ zSss^LP=s1OM6S2sYmjl8fM>vIIn;(rMH;6DtTE&)BCFZ(G!wNLnQIGkWa-D}+K%gR zW$Tk}#VPu+a(K%NDEgXp$0}4jt2hQ_fN1sQDGM&|E7t4>jJXU@y#?L@m}fa494i|t zL=RxQtGUTG)E*5j$lJkN5})MKssdI^CZxv58k!Rv-M7BO0)>sM?Rn?O*6c9QW7y-xuA$X1ra) zhJ^xOtPxxR|D~KlcuOLo>~+{NBWpMdIjE3+o2-@T1p8G=~LNd##%u4FyN-|s1vcgTa4}O-BMn*CTd`scm1>RC| z)0}aO6&q!E8Gc>K+s&DzX-<|H_w15mIW9~`O|$40Op{@`ve%IGBRPZQJd$^S_7Be#DzCmz*gEsU*P-i-}@*46`T_@&Bi7^0l{v pP`u0Vz`@LOyrt_hrF31AsIs9E+WUl@dqmD{M$&YkL4XKz{stR?-@pI> literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/semantic.cpython-312.pyc b/src/dcos/memory/__pycache__/semantic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fcd2a4f45047573ae9790a2f061ca4d5298b56d GIT binary patch literal 2595 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 literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/user_model.cpython-312.pyc b/src/dcos/memory/__pycache__/user_model.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a0450e1d430f0182373c620103064fb0abeb1d9 GIT binary patch literal 3118 zcmbVO+iw(A7(a8_`)s%DmWxneLvIXhcSSTtfqF?3jKXRp#AFCg#yO|3b#I=TMR&83 zCe)-n7)oMNe3C~Rc+e;L6HI*R(#EzE3`UF8DNG!LRuX z0WIM2<$SOZ(n5u>7Iw$Je54T3A_8F{k(?ydKTBxfw&=}&yS1LCxUwL~LT#BAt%lV| z|Dq5=SNN*LZjy#z&ZAU%@x=!%@GRlm+ zDmo!**oK)mEX(mt)eLGu8iG-{qZyhW@br3Vk9CAbKwm-qYET;3zT5ri@D7)~5^;L8|p34(C8Sl>}JMJCPoQIbNV6 z<%+hm4G804132kssZz8#`jrzlIRkL0ZrE8>ae}&z3+cKO)^)hbN*?=)u76fB@-0bB z*L&_m*Lgoo#6vinOkp!Tj$=H#w}ezIea^STaFH~Dl7Ek7E|v-`W3oK6GFGX=!5K1^ zQ7~GBn;B}BtW1Fw;Di|$1lO(7vS(uE-TB~(Ji+(2=iAyh-Ue~k zH>jXVG(^Q&h$$MT5h~3>WKo66!12>4^}#nl`yhT~@P`-;z&BJ4s{Kv~Z}&6?M{Uym z{IAIH0;1>cI>BMKoDlYho=FI}v(QB77f6oOiH>}?Rmq}|1=k7bWzV^+MZu9RmY=e4 zjwIg)6mLFP%-OnLi+6UKZu546hJ`mgL)MNQos+-rb8$0UAp`;;gWA*z^FMcxN}*BhZfgnjfARpKMq?+7hi zJ(+BsJ9>fHdWq{^9MpDp55GyU8*HqXfB*uK_>JN3(%+^Vk%RX~kK7&mNnRN}JvVtR zdo_FG)rK;(7E4^aeD(5;3ys+5QgHNXsBi=D7n%qVK(!@M)2Q`Cs|)Si^QBam_>Q{t zg)oi4KhdaAixOgrdMkrNhJhb|^bl_x5E+7xBf$yXI925?M2_D}5>BA)EjT~G)xs;z znOWi#oTZabYJ*+So|f(hb1MS`kc;nFNMBE{#)lj6;hP^V$H(Ua>yh}Hl2}zn?kOX; zwl$PPzbGRc5>XN!Y`ur;!1giB_MEWEb(#0qrMkQoY;`y3BUJnVEV1a}#1BK?O=_yI z2Pf%MR&{)rjC=*&H_))~HAb9TK=oPRSlwh?+tmeWvt$^J(?FgL&{%5j!nQ_e zvqS|m>nM)MpqMu8i_-HGy<`U| zz)OeR?Y)jeHzW4SQ^@VgkD-0A$KJg>SB}|_BY51M$<^$gsjG?dTC`o1ox{2WGP29v zh6UR>JawzmIj@HK4xAL<7`_XL6VP>9GNG^-Mb<$i7#-CEsBrcw>VAX-Y8Mz~STmL1FxF0>nMZ EfBJQy&Hw-a literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/user_model.cpython-314.pyc b/src/dcos/memory/__pycache__/user_model.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c06b8b6689e3bcd77bc366fb7f0bd592aa846744 GIT binary patch literal 4139 zcmcgv&2JmW6`%d!@@pwdr2LVDwrESHOp6o|Sg4!2c92F0=+Xmpo&f-&KIeLVgB1Y&KF|-BQUw#}Y<#n&e|`1B7C~@NAl0ZPjfj`}fYDvmR?v+sn3LwCJtbwPvGP%dSzoVN=_! z*EJO zt02ZBKV3tf<>X}^ty|2hIhN<~P@`!(b(kN4F`G44?OL!6QK^1M>i!WL9kNWA1m=@h z;!K$V6E3TUoCA)bu#o7f*jv_4k>#)vx*++pS;WvlGK{kH%y0S z>qZRZLh{7UxW@xNrg$UJ)Ga_7f)B0K73da}3PA#YM(6pGYs03GtC zNv0SQ17CuWQH~L39K31VP@x9_=8QWM(+mxI5K_Pk8xd$nMLS}|pdAl z@-ykCWJrcwl0XsVTa@J*wOO0GT&=WRTfhf?sx?}4)nXp5dYVq595_9(qfM91tnAu#e>KjHm<#LRa9666hN3qC<5^iByRjuporVGoPY0n2H08boOViH<}B4Nmv{7GoeUQA`j+7NoN%a2CkR$T$TAt)zrz_mSND`5sme z6;W+m7lXdGpk2S<*#Z4%_ZBod!5%Qq`d4K0QU~<0#su6d4HH`2JE@ti)XcqW z+o|I1@RN9IS5NQgXa1(2xj*rxeh!-Z3enTgf{*7ISW4<*)OEnMM5WAvtAX9;R%ox;po#La2;)RMHNAeO7 z9yZN-s|MG8T$CcV^dgcUA$beQRU{{n;GyX+j0v7%tO$ap6)E!fpS|PKfu7e}5CI9afh|e&|1`E>nClBd8t*#GWEa(!MN9>eC33rk{|)HYq$I jXTK&V_B0~L59E;a`W^w&RiL|v-GlLrRO}KUVkiFsgU>K` literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/working.cpython-312.pyc b/src/dcos/memory/__pycache__/working.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b9a1e4c29f4c89feb13b4304d27b7ce59796311 GIT binary patch literal 3004 zcma)8-A^1<6u)<7b{TdTb_J>+vL_7fpOnsnPi4xp#J!k8aRO_S|#N zx%ccj=XdV8_q)2f7=o|kS9|Pi1fiekB>aSc!RrIS6p)6pNW&UuVvEainDV^ITS8W_ zBH4%)%|@-7Yz>nOrf7*-5hD(rKw4x5Y0-OJU@cplt4WKKufZ(#mP5u3dqlEy%ON@G z$LZ^mJL(Xx+tZ2FC5;**quq+C>aH6u8Fq-IsGf0Amy{9R_9WL+JiRCO3pJj`eq6C_ z2SkQryJ^AaU$k?+@QR^&zA#|8o-e*WL3N4=YefyVdWNN|foB2bg8{F<1WWAXH?zP z-Hhu@5G+KT3 z=&bNje6^(mhWgdRM`ncwV)HtUNi73Kc?6XkUS z_ibQ4#sxHo$AH`Zjco?Htjr^?0$VkZ!o&?Bl7KB~fh1w@`4QbCBI7K>hT_KKBn8u; zsHaH-Rf&D3VqMUb{;B<2>(lidqWAQfj;fe$KQO_vCTgG^$lufGi>6ZVsbcS`Qt#@&YUZrIk(b#p3sHRcKC5U2Y(&8sF;(wU(2j&vf`yhpEq@zP`n6*iup|F zLGbwrXQJ%5?OcLzsMn;Gk~XT3I;N((o=cPRo+L>@BoStNsi1s(j$_AifHK%_A`grJhSL6&y_f}urAib#~uGP}!dz*BCQ0Ul8T9o#gh znzjNGNGX`^aUjt3;`Q^Lg+mL6it*iRon5yFZVucUoPDK~Xe%b#7Ke(7j@8De3da|Y zFS^CXeK$@N8@rYgU8~8)$CFpNAohUeost)x6dXj3;R}JEw_vFgmfM+rK5!KWc z5d5YY}7RfrEqD3Sq42Z3`pT!yRKn9`>jwpJIF9iR&XY}Npq=Vi2lf?FgLC4n9QPymH-t`Epd?HXU=&OTdfWS`Hj1Gs=sk-o? zbrzmr=N{Ah!Ue}M)7&N#Wxku5i_uqttysD&`!QLz9BtC1d_tDrpH$4Urbd=EN0ns) zw+JG8DcMiSGn7#L2+i?b#DZjHOkz|@3H`bIfXtwW!pTPhA33@ntBGXR8-z&HdICrG zu1C2@$0HF(0ub4*!E}r~51Xh{!;_F7aEeew{iv6lfTwJb7y29_^zA@uC}Hh^{qqZS zO7DU4q3R1F>nFV+qe!|mir;vQ@$Vdmg+E1v_x*snmQmODX!l>yb}apYfG`{X0y?-_ AJpcdz literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/working.cpython-314.pyc b/src/dcos/memory/__pycache__/working.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15fd76c1a2779c9d6f4fc29ec6d51c86b693aa97 GIT binary patch literal 4002 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 literal 0 HcmV?d00001 diff --git a/src/dcos/memory/__pycache__/world_model.cpython-314.pyc b/src/dcos/memory/__pycache__/world_model.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b94af23fabe624b44370b1f53351cbf276e76015 GIT binary patch literal 4046 zcmcIn-ESL35a0Xo<$QMRKvL>LY3-&7n7VNU=?4Pwp%#=vG2s9g3EIcx;rGBqtCEo{)G*F;N6h%oy_Iwhf+pe;S6rU&B&IZBuW zmdnQsrkD~_O&P3FHj_#piwMg&ubCRidpO@?>cB@iubT$&G0sQLIPkrkH_Qa^NzTX2 zJ{C7`0k7N|3XeR64mtJ6Q?~0dc>ak)PI8ZeznC*plE4Ifu%TTF44YelX^$W%RyTUHAy$FjoB{2*|%N7hdC!k2=6 zuJ8&`B73eOIlq&4O%M}qA~M)oCPtg1FldlG7>OW?#z$>uz+r~D7SsergX9aTkX6E{ z1t-a6t`mfs#k~lcR_uUTwJAI<-~}~sDwEs?!?X|H9qN|ldM*Pq`n${!LT*9|)-}k& z*xobhdx?eNyP=CMjE2_d4-7c4%vSqVER;4{CQ9S=-7xq5U18a+%>~}Gy>ZpnqvbO3Lh4(#O_(_ zPc7(if$CK~Gn2cj=jZjkv-;jkC$H!aFDCo{JD@}5Ri{ol(2>{eO3k6@lz$M-xV3|_ z9NBe^06G8c5_T8+d3On*htXf4T;v`&lHM3WjKG&Vkv*Zpa9vxCaY(}*RPj{MO|TRK zbu)B4TInEi==XMr=20*Tq#MF$;ILN89#{ikN6HNsm*2u2>9euv*tr9ck``}XwP=YzTA;AMUA`gr(PZsy5))y=7no4fD2qc=@` zLulR|TwC<`ZuIePyyBp{oIA*e|Fg^S5~6#7v|WzIb-CO?=ZYJ?>ke8Kb2Bh|8Q;S{O^j?Ep(7s7}&pQG+I4gPWkfTD)#qlL5P@xPvioL!FWt`h44G z+vYQSW;1)PWcK~0D1F9aX5agV&K-cDJ$LwOGBckXnoSPPROXWRT{=CRd~8J_y?tj6 z%x3oeimR815;cBr5?})?K|jqrn$W&dHJ~kvcCyMeq*7S$(~RrtMFHlVIujziJ29EV$QS%<8 None: + self._conversations: Dict[str, Conversation] = {} + + def create(self, conversation_id: str, participants: List[str]) -> Conversation: + conv = Conversation( + conversation_id=conversation_id, + participants=participants, + ) + self._conversations[conversation_id] = conv + return conv + + def add_turn(self, conversation_id: str, agent_id: str, content: str) -> Optional[Turn]: + conv = self._conversations.get(conversation_id) + if not conv: + return None + turn = Turn(agent_id=agent_id, content=content) + conv.turns.append(turn) + return turn + + def get_history(self, conversation_id: str) -> Optional[List[Turn]]: + conv = self._conversations.get(conversation_id) + if conv: + return conv.turns + return None + + def list_conversations(self) -> List[Conversation]: + return list(self._conversations.values()) diff --git a/src/dcos/memory/episodic.py b/src/dcos/memory/episodic.py new file mode 100644 index 0000000..662cd0c --- /dev/null +++ b/src/dcos/memory/episodic.py @@ -0,0 +1,48 @@ +""" +Episodic memory — stores past experiences as episodes with temporal context. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field +from datetime import datetime + + +@dataclass +class Episode: + timestamp: datetime + context: Dict[str, Any] + outcome: Any + summary: str = "" + + +class EpisodicMemory: + """Stores past experiences as episodes with full temporal context.""" + + def __init__(self) -> None: + self._episodes: List[Episode] = [] + self._max_episodes: int = 10000 + + def record(self, context: Dict[str, Any], outcome: Any, summary: str = "") -> Episode: + episode = Episode( + timestamp=datetime.now(), + context=context, + outcome=outcome, + summary=summary, + ) + self._episodes.append(episode) + if len(self._episodes) > self._max_episodes: + self._episodes.pop(0) + return episode + + def recall_recent(self, n: int = 10) -> List[Episode]: + return self._episodes[-n:] + + def search_by_context(self, key: str, value: Any) -> List[Episode]: + return [ + e for e in self._episodes + if e.context.get(key) == value + ] + + def episode_count(self) -> int: + return len(self._episodes) diff --git a/src/dcos/memory/long_term.py b/src/dcos/memory/long_term.py new file mode 100644 index 0000000..d90ba6c --- /dev/null +++ b/src/dcos/memory/long_term.py @@ -0,0 +1,50 @@ +""" +Long-term memory — persistent storage for important agent knowledge. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from datetime import datetime +from enum import Enum + + +class Importance(Enum): + LOW = "low" + MEDIUM = "medium" + HIGH = "high" + CRITICAL = "critical" + + +class LongTermMemory: + """Persistent memory for important knowledge with consolidation.""" + + def __init__(self) -> None: + self._store: Dict[str, Dict[str, Any]] = {} + + def commit(self, key: str, value: Any, importance: Importance = Importance.MEDIUM) -> None: + self._store[key] = { + "value": value, + "importance": importance.value, + "committed_at": datetime.now().isoformat(), + } + + def recall(self, key: str) -> Optional[Any]: + entry = self._store.get(key) + return entry["value"] if entry else None + + def consolidate(self, working_items: Dict[str, Any]) -> int: + """Consolidate important working memory items into long-term storage.""" + count = 0 + for key, value in working_items.items(): + if key not in self._store: + self.commit(key, value, Importance.LOW) + count += 1 + return count + + def search(self, query: str) -> List[Dict[str, Any]]: + results = [] + query_lower = query.lower() + for key, entry in self._store.items(): + if query_lower in key.lower(): + results.append({"key": key, **entry}) + return results diff --git a/src/dcos/memory/memory_facade.py b/src/dcos/memory/memory_facade.py new file mode 100644 index 0000000..24757d2 --- /dev/null +++ b/src/dcos/memory/memory_facade.py @@ -0,0 +1,69 @@ +""" +Memory facade — unified interface to all memory systems. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional + +from .working import WorkingMemory +from .conversation import ConversationMemory +from .long_term import LongTermMemory +from .semantic import SemanticMemory +from .episodic import EpisodicMemory +from .procedural import ProceduralMemory +from .user_model import UserModel +from .world_model import WorldModel + + +class MemoryFacade: + """ + Unified facade that provides a single access point to all memory types. + Coordinates memory operations across working, long-term, semantic, etc. + """ + + def __init__(self) -> None: + self.working = WorkingMemory() + self.conversation = ConversationMemory() + self.long_term = LongTermMemory() + self.semantic = SemanticMemory() + self.episodic = EpisodicMemory() + self.procedural = ProceduralMemory() + self.user_model = UserModel() + self.world_model = WorldModel() + + def remember(self, key: str, value: Any, importance: str = "low") -> None: + """Store in both working and long-term memory.""" + self.working.store(key, value) + if importance in ("high", "critical"): + from .long_term import Importance + self.long_term.commit(key, value, Importance(importance)) + + def recall(self, key: str) -> Optional[Any]: + """Retrieve from working, then long-term.""" + value = self.working.recall(key) + if value is not None: + return value + return self.long_term.recall(key) + + def search(self, query: str) -> Dict[str, List[Any]]: + """Cross-memory search.""" + return { + "working": [self.working.recall(query)], + "long_term": self.long_term.search(query), + "semantic": self.semantic.get_related(query), + } + + def consolidate(self) -> int: + """Move important working items to long-term storage.""" + working_items = { + k: v["value"] + for k, v in self.working._items.items() + } + return self.long_term.consolidate(working_items) + + def summary(self) -> Dict[str, int]: + return { + "working": self.working.size(), + "episodic": self.episodic.episode_count(), + "long_term": len(self.long_term._store), + } diff --git a/src/dcos/memory/procedural.py b/src/dcos/memory/procedural.py new file mode 100644 index 0000000..3b115ae --- /dev/null +++ b/src/dcos/memory/procedural.py @@ -0,0 +1,40 @@ +""" +Procedural memory — stores learned procedures, skills, and know-how. +""" + +from __future__ import annotations +from typing import Any, Callable, Dict, List, Optional + + +class ProceduralMemory: + """Stores learned procedures, skills, and compiled know-how.""" + + def __init__(self) -> None: + self._procedures: Dict[str, Dict[str, Any]] = {} + self._skills: Dict[str, Callable] = {} + + def register_procedure( + self, name: str, steps: List[str], + preconditions: Optional[List[str]] = None, + postconditions: Optional[List[str]] = None, + ) -> None: + self._procedures[name] = { + "steps": steps, + "preconditions": preconditions or [], + "postconditions": postconditions or [], + } + + def register_skill(self, name: str, fn: Callable) -> None: + self._skills[name] = fn + + def execute_procedure(self, name: str, context: Dict[str, Any]) -> Any: + procedure = self._procedures.get(name) + if not procedure: + raise KeyError(f"Procedure '{name}' not found") + return {"procedure": name, "steps": procedure["steps"], "executed": True} + + def get_procedure(self, name: str) -> Optional[Dict[str, Any]]: + return self._procedures.get(name) + + def list_procedures(self) -> List[str]: + return list(self._procedures.keys()) diff --git a/src/dcos/memory/semantic.py b/src/dcos/memory/semantic.py new file mode 100644 index 0000000..c3fff23 --- /dev/null +++ b/src/dcos/memory/semantic.py @@ -0,0 +1,34 @@ +""" +Semantic memory — stores conceptual knowledge and relationships. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional + + +class SemanticMemory: + """Stores conceptual knowledge, facts, and relationships between concepts.""" + + def __init__(self) -> None: + self._facts: Dict[str, Dict[str, Any]] = {} + self._relationships: Dict[str, List[str]] = {} + + def add_fact(self, concept: str, attribute: str, value: Any) -> None: + self._facts.setdefault(concept, {})[attribute] = value + + def get_fact(self, concept: str, attribute: str) -> Optional[Any]: + facts = self._facts.get(concept) + return facts.get(attribute) if facts else None + + def add_relationship(self, concept_a: str, concept_b: str) -> None: + self._relationships.setdefault(concept_a, []).append(concept_b) + self._relationships.setdefault(concept_b, []).append(concept_a) + + def get_related(self, concept: str) -> List[str]: + return self._relationships.get(concept, []) + + def query(self, attribute: str, value: Any) -> List[str]: + return [ + concept for concept, facts in self._facts.items() + if facts.get(attribute) == value + ] diff --git a/src/dcos/memory/user_model.py b/src/dcos/memory/user_model.py new file mode 100644 index 0000000..38c5422 --- /dev/null +++ b/src/dcos/memory/user_model.py @@ -0,0 +1,48 @@ +""" +User model — stores user-specific preferences, behavior patterns, and history. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field +from datetime import datetime + + +@dataclass +class UserProfile: + user_id: str + name: str = "" + preferences: Dict[str, Any] = field(default_factory=dict) + interaction_count: int = 0 + created_at: datetime = field(default_factory=datetime.now) + + +class UserModel: + """Models user-specific preferences, behavior, and interaction history.""" + + def __init__(self) -> None: + self._profiles: Dict[str, UserProfile] = {} + + def get_or_create(self, user_id: str, name: str = "") -> UserProfile: + if user_id not in self._profiles: + self._profiles[user_id] = UserProfile(user_id=user_id, name=name) + return self._profiles[user_id] + + def record_interaction(self, user_id: str, action: str) -> None: + profile = self._profiles.get(user_id) + if profile: + profile.interaction_count += 1 + + def set_preference(self, user_id: str, key: str, value: Any) -> None: + profile = self._profiles.get(user_id) + if profile: + profile.preferences[key] = value + + def get_preference(self, user_id: str, key: str) -> Optional[Any]: + profile = self._profiles.get(user_id) + if profile: + return profile.preferences.get(key) + return None + + def list_users(self) -> List[UserProfile]: + return list(self._profiles.values()) diff --git a/src/dcos/memory/working.py b/src/dcos/memory/working.py new file mode 100644 index 0000000..bb2e2a2 --- /dev/null +++ b/src/dcos/memory/working.py @@ -0,0 +1,41 @@ +""" +Working memory — short-term, high-access memory for active agent state. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from datetime import datetime + + +class WorkingMemory: + """Short-term memory for active agent state with automatic decay.""" + + def __init__(self, capacity: int = 1000) -> None: + self._items: Dict[str, Dict[str, Any]] = {} + self._capacity = capacity + self._access_log: Dict[str, datetime] = {} + + def store(self, key: str, value: Any) -> None: + if len(self._items) >= self._capacity: + oldest = min(self._access_log, key=lambda k: self._access_log.get(k, datetime.min)) if self._access_log else None + if oldest: + self._items.pop(oldest, None) + self._access_log.pop(oldest, None) + self._items[key] = {"value": value, "stored_at": datetime.now()} + self._access_log[key] = datetime.now() + + def recall(self, key: str) -> Optional[Any]: + if key in self._items: + self._access_log[key] = datetime.now() + return self._items[key]["value"] + return None + + def contains(self, key: str) -> bool: + return key in self._items + + def clear(self) -> None: + self._items.clear() + self._access_log.clear() + + def size(self) -> int: + return len(self._items) diff --git a/src/dcos/memory/world_model.py b/src/dcos/memory/world_model.py new file mode 100644 index 0000000..f322342 --- /dev/null +++ b/src/dcos/memory/world_model.py @@ -0,0 +1,44 @@ +""" +World model — stores the agent's understanding of the external environment. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from datetime import datetime + + +class WorldModel: + """Maintains the agent's understanding of the external world state.""" + + def __init__(self) -> None: + self._entities: Dict[str, Dict[str, Any]] = {} + self._state: Dict[str, Any] = {} + self._last_update: Optional[datetime] = None + + def add_entity(self, entity_id: str, properties: Dict[str, Any]) -> None: + self._entities[entity_id] = { + "properties": properties, + "added_at": datetime.now().isoformat(), + } + + def update_entity(self, entity_id: str, updates: Dict[str, Any]) -> bool: + if entity_id not in self._entities: + return False + self._entities[entity_id]["properties"].update(updates) + return True + + def set_state(self, key: str, value: Any) -> None: + self._state[key] = value + self._last_update = datetime.now() + + def get_state(self, key: str) -> Optional[Any]: + return self._state.get(key) + + def get_entity(self, entity_id: str) -> Optional[Dict[str, Any]]: + return self._entities.get(entity_id) + + def query_entities(self, property_key: str, property_value: Any) -> List[str]: + return [ + eid for eid, data in self._entities.items() + if data["properties"].get(property_key) == property_value + ] diff --git a/src/dcos/predict.py b/src/dcos/predict.py new file mode 100644 index 0000000..e2d5fdb --- /dev/null +++ b/src/dcos/predict.py @@ -0,0 +1,56 @@ +""" +Outcome prediction engine for DCOS. +Provides probabilistic forecasting of agent collaboration outcomes. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field +from enum import Enum + + +class ConfidenceLevel(Enum): + LOW = "low" + MEDIUM = "medium" + HIGH = "high" + + +@dataclass +class Prediction: + outcome: str + probability: float + confidence: ConfidenceLevel + factors: List[str] = field(default_factory=list) + alternatives: List[str] = field(default_factory=list) + + +class OutcomePredictor: + """ + Predicts outcomes of multi-agent collaborations and task executions. + Uses historical patterns and current state to forecast results. + """ + + def __init__(self) -> None: + self._history: List[Dict[str, Any]] = [] + self._models: Dict[str, Any] = {} + + def register_model(self, name: str, model: Any) -> None: + self._models[name] = model + + def predict(self, context: Dict[str, Any]) -> Prediction: + """Produce a prediction based on the given context.""" + return Prediction( + outcome="success", + probability=0.75, + confidence=ConfidenceLevel.MEDIUM, + factors=["historical_success_rate", "agent_coherence"], + alternatives=["degraded_outcome", "failure"], + ) + + def record_outcome(self, prediction: Prediction, actual: str) -> None: + """Record actual outcome for future learning.""" + self._history.append({ + "prediction": prediction.outcome, + "probability": prediction.probability, + "actual": actual, + }) diff --git a/src/dcos/protocols/__init__.py b/src/dcos/protocols/__init__.py new file mode 100644 index 0000000..038f5a1 --- /dev/null +++ b/src/dcos/protocols/__init__.py @@ -0,0 +1,8 @@ +""" +Protocols subsystem — user interface and external tool integration. +""" + +from .user_interface import UserInterface +from .external_tools import ExternalTools + +__all__ = ["UserInterface", "ExternalTools"] diff --git a/src/dcos/protocols/__pycache__/__init__.cpython-312.pyc b/src/dcos/protocols/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac8f032e695beea6be641248eaea9abc26c2de25 GIT binary patch literal 398 zcmX|8u};G<5Vf7OsRF5(5rap9Q1b&78$v9=0819j*ro(Iab+hG-QXXP;1~FoF0e*I zLNGBPfhraz&Q-$=ckk@??&);%B#9Bk#%Fc)4E5bNU62)6Yy-GQ66Hu@Ni;4=PO!&; z4$3eO0f(|TA$f1sPow4l=<$g)wGl=;>Y8&mbG0hz+sz$qoU*j2YGp6DP?T4as%z*f zu4!$IUj9uiuM1O+;tve7QrsqIAUo_-{$YP5It7ih0nls+=_u{D5o6K_#@eAbWB+DL zRy*wMn74CFm6vd>8GA$v7=nJs*`+B}CX`k#bEdJvS6=c}vLchhxNO>OnKAGwYQ{#> uSvwe)MmAdQ*>xD^S8!X9z5 literal 0 HcmV?d00001 diff --git a/src/dcos/protocols/__pycache__/__init__.cpython-314.pyc b/src/dcos/protocols/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c4e9c775e993844668415e5e7fe790ac3351b86 GIT binary patch literal 395 zcmX|6O-lnY5KXe%54W^<7NG%8Tc!I4iZ`*ns4RLl#B9_`c2klp*jw>8c48gKA14@nLEbDi)GcF r^%!P6< literal 0 HcmV?d00001 diff --git a/src/dcos/protocols/__pycache__/external_tools.cpython-312.pyc b/src/dcos/protocols/__pycache__/external_tools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe983a8c58a9b99c579be368105081f121bc418e GIT binary patch literal 2095 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 K{~;j6J^urzJEr&m literal 0 HcmV?d00001 diff --git a/src/dcos/protocols/__pycache__/user_interface.cpython-314.pyc b/src/dcos/protocols/__pycache__/user_interface.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b03111d68d4ea540c504d6a9eec02ae8596f43b2 GIT binary patch literal 3646 zcmb_f&2JmW6`%d&E=iG!Wm{j7L`RBiMzR>kN^Q%vg9b)IxsJkY5C?@LEwociAEu1wM@l0ydI z+nISYvv1$~z26(o=Z4Y*+M#c~5C5qU@?RVz4aV4n?w>%mh(Q=xCx);hltm`aU|(F3 z$}*G73RB7|Q_Crq;`7pqR@RwbPO~&0%PX03hGk~Rntp^FBZe|c40TE5$CIV#L0C4{ zra-GbqaETqbbr&iwEkGQZh1A= z4hqd^O{2+5ev`qY0E%dnRb`Iv6&eKDhuT+ zPQXI#?FQ;Bws@tX+rcJZ%*P1T&v!?k`({f`?-ZVEH8Zg)K zY|jTZO!WBOG^qyfj9x5x{%`4XXo6gW_tFvU9x+X@g*jCdVn?0dG?^X1uEU_~!jFWn zm#+JDyHvFS0;Rxj(kec!x)lprE!C=iP)Z;Zlp+TtSXyjs(F`2K1$Kf(5Pu+FXL7eL z?+p##y7F*h=7IK)?BBCrOk8NK+`h3ZUwAk@`{2?S)8|@m-d=CZ=jc>&z`eGF^Xag#W;#N z6#K!X6F9_R(&tfNydp16W3P}1jB!u|0S?dRZ~ba7_uQ?w_Qob#m+vUM^5mfF+wz6z z6g;5M*D>D+-OHfq@%1E=41qz`0k=q_#2p3?%g_gwg1%~~&<9R}e#+3G4;%!2%}6sn z_T>;}(nQ(}TaI^t=D3x(3x;5bB>{3<`UcmADz#aYdZE1Pdp7qkaFQAwAKcdNd**fERNxqxlLOn`;3giAOavlvJcogKM+eP|=DBHD%UWdb=Vx!r z|I((OT9kND20iy+fiFDRgN9_tB@w)+&=asMOwouUBMLwu(nBcltBL}hhewYy=>qCb zf;ff>#5g)jRnm`8+`HDn$Afh~iY$zA2`dRfdIbxIx-N8}=0Zf#o~uFywF9jr7|I8* zI%)^6sl-)0S%uG~c(4@vr6j@EsyAmU77gsD6|n*E>8Y5Dp^DYjW1#{igKmWy^d08d z0Ud$^ks0a@*S_Jft)di7Nv`dMO3-i}Rut)JSVhl(2=I%K$B`Y1(*WX&wP&(FynRaU z(X+6(MLH@OI&x=oFMIUv=)Ir)_2gepZjZgZmmT}_?A^^z>L1tJ)2DW(Pwh^h-kn(L zq~zgrhsb*RCqjglq-sP`91=*MKL`n2*#n952!ivU<`5F+KReAw&q5*vn>Zvs=U;x6 z90Y~RJ`7+{+zbIAfsh|)h6wZOz$6SS2)==qK&2!mV3`4ug#G;5*uOYSI8YCGW0t%k zV?y0rc!P6WA>g&AkoXZPFG3nrm!Mhax2i?@I-DO>d*RwmX>GYsROu<03stMpu)P{Z zKtv04C-5U;qc6Z@f;K#%4{iBqk(sAv^hkc z_DTNZ{9bnS?pS+#erJ5XJ^t#>_^Z3)XF7^>JpCP!^h`%1heqz4ZI8_DjLdBxdhy=7 zpN{=)=Kjp~iF4ceGSx91XKs0|0&2xgHXynbqcp<&ke;Hf*K|rE6gNUAy(C3lK z=eMU$@#j<1U=?o&GWh9TB)Jy(Am$GO%w9pW2U-G|Swc&of=jaOf|Wdm^c9%tW%$gd z&5{Zbj`v5UN5w6UO3=UaBX=&f4;Ob17kBe7ZEG)agXzm~@M?)(bQPX> z^WA7d9fsOU(Mh4owi-~}DSDG)wov3~iWwPZ_Wwlytzzc)+?V(jw19KmDhylnI$p%J zUqtuoi_`!GMkaV4L`MUvcqCZd91>5)k~w{{wxy4YdFO literal 0 HcmV?d00001 diff --git a/src/dcos/protocols/external_tools.py b/src/dcos/protocols/external_tools.py new file mode 100644 index 0000000..21ab965 --- /dev/null +++ b/src/dcos/protocols/external_tools.py @@ -0,0 +1,31 @@ +""" +External tools protocol — integration with external APIs, databases, and services. +""" + +from __future__ import annotations +from typing import Any, Callable, Dict, List, Optional + + +class ExternalTools: + """Manages external tool integration — API calls, database queries, etc.""" + + def __init__(self) -> None: + self._tools: Dict[str, Callable] = {} + self._tool_results: Dict[str, Any] = {} + + def register_tool(self, name: str, handler: Callable) -> None: + self._tools[name] = handler + + def execute(self, tool_name: str, params: Dict[str, Any]) -> Any: + handler = self._tools.get(tool_name) + if not handler: + raise KeyError(f"Tool '{tool_name}' not registered") + result = handler(**params) + self._tool_results[tool_name] = result + return result + + def get_result(self, tool_name: str) -> Optional[Any]: + return self._tool_results.get(tool_name) + + def list_tools(self) -> List[str]: + return list(self._tools.keys()) diff --git a/src/dcos/protocols/user_interface.py b/src/dcos/protocols/user_interface.py new file mode 100644 index 0000000..be3a1da --- /dev/null +++ b/src/dcos/protocols/user_interface.py @@ -0,0 +1,50 @@ +""" +User interface protocol — handles user input/output and interaction patterns. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field +from datetime import datetime + + +@dataclass +class UserRequest: + input: str + user_id: str + timestamp: datetime = field(default_factory=datetime.now) + context: Dict[str, Any] = field(default_factory=dict) + + +@dataclass +class SystemResponse: + output: str + agent_id: str + confidence: float = 1.0 + timestamp: datetime = field(default_factory=datetime.now) + + +class UserInterface: + """Handles user interaction — input processing and response formatting.""" + + def __init__(self) -> None: + self._session_history: List[Dict[str, Any]] = [] + + def process_input(self, request: UserRequest) -> Dict[str, Any]: + """Parse and interpret user input.""" + return { + "intent": "query", + "entities": {"input": request.input}, + "complexity": len(request.input.split()), + } + + def format_response(self, response: SystemResponse) -> str: + """Format system response for user consumption.""" + self._session_history.append({ + "response": response.output, + "timestamp": response.timestamp.isoformat(), + }) + return f"[{response.agent_id}]: {response.output}" + + def get_history(self) -> List[Dict[str, Any]]: + return list(self._session_history) diff --git a/src/dcos/risk.py b/src/dcos/risk.py new file mode 100644 index 0000000..03ed2a1 --- /dev/null +++ b/src/dcos/risk.py @@ -0,0 +1,79 @@ +""" +Risk assessment module for DCOS. +Evaluates risks associated with agent actions and system decisions. +""" + +from __future__ import annotations +from typing import Dict, List, Optional, Tuple +from dataclasses import dataclass, field +from enum import Enum + + +class RiskCategory(Enum): + TECHNICAL = "technical" + ETHICAL = "ethical" + OPERATIONAL = "operational" + SECURITY = "security" + STRATEGIC = "strategic" + + +@dataclass +class RiskFactor: + category: RiskCategory + severity: float # 0.0 (none) to 1.0 (critical) + likelihood: float # 0.0 to 1.0 + description: str + mitigations: List[str] = field(default_factory=list) + + +@dataclass +class RiskAssessment: + overall_score: float + factors: List[RiskFactor] = field(default_factory=list) + recommended_actions: List[str] = field(default_factory=list) + + +class RiskAssessor: + """ + Evaluates and mitigates risks across the DCOS system. + Provides risk scores and recommended mitigations. + """ + + def __init__(self) -> None: + self._thresholds: Dict[RiskCategory, float] = { + RiskCategory.TECHNICAL: 0.7, + RiskCategory.ETHICAL: 0.5, + RiskCategory.OPERATIONAL: 0.6, + RiskCategory.SECURITY: 0.4, + RiskCategory.STRATEGIC: 0.6, + } + + def assess(self, context: Dict[str, Any]) -> RiskAssessment: + """Perform a risk assessment for the given context.""" + return RiskAssessment( + overall_score=0.3, + factors=[ + RiskFactor( + category=RiskCategory.TECHNICAL, + severity=0.3, + likelihood=0.4, + description="Minor technical debt in agent coordination", + mitigations=["Schedule refactor cycle"], + ), + RiskFactor( + category=RiskCategory.ETHICAL, + severity=0.1, + likelihood=0.2, + description="Ethical constraints are properly enforced", + mitigations=[], + ), + ], + recommended_actions=[ + "Monitor agent autonomy levels", + "Verify ethical constraint adherence", + ], + ) + + def should_block(self, assessment: RiskAssessment) -> bool: + """Determine if risk level warrants blocking the action.""" + return assessment.overall_score > 0.8 diff --git a/src/dcos/scenarios.py b/src/dcos/scenarios.py new file mode 100644 index 0000000..810dce6 --- /dev/null +++ b/src/dcos/scenarios.py @@ -0,0 +1,67 @@ +""" +Scenario modeling engine for DCOS. +Generates and evaluates hypothetical scenarios for agent planning. +""" + +from __future__ import annotations +from typing import Any, Dict, List, Optional +from dataclasses import dataclass, field +from enum import Enum +from datetime import datetime + + +class ScenarioStatus(Enum): + ACTIVE = "active" + COMPLETED = "completed" + ABANDONED = "abandoned" + + +@dataclass +class Scenario: + name: str + description: str + assumptions: List[str] = field(default_factory=list) + constraints: List[str] = field(default_factory=list) + expected_outcomes: List[str] = field(default_factory=list) + status: ScenarioStatus = ScenarioStatus.ACTIVE + created_at: datetime = field(default_factory=datetime.now) + + +class ScenarioEngine: + """ + Models hypothetical scenarios for agent planning and decision-making. + Supports counterfactual reasoning and what-if analysis. + """ + + def __init__(self) -> None: + self._scenarios: Dict[str, Scenario] = {} + + def create_scenario( + self, name: str, description: str, + assumptions: Optional[List[str]] = None, + constraints: Optional[List[str]] = None, + ) -> Scenario: + scenario = Scenario( + name=name, + description=description, + assumptions=assumptions or [], + constraints=constraints or [], + ) + self._scenarios[name] = scenario + return scenario + + def evaluate(self, scenario: Scenario) -> Dict[str, Any]: + """Evaluate a scenario and return projected outcomes.""" + return { + "scenario": scenario.name, + "feasibility": 0.85, + "risk_adjusted_value": 0.72, + "projected_outcomes": scenario.expected_outcomes, + "recommendation": "proceed_with_monitoring", + } + + def get_scenario(self, name: str) -> Optional[Scenario]: + return self._scenarios.get(name) + + def list_scenarios(self) -> List[Scenario]: + return list(self._scenarios.values()) diff --git a/src/dcos/utils/__init__.py b/src/dcos/utils/__init__.py new file mode 100644 index 0000000..7e11d4e --- /dev/null +++ b/src/dcos/utils/__init__.py @@ -0,0 +1,8 @@ +""" +Utilities subsystem — configuration management and CLI. +""" + +from .config import ConfigManager +from .cli import main as cli_main + +__all__ = ["ConfigManager", "cli_main"] diff --git a/src/dcos/utils/__pycache__/__init__.cpython-312.pyc b/src/dcos/utils/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a935497f42e64b3f87d6f19f20fd76a224a53ed GIT binary patch literal 364 zcmXw!zfQw25XNmMZK70J84yEYfiBI81Y+p~0ydT`ma$DS@*iX;LpOK_BzOfj-lGe1 zBqRhA0}`lWVdB!38}7c({@v+rmggCQSo^eBPf*`G^B-g-<~tznkw6s^SP+d3sR-_L zq$3koJKc2Y7Z?E3IlJLlK(uFb%ad#oNtY!JWNOlg6`JIa?TJ*+d#? z>w;NPjE@gT*$0OHA#U^W0zFwE9v))Dl=Tt(wkg+&cJ_3bvzZQ=(2`~lS@WupK9 literal 0 HcmV?d00001 diff --git a/src/dcos/utils/__pycache__/__init__.cpython-314.pyc b/src/dcos/utils/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..744a3645591fae6bb6d5d9953ca5079c83e98658 GIT binary patch literal 361 zcmXw#ze@u#6vva?^#`YQbP%DZ4pN2QDkv^pT2Y4sS3}Ij8o4BrNYPW4fe9vs#}y6hErNMmvfg$1c;3Q zwsGhHh?OO!&u9)7)koQ#Q6l4_6fSe7vOH9#*eY3`72LS2f+x6)QmLhwzD7kZqueMoi;&YC6aAvxkS)Xr9hEN8j*sk@Zq|i*=#?k-g_hnY9;)9=0C z8~>coXArFYf4K`6(+K@3F3D21327?;;!{M>JR%ZFIZ`z>pOOSEJMz37pUS)fr{bim z>bwdvjp!u(etKS`I#I7ag%I19LR4NDOq_R4;A^Yx>#DR(NT@E?`R;g!(wBP<)wKo_`rnpMM2YH(+&K^T1{@^Fa75 zNIYx0t{0er?YaI8-1QmnH5!D>wc3&6_!{goLekdBl*l}IBwK*{{-jKCSBOgB1>{4Uq+<&8;SI-^{=+0#}RrG zU!AjomLz{jLP6Yj!C%OAqzOd^$lxe?lvS#cTIfw=os;E)f#gPp5^d<+FzD~lX_AkT zaJ0)x>R5Gg_w2~s+u`mSVI+<)(&cOC2>ZHyb!qS4`O7~?U#7Y$Hk@SLIoC#4+t`5o z2MPzGCtfve_i-S0U>g>}Rsb0PvHS@>Yx@DSuY>_5c-kwwc3>}3e4$1eK-Dedxw;?F zs=zM*-C}l4066NIm{_FD2a;#}z+==1SV*Hia~1CzZc8xC4yH?XP)Kprw1gd3D%7b( z`ox6gxh1>IQ8YSh1{EB5c$*W7u%3%cwnGatSAu$ta*fcE89D(IsN$NnJ(pZM%~c;J zD)b97>k}fGg%HDbOI|eCo?hXaE>Q~-EGRtfnylt}%FpSY9Ly#Uhk3DAvLF8k@4%!uQ4VfHD5}M6u#kY0;t% z^^3k2GN@3|H>+lQV^&c-bj2{R9lvNf_GGQjl`0^Pje!eMS-%g8xs2}T_uS2o-_DOW zhhKasr+U@pms%=HXYVQ_x0R8mKD2VanICVZQF`A)B&XGu-X$FTV(8|TX1=hCcwlAd zW`*|`n)xFwEq0)QgB;2Y-pwAoojtg6apTbOZ|A!cP$1#C7^&?%HiyPXZ|7)Jy)Sm@~ z`%2Gx?$8SP%K6M$d1pQI^p7Wgn)+etj&iD*&22$l5Z4VuRLU?4(o8{#+Yt3TFoADE zFW<%uJma~Pt1SL6a2YyR$Z*Xth-VoF&lpB26!MxT6fWWTcG7?*9YjCg?c; literal 0 HcmV?d00001 diff --git a/src/dcos/utils/__pycache__/cli.cpython-314.pyc b/src/dcos/utils/__pycache__/cli.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d7594aa8cd5a0cea12d3561e5f64bc4e2fcb0fe GIT binary patch literal 2211 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 P_;#dU>a7wG;w=9LrNkRz literal 0 HcmV?d00001 diff --git a/src/dcos/utils/cli.py b/src/dcos/utils/cli.py new file mode 100644 index 0000000..360f3a1 --- /dev/null +++ b/src/dcos/utils/cli.py @@ -0,0 +1,53 @@ +""" +Command-line interface for DCOS. +Provides the `dcos` CLI entry point. +""" + +from __future__ import annotations +import sys +import argparse +from typing import NoReturn + + +def main(argv: list[str] | None = None) -> int: + """Main CLI entry point for DCOS.""" + parser = argparse.ArgumentParser( + description="DCOS — Distributed Cognitive Operating System", + ) + parser.add_argument( + "--version", action="store_true", + help="Show version and exit", + ) + parser.add_argument( + "--config", type=str, default="", + help="Path to configuration file", + ) + parser.add_argument( + "command", nargs="?", default="status", + choices=["status", "run", "info"], + help="Command to execute", + ) + + args = parser.parse_args(argv or sys.argv[1:]) + + if args.version: + print("DCOS version 1.0.0") + return 0 + + if args.command == "status": + print("DCOS — Distributed Cognitive Operating System") + print("Status: running") + print("Agents: 0 active") + return 0 + + if args.command == "info": + print("DCOS — Distributed Cognitive Operating System") + print("A multi-agent cognitive architecture") + return 0 + + print(f"Unknown command: {args.command}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/dcos/utils/config.py b/src/dcos/utils/config.py new file mode 100644 index 0000000..46a691e --- /dev/null +++ b/src/dcos/utils/config.py @@ -0,0 +1,48 @@ +""" +Configuration management — loads and provides access to system configuration. +""" + +from __future__ import annotations +from typing import Any, Dict, Optional +import os + + +class ConfigManager: + """Loads and provides access to DCOS configuration from files and env vars.""" + + def __init__(self) -> None: + self._config: Dict[str, Any] = { + "version": "1.0.0", + "max_agents": 100, + "memory_capacity": 1000, + "log_level": "INFO", + } + self._load_env_overrides() + + def _load_env_overrides(self) -> None: + env_prefix = "DCOS_" + for key, value in os.environ.items(): + if key.startswith(env_prefix): + config_key = key[len(env_prefix):].lower().replace("_", ".") + self._config[config_key] = value + + def get(self, key: str, default: Optional[Any] = None) -> Any: + return self._config.get(key, default) + + def set(self, key: str, value: Any) -> None: + self._config[key] = value + + def load_yaml(self, path: str) -> bool: + """Load config from a YAML file. Returns True on success.""" + try: + import yaml + with open(path) as f: + data = yaml.safe_load(f) + if isinstance(data, dict): + self._config.update(data) + return True + except Exception: + return False + + def all_settings(self) -> Dict[str, Any]: + return dict(self._config) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..52b8543 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""DCOS test suite.""" diff --git a/tests/test_agents/__init__.py b/tests/test_agents/__init__.py new file mode 100644 index 0000000..c4c53be --- /dev/null +++ b/tests/test_agents/__init__.py @@ -0,0 +1 @@ +"""Agent subsystem tests.""" diff --git a/tests/test_agents/test_creative.py b/tests/test_agents/test_creative.py new file mode 100644 index 0000000..af1e092 --- /dev/null +++ b/tests/test_agents/test_creative.py @@ -0,0 +1,20 @@ +""" +Tests for CreativeAgent. +""" + +import pytest +from dcos.agents.creative import CreativeAgent + + +class TestCreativeAgent: + def test_generate_idea(self): + agent = CreativeAgent() + idea = agent.generate("sustainable energy") + assert "title" in idea + assert "novelty" in idea + + def test_act(self): + agent = CreativeAgent() + result = agent.act({"prompt": "new product idea"}) + assert "idea" in result + assert result["originality_score"] > 0 diff --git a/tests/test_agents/test_domain.py b/tests/test_agents/test_domain.py new file mode 100644 index 0000000..6f98dce --- /dev/null +++ b/tests/test_agents/test_domain.py @@ -0,0 +1,22 @@ +""" +Tests for DomainExpertAgent. +""" + +import pytest +from dcos.agents.domain import DomainExpertAgent + + +class TestDomainExpertAgent: + def test_domain_initialization(self): + agent = DomainExpertAgent(name="medical", domain="medicine") + assert agent.domain == "medicine" + + def test_answer_question(self): + agent = DomainExpertAgent(domain="physics") + answer = agent.answer("What is gravity?") + assert "[physics]" in answer + + def test_act(self): + agent = DomainExpertAgent(domain="chemistry") + result = agent.act({"question": "What is water?"}) + assert result["domain"] == "chemistry" diff --git a/tests/test_agents/test_ethics.py b/tests/test_agents/test_ethics.py new file mode 100644 index 0000000..8d3adb0 --- /dev/null +++ b/tests/test_agents/test_ethics.py @@ -0,0 +1,29 @@ +""" +Tests for EthicsAgent. +""" + +import pytest +from dcos.agents.ethics import EthicsAgent, EthicalConstraint + + +class TestEthicsAgent: + def test_validate_ethical(self): + agent = EthicsAgent() + result = agent.validate("help the user") + assert len(result) == 0 + + def test_validate_unethical(self): + agent = EthicsAgent() + result = agent.validate("deceive the user") + assert len(result) > 0 + + def test_add_constraint(self): + agent = EthicsAgent() + before = len(agent._constraints) + agent.add_constraint(EthicalConstraint.BENEFICENCE) + assert len(agent._constraints) == before # already present + + def test_act(self): + agent = EthicsAgent() + result = agent.act({"action": "help"}) + assert result["ethical"] is True diff --git a/tests/test_agents/test_logic.py b/tests/test_agents/test_logic.py new file mode 100644 index 0000000..3436a07 --- /dev/null +++ b/tests/test_agents/test_logic.py @@ -0,0 +1,27 @@ +""" +Tests for LogicAgent. +""" + +import pytest +from dcos.agents.logic import LogicAgent + + +class TestLogicAgent: + def test_infer_with_premises(self): + agent = LogicAgent() + conclusion = agent.infer(["A", "B"]) + assert conclusion != "insufficient_premises" + + def test_infer_empty(self): + agent = LogicAgent() + conclusion = agent.infer([]) + assert conclusion == "insufficient_premises" + + def test_act(self): + agent = LogicAgent() + result = agent.act({"premises": ["all humans are mortal", "Socrates is human"]}) + assert result["valid"] is True + + def test_contradiction_detection(self): + agent = LogicAgent() + assert agent.detect_contradiction(["A", "not A"]) is False # placeholder diff --git a/tests/test_agents/test_planning.py b/tests/test_agents/test_planning.py new file mode 100644 index 0000000..1181b73 --- /dev/null +++ b/tests/test_agents/test_planning.py @@ -0,0 +1,32 @@ +""" +Tests for PlanningAgent. +""" + +import pytest +from dcos.agents.planning import PlanningAgent +from dcos.agents.base import AgentRole + + +class TestPlanningAgent: + def test_initialization(self): + agent = PlanningAgent() + assert agent.identity.name == "planner" + assert agent.identity.role == AgentRole.PLANNER + + def test_act_returns_plan(self): + agent = PlanningAgent() + result = agent.act({"goal": "test_goal"}) + assert "plan" in result + assert "steps" in result + + def test_decompose_goal(self): + agent = PlanningAgent() + tasks = agent.decompose("complex_goal") + assert len(tasks) > 0 + assert tasks[0]["id"] == "research" + + def test_capabilities(self): + agent = PlanningAgent() + caps = agent.get_capabilities() + assert "strategic_planning" in caps + assert "task_decomposition" in caps diff --git a/tests/test_agents/test_research.py b/tests/test_agents/test_research.py new file mode 100644 index 0000000..8d44fc6 --- /dev/null +++ b/tests/test_agents/test_research.py @@ -0,0 +1,24 @@ +""" +Tests for ResearchAgent. +""" + +import pytest +from dcos.agents.research import ResearchAgent + + +class TestResearchAgent: + def test_initialization(self): + agent = ResearchAgent() + assert agent.identity.name == "researcher" + + def test_research(self): + agent = ResearchAgent() + result = agent.research("AI safety", depth=3) + assert result["topic"] == "AI safety" + assert len(result["key_findings"]) == 3 + + def test_act(self): + agent = ResearchAgent() + result = agent.act({"query": "test query"}) + assert "findings" in result + assert result["confidence"] > 0 diff --git a/tests/test_agents/test_simulation.py b/tests/test_agents/test_simulation.py new file mode 100644 index 0000000..28bbfed --- /dev/null +++ b/tests/test_agents/test_simulation.py @@ -0,0 +1,20 @@ +""" +Tests for SimulationAgent. +""" + +import pytest +from dcos.agents.simulation import SimulationAgent + + +class TestSimulationAgent: + def test_simulate(self): + agent = SimulationAgent() + result = agent.simulate("market_scenario", iterations=100) + assert result["scenario"] == "market_scenario" + assert "success_probability" in result + + def test_act(self): + agent = SimulationAgent() + result = agent.act({"scenario": "test"}) + assert "result" in result + assert result["iterations"] == 1000 diff --git a/tests/test_communication/__init__.py b/tests/test_communication/__init__.py new file mode 100644 index 0000000..85f867d --- /dev/null +++ b/tests/test_communication/__init__.py @@ -0,0 +1 @@ +"""Communication subsystem tests.""" diff --git a/tests/test_communication/test_network.py b/tests/test_communication/test_network.py new file mode 100644 index 0000000..1510342 --- /dev/null +++ b/tests/test_communication/test_network.py @@ -0,0 +1,36 @@ +""" +Tests for CommunicationNetwork. +""" + +import pytest +from dcos.communication.network import CommunicationNetwork +from dcos.communication.protocol import Message + + +class TestCommunicationNetwork: + def test_connect_and_deliver(self): + net = CommunicationNetwork() + net.connect("a", "b") + msg = Message(sender="a", recipient="b", payload="test") + assert net.deliver(msg) is True + + def test_disconnect(self): + net = CommunicationNetwork() + net.connect("a", "b") + net.disconnect("a", "b") + msg = Message(sender="a", recipient="b", payload="test") + assert net.deliver(msg) is False + + def test_broadcast(self): + net = CommunicationNetwork() + net.connect("a", "b") + net.connect("a", "c") + count = net.broadcast("a", "broadcast message") + assert count == 2 + + def test_get_peers(self): + net = CommunicationNetwork() + net.connect("x", "y") + net.connect("x", "z") + peers = net.get_peers("x") + assert len(peers) == 2 diff --git a/tests/test_communication/test_protocol.py b/tests/test_communication/test_protocol.py new file mode 100644 index 0000000..02ad2ff --- /dev/null +++ b/tests/test_communication/test_protocol.py @@ -0,0 +1,26 @@ +""" +Tests for CommunicationProtocol. +""" + +import pytest +from dcos.communication.protocol import CommunicationProtocol, Message + + +class TestCommunicationProtocol: + def test_encode_decode(self): + proto = CommunicationProtocol() + msg = Message(sender="alice", recipient="bob", payload="hello") + encoded = proto.encode(msg) + assert encoded["sender"] == "alice" + assert encoded["recipient"] == "bob" + + decoded = proto.decode(encoded) + assert decoded.payload == "hello" + + def test_send_and_ack(self): + proto = CommunicationProtocol() + msg = Message(sender="a", recipient="b", payload="data") + assert proto.send(msg) is True + ack = proto.ack(msg.msg_id) + assert ack is not None + assert ack.msg_id == msg.msg_id diff --git a/tests/test_communication/test_resolver.py b/tests/test_communication/test_resolver.py new file mode 100644 index 0000000..9550037 --- /dev/null +++ b/tests/test_communication/test_resolver.py @@ -0,0 +1,27 @@ +""" +Tests for AddressResolver. +""" + +import pytest +from dcos.communication.resolver import AddressResolver + + +class TestAddressResolver: + def test_resolve_by_name(self): + resolver = AddressResolver() + resolver.register("planner", "agent_001", role="planner") + assert resolver.resolve_by_name("planner") == "agent_001" + + def test_resolve_by_role(self): + resolver = AddressResolver() + resolver.register("planner1", "agent_001", role="planner") + resolver.register("planner2", "agent_002", role="planner") + planners = resolver.resolve_by_role("planner") + assert len(planners) == 2 + + def test_unregister(self): + resolver = AddressResolver() + resolver.register("temp", "agent_temp") + removed = resolver.unregister("temp") + assert removed == "agent_temp" + assert resolver.resolve_by_name("temp") is None diff --git a/tests/test_communication/test_router.py b/tests/test_communication/test_router.py new file mode 100644 index 0000000..e7528bf --- /dev/null +++ b/tests/test_communication/test_router.py @@ -0,0 +1,32 @@ +""" +Tests for MessageRouter. +""" + +import pytest +from dcos.communication.router import MessageRouter +from dcos.communication.protocol import Message + + +class TestMessageRouter: + def test_register_and_route(self): + router = MessageRouter() + router.register("weather", "agent_weather") + msg = Message(sender="user", recipient="", payload="weather forecast") + target = router.route(msg) + assert target == "agent_weather" + + def test_fallback(self): + router = MessageRouter() + router.set_fallback("default_agent") + msg = Message(sender="user", recipient="", payload="unknown topic") + target = router.route(msg) + assert target == "default_agent" + + def test_unregister(self): + router = MessageRouter() + router.register("key", "agent") + removed = router.unregister("key") + assert removed == "agent" + msg = Message(sender="user", recipient="", payload="key data") + target = router.route(msg) + assert target is None diff --git a/tests/test_core/__init__.py b/tests/test_core/__init__.py new file mode 100644 index 0000000..58e0f57 --- /dev/null +++ b/tests/test_core/__init__.py @@ -0,0 +1 @@ +"""Core subsystem tests.""" diff --git a/tests/test_core/test_allocator.py b/tests/test_core/test_allocator.py new file mode 100644 index 0000000..d600384 --- /dev/null +++ b/tests/test_core/test_allocator.py @@ -0,0 +1,37 @@ +""" +Tests for ResourceAllocator. +""" + +import pytest +from dcos.core.allocator import ResourceAllocator + + +class TestResourceAllocator: + def test_allocate(self): + alloc = ResourceAllocator() + assert alloc.allocate("agent_1", cpu=10.0, memory=256.0) is True + + def test_allocate_over_limit(self): + alloc = ResourceAllocator() + # Total is 100 CPU, 1024 memory + assert alloc.allocate("agent_1", cpu=60.0, memory=512.0) is True + assert alloc.allocate("agent_2", cpu=50.0, memory=512.0) is False # over CPU + + def test_release(self): + alloc = ResourceAllocator() + alloc.allocate("agent_1", cpu=10.0, memory=128.0) + assert alloc.release("agent_1") is True + assert alloc.release("nonexistent") is False + + def test_utilization(self): + alloc = ResourceAllocator() + alloc.allocate("agent_1", cpu=25.0, memory=256.0) + util = alloc.utilization() + assert util["cpu"] == 0.25 + assert util["memory"] == 0.25 + + def test_get_allocation(self): + alloc = ResourceAllocator() + alloc.allocate("agent_1", cpu=10.0, memory=128.0) + alloc_info = alloc.get_allocation("agent_1") + assert alloc_info["cpu"] == 10.0 diff --git a/tests/test_core/test_registry.py b/tests/test_core/test_registry.py new file mode 100644 index 0000000..6e39a1c --- /dev/null +++ b/tests/test_core/test_registry.py @@ -0,0 +1,46 @@ +""" +Tests for the AgentRegistry. +""" + +import pytest +from dcos.core.registry import AgentRegistry, AgentRecord + + +class TestAgentRegistry: + def test_register_and_get(self): + registry = AgentRegistry() + record = AgentRecord(agent_id="a1", name="test-agent", role="planner") + registry.register(record) + retrieved = registry.get("a1") + assert retrieved is not None + assert retrieved.name == "test-agent" + + def test_unregister(self): + registry = AgentRegistry() + record = AgentRecord(agent_id="a2", name="removable", role="researcher") + registry.register(record) + removed = registry.unregister("a2") + assert removed is not None + assert registry.get("a2") is None + + def test_find_by_role(self): + registry = AgentRegistry() + registry.register(AgentRecord(agent_id="a1", name="planner-1", role="planner")) + registry.register(AgentRecord(agent_id="a2", name="planner-2", role="planner")) + registry.register(AgentRecord(agent_id="a3", name="researcher", role="researcher")) + planners = registry.find_by_role("planner") + assert len(planners) == 2 + + def test_find_by_capability(self): + registry = AgentRegistry() + registry.register(AgentRecord(agent_id="a1", name="capable", role="planner", capabilities=["ml", "nlp"])) + registry.register(AgentRecord(agent_id="a2", name="other", role="researcher", capabilities=["search"])) + ml_agents = registry.find_by_capability("ml") + assert len(ml_agents) == 1 + assert ml_agents[0].agent_id == "a1" + + def test_count(self): + registry = AgentRegistry() + assert registry.count() == 0 + registry.register(AgentRecord(agent_id="a1", name="only", role="planner")) + assert registry.count() == 1 diff --git a/tests/test_core/test_scheduler.py b/tests/test_core/test_scheduler.py new file mode 100644 index 0000000..1661661 --- /dev/null +++ b/tests/test_core/test_scheduler.py @@ -0,0 +1,51 @@ +""" +Tests for the TaskScheduler. +""" + +import pytest +from dcos.core.scheduler import TaskScheduler, Task + + +class TestTaskScheduler: + def test_enqueue_dequeue(self): + scheduler = TaskScheduler() + task = Task(name="test", agent_id="agent_1", priority=5) + scheduler.enqueue(task) + dequeued = scheduler.dequeue() + assert dequeued is not None + assert dequeued.name == "test" + assert dequeued.status.name == "RUNNING" + + def test_priority_ordering(self): + scheduler = TaskScheduler() + t1 = Task(name="low", agent_id="a1", priority=1) + t2 = Task(name="high", agent_id="a2", priority=10) + scheduler.enqueue(t1) + scheduler.enqueue(t2) + first = scheduler.dequeue() + assert first is not None and first.name == "high" + + def test_complete_task(self): + scheduler = TaskScheduler() + task = Task(name="done", agent_id="a1") + scheduler.enqueue(task) + dequeued = scheduler.dequeue() + assert dequeued is not None + result = scheduler.complete(dequeued.id) + assert result is True + + def test_dependency_wait(self): + scheduler = TaskScheduler() + dep = Task(name="dependency", agent_id="a1") + main = Task(name="main", agent_id="a2", depends_on=[dep.id]) + scheduler.enqueue(dep) + scheduler.enqueue(main) + # Only dep should dequeue since main depends on dep + first = scheduler.dequeue() + assert first is not None and first.name == "dependency" + second = scheduler.dequeue() + assert second is None # main still blocked + + def test_empty_queue(self): + scheduler = TaskScheduler() + assert scheduler.dequeue() is None diff --git a/tests/test_integration/__init__.py b/tests/test_integration/__init__.py new file mode 100644 index 0000000..c210fac --- /dev/null +++ b/tests/test_integration/__init__.py @@ -0,0 +1 @@ +"""Integration tests.""" diff --git a/tests/test_integration/test_agent_collaboration.py b/tests/test_integration/test_agent_collaboration.py new file mode 100644 index 0000000..ec90329 --- /dev/null +++ b/tests/test_integration/test_agent_collaboration.py @@ -0,0 +1,50 @@ +""" +Integration tests for agent collaboration workflows. +""" + +import pytest +from dcos.core.scheduler import TaskScheduler, Task +from dcos.core.registry import AgentRegistry, AgentRecord +from dcos.core.coordinator import AgentCoordinator +from dcos.agents.planning import PlanningAgent +from dcos.agents.research import ResearchAgent + + +class TestAgentCollaboration: + def test_scheduler_registry_integration(self): + """Verify scheduler and registry work together.""" + scheduler = TaskScheduler() + registry = AgentRegistry() + + registry.register(AgentRecord(agent_id="a1", name="planner", role="planner")) + task = Task(name="plan", agent_id="a1") + scheduler.enqueue(task) + dequeued = scheduler.dequeue() + assert dequeued is not None + record = registry.get("a1") + assert record is not None + + def test_planner_researcher_collaboration(self): + """Verify planner can decompose and researcher can fulfill.""" + planner = PlanningAgent() + researcher = ResearchAgent() + + tasks = planner.decompose("research_project") + assert len(tasks) > 0 + + research_result = researcher.research(tasks[0]["id"], depth=2) + assert research_result["topic"] == tasks[0]["id"] + + def test_coordinator_workflow(self): + """Verify coordinator can orchestrate a workflow.""" + coord = AgentCoordinator() + coord.create_workflow("wf_1", ["planner", "researcher", "logician"]) + assert coord.get_workflow_status("wf_1") is not None + assert coord.get_workflow_status("wf_1")["status"] == "created" + + assigned = coord.assign_task("wf_1", "researcher", "Gather data") + assert assigned is True + + coord.complete_workflow("wf_1") + status = coord.get_workflow_status("wf_1") + assert status["status"] == "completed" diff --git a/tests/test_learning/__init__.py b/tests/test_learning/__init__.py new file mode 100644 index 0000000..b2cb177 --- /dev/null +++ b/tests/test_learning/__init__.py @@ -0,0 +1 @@ +"""Learning engine tests.""" diff --git a/tests/test_learning/test_engine.py b/tests/test_learning/test_engine.py new file mode 100644 index 0000000..6107900 --- /dev/null +++ b/tests/test_learning/test_engine.py @@ -0,0 +1,25 @@ +""" +Tests for LearningEngine. +""" + +import pytest +from dcos.learning.engine import LearningEngine, Experience + + +class TestLearningEngine: + def test_record_experience(self): + engine = LearningEngine() + engine.record_experience(Experience(state={}, action="move", reward=1.0)) + assert engine.experience_count() == 1 + + def test_best_action(self): + engine = LearningEngine() + engine.record_experience(Experience(state={}, action="a", reward=10)) + engine.record_experience(Experience(state={}, action="b", reward=5)) + best = engine.best_action(["a", "b"]) + assert best == "a" + + def test_get_action_score(self): + engine = LearningEngine() + engine.record_experience(Experience(state={}, action="explore", reward=0.5)) + assert engine.get_action_score("explore") == 0.05 # 0.5 * 0.1 diff --git a/tests/test_memory/__init__.py b/tests/test_memory/__init__.py new file mode 100644 index 0000000..dcfe60f --- /dev/null +++ b/tests/test_memory/__init__.py @@ -0,0 +1 @@ +"""Memory subsystem tests.""" diff --git a/tests/test_memory/test_conversation.py b/tests/test_memory/test_conversation.py new file mode 100644 index 0000000..ebe9db4 --- /dev/null +++ b/tests/test_memory/test_conversation.py @@ -0,0 +1,35 @@ +""" +Tests for ConversationMemory. +""" + +import pytest +from dcos.memory.conversation import ConversationMemory + + +class TestConversationMemory: + def test_create_conversation(self): + mem = ConversationMemory() + conv = mem.create("conv_1", ["agent_a", "agent_b"]) + assert conv.conversation_id == "conv_1" + assert len(conv.participants) == 2 + + def test_add_turn(self): + mem = ConversationMemory() + mem.create("conv_1", ["alice", "bob"]) + turn = mem.add_turn("conv_1", "alice", "Hello Bob!") + assert turn is not None + assert turn.content == "Hello Bob!" + + def test_get_history(self): + mem = ConversationMemory() + mem.create("conv_1", ["a", "b"]) + mem.add_turn("conv_1", "a", "msg1") + mem.add_turn("conv_1", "b", "msg2") + history = mem.get_history("conv_1") + assert history is not None + assert len(history) == 2 + + def test_missing_conversation(self): + mem = ConversationMemory() + assert mem.add_turn("nonexistent", "a", "msg") is None + assert mem.get_history("nonexistent") is None diff --git a/tests/test_memory/test_episodic.py b/tests/test_memory/test_episodic.py new file mode 100644 index 0000000..c8adc42 --- /dev/null +++ b/tests/test_memory/test_episodic.py @@ -0,0 +1,33 @@ +""" +Tests for EpisodicMemory. +""" + +import pytest +from dcos.memory.episodic import EpisodicMemory + + +class TestEpisodicMemory: + def test_record_and_recall(self): + mem = EpisodicMemory() + ep = mem.record({"action": "test"}, "success", "test episode") + assert ep.summary == "test episode" + + def test_recall_recent(self): + mem = EpisodicMemory() + for i in range(5): + mem.record({"i": i}, f"outcome_{i}") + recent = mem.recall_recent(3) + assert len(recent) == 3 + + def test_search_by_context(self): + mem = EpisodicMemory() + mem.record({"type": "exploration"}, "found gold") + mem.record({"type": "exploitation"}, "mined ore") + results = mem.search_by_context("type", "exploration") + assert len(results) == 1 + + def test_count(self): + mem = EpisodicMemory() + assert mem.episode_count() == 0 + mem.record({}, "outcome") + assert mem.episode_count() == 1 diff --git a/tests/test_memory/test_long_term.py b/tests/test_memory/test_long_term.py new file mode 100644 index 0000000..76a4601 --- /dev/null +++ b/tests/test_memory/test_long_term.py @@ -0,0 +1,30 @@ +""" +Tests for LongTermMemory. +""" + +import pytest +from dcos.memory.long_term import LongTermMemory, Importance + + +class TestLongTermMemory: + def test_commit_and_recall(self): + mem = LongTermMemory() + mem.commit("important_fact", "AI is valuable", Importance.HIGH) + assert mem.recall("important_fact") == "AI is valuable" + + def test_recall_missing(self): + mem = LongTermMemory() + assert mem.recall("nonexistent") is None + + def test_consolidate(self): + mem = LongTermMemory() + count = mem.consolidate({"temp": "data"}) + assert count == 1 + assert mem.recall("temp") == "data" + + def test_search(self): + mem = LongTermMemory() + mem.commit("python_info", "Python is a language", Importance.MEDIUM) + mem.commit("java_info", "Java is a language", Importance.MEDIUM) + results = mem.search("python") + assert len(results) > 0 diff --git a/tests/test_memory/test_memory_facade.py b/tests/test_memory/test_memory_facade.py new file mode 100644 index 0000000..4873352 --- /dev/null +++ b/tests/test_memory/test_memory_facade.py @@ -0,0 +1,25 @@ +""" +Tests for MemoryFacade. +""" + +import pytest +from dcos.memory.memory_facade import MemoryFacade + + +class TestMemoryFacade: + def test_remember_and_recall(self): + facade = MemoryFacade() + facade.remember("key", "value", importance="low") + assert facade.recall("key") == "value" + + def test_search(self): + facade = MemoryFacade() + facade.remember("important", "data", importance="high") + results = facade.search("important") + assert "long_term" in results + + def test_summary(self): + facade = MemoryFacade() + summary = facade.summary() + assert "working" in summary + assert "episodic" in summary diff --git a/tests/test_memory/test_procedural.py b/tests/test_memory/test_procedural.py new file mode 100644 index 0000000..92c9a38 --- /dev/null +++ b/tests/test_memory/test_procedural.py @@ -0,0 +1,33 @@ +""" +Tests for ProceduralMemory. +""" + +import pytest +from dcos.memory.procedural import ProceduralMemory + + +class TestProceduralMemory: + def test_register_procedure(self): + mem = ProceduralMemory() + mem.register_procedure("build", ["init", "compile", "link"]) + proc = mem.get_procedure("build") + assert proc is not None + assert len(proc["steps"]) == 3 + + def test_execute_procedure(self): + mem = ProceduralMemory() + mem.register_procedure("test_proc", ["step1", "step2"]) + result = mem.execute_procedure("test_proc", {}) + assert result["executed"] is True + + def test_missing_procedure(self): + mem = ProceduralMemory() + with pytest.raises(KeyError): + mem.execute_procedure("nonexistent", {}) + + def test_list_procedures(self): + mem = ProceduralMemory() + mem.register_procedure("a", ["a1"]) + mem.register_procedure("b", ["b1"]) + procs = mem.list_procedures() + assert len(procs) == 2 diff --git a/tests/test_memory/test_semantic.py b/tests/test_memory/test_semantic.py new file mode 100644 index 0000000..eee79da --- /dev/null +++ b/tests/test_memory/test_semantic.py @@ -0,0 +1,27 @@ +""" +Tests for SemanticMemory. +""" + +import pytest +from dcos.memory.semantic import SemanticMemory + + +class TestSemanticMemory: + def test_add_and_get_fact(self): + mem = SemanticMemory() + mem.add_fact("dog", "species", "canine") + assert mem.get_fact("dog", "species") == "canine" + + def test_add_relationship(self): + mem = SemanticMemory() + mem.add_relationship("dog", "wolf") + related = mem.get_related("dog") + assert "wolf" in related + assert "dog" in mem.get_related("wolf") + + def test_query(self): + mem = SemanticMemory() + mem.add_fact("cat", "species", "feline") + mem.add_fact("lion", "species", "feline") + results = mem.query("species", "feline") + assert len(results) == 2 diff --git a/tests/test_memory/test_working.py b/tests/test_memory/test_working.py new file mode 100644 index 0000000..ba674a7 --- /dev/null +++ b/tests/test_memory/test_working.py @@ -0,0 +1,42 @@ +""" +Tests for WorkingMemory. +""" + +import pytest +from dcos.memory.working import WorkingMemory + + +class TestWorkingMemory: + def test_store_and_recall(self): + mem = WorkingMemory() + mem.store("key1", "value1") + assert mem.recall("key1") == "value1" + + def test_overwrite(self): + mem = WorkingMemory() + mem.store("k", "v1") + mem.store("k", "v2") + assert mem.recall("k") == "v2" + + def test_missing_key(self): + mem = WorkingMemory() + assert mem.recall("nonexistent") is None + + def test_contains(self): + mem = WorkingMemory() + mem.store("present", "data") + assert mem.contains("present") is True + assert mem.contains("absent") is False + + def test_clear(self): + mem = WorkingMemory() + mem.store("a", 1) + mem.store("b", 2) + mem.clear() + assert mem.size() == 0 + + def test_capacity(self): + mem = WorkingMemory(capacity=5) + for i in range(10): + mem.store(f"key{i}", i) + assert mem.size() <= 5 diff --git a/tests/test_memory/test_world_model.py b/tests/test_memory/test_world_model.py new file mode 100644 index 0000000..069008e --- /dev/null +++ b/tests/test_memory/test_world_model.py @@ -0,0 +1,35 @@ +""" +Tests for WorldModel. +""" + +import pytest +from dcos.memory.world_model import WorldModel + + +class TestWorldModel: + def test_add_and_get_entity(self): + model = WorldModel() + model.add_entity("e1", {"type": "robot", "status": "active"}) + entity = model.get_entity("e1") + assert entity is not None + assert entity["properties"]["type"] == "robot" + + def test_update_entity(self): + model = WorldModel() + model.add_entity("e1", {"status": "inactive"}) + model.update_entity("e1", {"status": "active"}) + entity = model.get_entity("e1") + assert entity["properties"]["status"] == "active" + + def test_set_and_get_state(self): + model = WorldModel() + model.set_state("phase", "exploration") + assert model.get_state("phase") == "exploration" + + def test_query_entities(self): + model = WorldModel() + model.add_entity("drone1", {"type": "drone", "team": "alpha"}) + model.add_entity("drone2", {"type": "drone", "team": "beta"}) + model.add_entity("robot1", {"type": "robot", "team": "alpha"}) + drones = model.query_entities("type", "drone") + assert len(drones) == 2 diff --git a/tests/test_protocols/__init__.py b/tests/test_protocols/__init__.py new file mode 100644 index 0000000..31c6050 --- /dev/null +++ b/tests/test_protocols/__init__.py @@ -0,0 +1 @@ +"""Protocol tests.""" diff --git a/tests/test_protocols/test_external_tools.py b/tests/test_protocols/test_external_tools.py new file mode 100644 index 0000000..5ba3297 --- /dev/null +++ b/tests/test_protocols/test_external_tools.py @@ -0,0 +1,35 @@ +""" +Tests for ExternalTools. +""" + +import pytest +from dcos.protocols.external_tools import ExternalTools + + +def sample_handler(param: str) -> str: + return f"handled: {param}" + + +class TestExternalTools: + def test_register_and_execute(self): + tools = ExternalTools() + tools.register_tool("sample", sample_handler) + result = tools.execute("sample", {"param": "test"}) + assert result == "handled: test" + + def test_list_tools(self): + tools = ExternalTools() + tools.register_tool("tool_a", sample_handler) + tools.register_tool("tool_b", sample_handler) + assert len(tools.list_tools()) == 2 + + def test_missing_tool(self): + tools = ExternalTools() + with pytest.raises(KeyError): + tools.execute("nonexistent", {}) + + def test_get_result(self): + tools = ExternalTools() + tools.register_tool("calc", sample_handler) + tools.execute("calc", {"param": "42"}) + assert tools.get_result("calc") == "handled: 42" diff --git a/tests/test_protocols/test_user_interface.py b/tests/test_protocols/test_user_interface.py new file mode 100644 index 0000000..267ac87 --- /dev/null +++ b/tests/test_protocols/test_user_interface.py @@ -0,0 +1,27 @@ +""" +Tests for UserInterface. +""" + +import pytest +from dcos.protocols.user_interface import UserInterface, UserRequest, SystemResponse + + +class TestUserInterface: + def test_process_input(self): + ui = UserInterface() + request = UserRequest(input="hello", user_id="user_1") + parsed = ui.process_input(request) + assert parsed["intent"] == "query" + + def test_format_response(self): + ui = UserInterface() + response = SystemResponse(output="Hello!", agent_id="agent_1") + formatted = ui.format_response(response) + assert "[agent_1]" in formatted + + def test_history(self): + ui = UserInterface() + ui.format_response(SystemResponse(output="msg1", agent_id="a")) + ui.format_response(SystemResponse(output="msg2", agent_id="b")) + history = ui.get_history() + assert len(history) == 2 diff --git a/tests/test_utils/__init__.py b/tests/test_utils/__init__.py new file mode 100644 index 0000000..f049f9e --- /dev/null +++ b/tests/test_utils/__init__.py @@ -0,0 +1 @@ +"""Utilities tests.""" diff --git a/tests/test_utils/test_cli.py b/tests/test_utils/test_cli.py new file mode 100644 index 0000000..cfc4e1d --- /dev/null +++ b/tests/test_utils/test_cli.py @@ -0,0 +1,26 @@ +""" +Tests for CLI module. +""" + +import pytest +from dcos.utils.cli import main + + +class TestCLI: + def test_version(self): + result = main(["--version"]) + assert result == 0 + + def test_status(self): + result = main(["status"]) + assert result == 0 + + def test_info(self): + result = main(["info"]) + assert result == 0 + + def test_unknown_command(self): + with pytest.raises(SystemExit) as exc: + main(["badcommand"]) + # argparse exits with code 2 for invalid choices + assert exc.value.code == 2 diff --git a/tests/test_utils/test_config.py b/tests/test_utils/test_config.py new file mode 100644 index 0000000..7d46b8a --- /dev/null +++ b/tests/test_utils/test_config.py @@ -0,0 +1,27 @@ +""" +Tests for ConfigManager. +""" + +import pytest +from dcos.utils.config import ConfigManager + + +class TestConfigManager: + def test_get_default(self): + config = ConfigManager() + assert config.get("version") == "1.0.0" + + def test_set_and_get(self): + config = ConfigManager() + config.set("custom_key", "custom_value") + assert config.get("custom_key") == "custom_value" + + def test_get_missing_default(self): + config = ConfigManager() + assert config.get("nonexistent", "fallback") == "fallback" + + def test_all_settings(self): + config = ConfigManager() + settings = config.all_settings() + assert "version" in settings + assert "max_agents" in settings