Skip to content

Releases: cortxai/COREtex

v0.4.5 — COREtex Pipeline System

09 Mar 13:10
f95e5a9

Choose a tag to compare

Overview

This release introduces the COREtex Pipeline System — a configurable, structured execution pipeline that replaces the previously hardcoded classifier → router → worker → executor flow with a modular, registry-backed design.

Building on v0.3.26 Runtime Stabilisation, the platform can now represent pipelines as first-class objects. Pipelines are defined declaratively, registered at startup, and resolved at runtime — making them replaceable without modifying the runtime core.

The default pipeline preserves full backward compatibility: all existing /ingest and OpenWebUI endpoints behave identically to v0.3.26.


✨ Features & Improvements

Pipeline Definition Objects

Two new dataclasses in coretex/runtime/pipeline.py formalise pipeline structure:

  • PipelineStep — a single step with a component_type and name. The component_type is statically typed as Literal["classifier", "router", "worker", "tool_executor"] and validated at construction time via __post_init__. Invalid types raise a descriptive ValueError immediately.
  • PipelineDefinition — an ordered sequence of PipelineStep objects, identified by a name used in observability logs. Provides a get_step(component_type) helper for step lookup.

A make_default_pipeline() factory produces the standard four-step pipeline:

ClassifierBasic → RouterSimple → WorkerLLM → ToolExecutor

This is registered as "default" at startup and is functionally identical to the pre-v0.4.0 hardcoded behaviour.


PipelineRegistry Enhancements

PipelineRegistry is now a fully validated, type-safe registry for PipelineDefinition objects:

  • register(name, pipeline) — raises ValueError("Pipeline already registered: <name>") on duplicates
  • get(name) — raises ValueError("Unknown pipeline: <name>") and logs event=registry_lookup_failed on unknown lookup
  • list() — enumerates all registered pipeline names
  • All type signatures use PipelineDefinition directly (no object fallback), enforcing type safety at the registry boundary

PipelineRunner Refactor

PipelineRunner now accepts a pipeline: Optional[PipelineDefinition] argument:

  • Component names (classifier_name, router_name, worker_name) are resolved from the pipeline definition at construction time
  • If no pipeline is supplied, make_default_pipeline() is used — preserving pre-v0.4.0 behaviour
  • All failure handling, latency metrics, and structured log events are fully preserved

Observability: Pipeline Selection Logging

Every request now emits two structured log events at the start of execution, in logical order:

event=request_received  request_id=<id>
event=pipeline_selected request_id=<id> pipeline=<name>

This makes the active pipeline fully visible in logs for every request without any additional tooling.


Bootstrap & Distribution Wiring

distributions/cortx/bootstrap.py now creates a PipelineRegistry singleton and registers the default pipeline at startup. main.py retrieves the pipeline definition from the registry and passes it to PipelineRunner, completing the end-to-end pipeline system integration.


Expanded Test Suite

  • Test coverage increased from 106 to 129 tests (+23)
  • New tests cover:
    • PipelineStep valid and invalid component_type values
    • PipelineDefinition construction, get_step(), and empty steps
    • make_default_pipeline() name, step count, and step names
    • PipelineRegistry duplicate registration, unknown lookup, list(), and event=registry_lookup_failed log
    • PipelineRunner component name resolution from pipeline definition
    • PipelineRunner default pipeline fallback when pipeline=None
    • Bootstrap default pipeline registration
    • event=pipeline_selected log emission and pipeline name in log
    • Full async request execution with a custom PipelineDefinition
  • Ollama calls remain fully mocked → deterministic CI/CD testing

🧱 Architecture Update

The execution architecture is unchanged — the pipeline system is a structural layer around the same runtime behaviour:

User (browser)
└─► OpenWebUI (port 3000)
    └─► POST /v1/chat/completions
        └─► POST /ingest
            └─► PipelineRunner.run(ExecutionContext)
                │   [pipeline resolved from PipelineRegistry at startup]
                ├─► ClassifierBasic.classify()  → ClassificationResult(intent, confidence)
                ├─► RouterSimple.route(intent)  → handler name
                └─► WorkerLLM.generate()        → JSON action envelope
                    │
                    parse_agent_output → AgentAction
                    │
                    ToolExecutor.execute → tool result or direct content

The two-LLM-call invariant, deterministic routing, and strict agent-tool separation are all preserved.


🎯 Design Principles Reinforced

  • Everything is replaceable — classifier, router, worker, and tool executor are all resolved by name from registries at runtime; swapping any component requires only a new pipeline registration
  • Explicit pipelines — intelligence flows through declared, inspectable PipelineDefinition objects, not opaque frameworks
  • Single source of truth — the PipelineRegistry is the authoritative store for all pipeline configurations; main.py reads from it, not from hardcoded names
  • Fail-fast validation — invalid step types are rejected at PipelineStep construction, not silently at execution time

⚠️ Current Limitations

No new agent capabilities in this release:

  • Single-action responses only
  • No memory or conversation history
  • No streaming responses
  • No multi-agent or planner orchestration
  • No persistent storage, authentication, or rate limiting
  • Ollama remains the only model backend
  • Async tool execution still not supported
  • Pipeline steps are resolved at PipelineRunner construction — runtime pipeline switching is not yet supported

🚧 Next Steps

  • Model Provider System — introduce ModelProvider abstraction; enable hybrid model strategies (Ollama, OpenAI, Anthropic, llama.cpp)
  • Distribution Layer — first formal CortX distribution (cortx_local) with fully bootstrapped module loading
  • Event System — runtime-wide event bus; every action emits structured events for observability and monitoring
  • Tool System as Modules — refactor tools into replaceable, user-composable modules

All planned improvements will retain deterministic orchestration and full observability.


🧪 Status

v0.4.5 delivers the COREtex Pipeline System with:

  • Declarative PipelineDefinition and PipelineStep primitives
  • Fully validated PipelineRegistry with type-safe signatures
  • PipelineRunner driven by pipeline definitions, not hardcoded names
  • Default pipeline registered at startup, backward compatible with v0.3.26
  • Full event=pipeline_selected observability on every request
  • 129 tests (up from 106), all passing

The platform is now ready for configurable, multi-pipeline workflows on top of the stable deterministic core.


Full Changelog

https://github.com/cortxai/COREtex/commits/feature/v0.4-pipeline-system

v0.3.26 — COREtex Runtime Stabilisation & Hardening

09 Mar 11:44
427a80e

Choose a tag to compare

Overview

This release stabilises the COREtex runtime platform and hardens the deterministic tool execution pipeline introduced in previous versions.

Building on v0.3.x Stabilisation, the platform now features full lifecycle logging, registry safety enforcement, and expanded test coverage, ensuring that all modules, tools, and pipelines behave predictably and failures are fully observable.

No new agent capabilities (planners, memory, multi-agent workflows) have been introduced — the focus is robustness, maintainability, and observability.


✨ Features & Improvements

Full Log Lifecycle & Failure Transparency

The PipelineRunner now records all pipeline stages and latency metrics with consistent event names. Explicit failure categories are reinforced:

  • Classifier HTTP failure → event=pipeline_classifier_failure
  • Worker HTTP failure → event=pipeline_worker_failure
  • Agent JSON parse error → event=pipeline_agent_parse_failure
  • Tool lookup/runtime error → event=pipeline_tool_failure

Latency metrics are included in all events for observability.


Registry Validation & Safety

All four registries (Module, Tool, ModelProvider, Pipeline) now enforce:

  • Duplicate registration detection → ValueError("Component already registered: <name>")
  • Unknown component access → ValueError("Unknown component: <name>") + event=registry_lookup_failed
  • Explicit logging on successful and failed lookups
  • list() and mark_loaded() consistency for all module types

This ensures deterministic behaviour across all modules and tools.


ModuleLoader Hardening

Module loading now validates:

  1. Module import → logs event=module_import_failed on ImportError
  2. Presence of register(module_registry, tool_registry, model_registry) function → raises ValueError if missing
  3. Signature validation → ensures all three required parameters exist
  4. Lifecycle events:
    • event=module_loading_start
    • event=module_loaded module=<name> registered_components=N
    • Warnings emitted if no components registered

These changes make module integration safe and predictable.


ExecutionContext Enhancements

ExecutionContext now captures:

  • metadata: Optional[Dict[str, Any]] for module-specific contextual data
  • timestamp: float wall-clock time in addition to t_start monotonic timestamp

This enables improved observability and traceability of request flows.


ToolExecutor & AgentAction Stability

  • ToolExecutor.execute() now fully validates AgentAction inputs
  • Unknown actions or missing tool names raise structured ValueErrors
  • Logs all tool execution steps (event=tool_execute / event=tool_execute_complete)
  • parse_agent_output() robustly handles malformed JSON, markdown fences, or unexpected fields
  • Safe fallback: raw output returned to user if parsing fails

Expanded Test Suite

  • Test coverage increased to 106 unit + integration tests
  • Includes:
    • ModuleLoader import/signature/empty-registration tests
    • Registry duplicate and unknown lookup tests
    • Pipeline failure scenarios
    • ToolExecutor dispatch and error handling
    • parse_agent_output valid/invalid cases
    • Router debug logging
    • ExecutionContext timestamp and metadata validation
  • Ollama calls remain fully mocked → deterministic CI/CD testing

🧱 Architecture Update

No functional changes to pipeline execution — the current architecture remains:

User (browser)
└─► OpenWebUI (port 3000)
└─► POST /v1/chat/completions
└─► POST /ingest
└─► PipelineRunner.run(ExecutionContext)
├─► ClassifierBasic.classify() → ClassificationResult(intent, confidence)
├─► RouterSimple.route(intent) → handler name
└─► WorkerLLM.generate() → JSON action envelope
│
parse_agent_output → AgentAction
│
ToolExecutor.execute → tool result or direct content

This maintains the two-LLM-call invariant, deterministic routing, and strict agent-tool separation.


🎯 Design Principles Reinforced

  • Deterministic Execution — all tools executed only through ToolExecutor
  • Separation of Concerns — agents decide actions; system executes
  • Explicit Capabilities — all tools registered at startup
  • Robust Failure Handling — pipeline resilient to HTTP errors, invalid JSON, unknown tools

⚠️ Current Limitations

No major new capabilities:

  • Single-action responses only
  • No memory or conversation history
  • No streaming responses
  • No multi-agent or planner orchestration
  • No persistent storage, authentication, or rate limiting
  • Ollama remains the only model backend
  • Async tool execution still not supported

🚧 Next Steps

  • Tool Ecosystem Expansion — HTTP, database, shell, vector search, structured data
  • Planner & Task Graphs — deterministic multi-step execution graphs
  • Multi-Agent Workflows — orchestrated task pipelines
  • Persistent Memory — optional local-first memory layer

All planned improvements will retain deterministic orchestration and observability.


🧪 Status

v0.3.26 stabilises the COREtex runtime with:

  • Hardened module loading and registry safety
  • Full structured logging of pipelines, tools, and agent outputs
  • Robust AgentAction parsing and safe fallbacks
  • Expanded test coverage (106 tests)
  • Clear separation between runtime, modules, and distributions

The platform is now fully ready for building advanced agent workflows on top of a stable deterministic core.


Full Changelog

https://github.com/philbudden/cortex/commits/v0.3.26

v0.2.0 — Deterministic Tool Execution Layer

08 Mar 10:00
fb35448

Choose a tag to compare

Overview

This release introduces the first deterministic tool execution layer for CortX.

Building on the orchestration foundation established in v0.1.0, the platform can now execute structured actions requested by the worker agent while maintaining the core design goals of transparency, determinism, and local-first operation.

The worker agent now returns a structured JSON action envelope rather than raw text. This output is parsed and executed by a centralised ToolExecutor, ensuring that agents never directly execute tools and that all actions remain observable and controllable.

This phase validates the architecture required for safe agent-tool interaction without introducing autonomous loops or complex planning behaviour.


✨ Features

Deterministic Tool Execution Layer

Agents can now request external actions through a structured JSON interface.

Example agent output:

{
  "action": "tool",
  "tool": "read_file",
  "args": {
    "path": "README.md"
  }
}

The action envelope is parsed and executed by the ToolExecutor, which determines
whether to:

  • return direct content to the user
  • execute a registered tool
  • reject invalid actions

This preserves strict separation between agent reasoning and system execution.


Tool Registry

All available tools are registered in a central ToolRegistry at application startup.

Benefits:

  • deterministic tool lookup
  • prevention of duplicate tool registration
  • explicit declaration of system capabilities

New tools can be added by implementing a tool module and registering it in bootstrap_tools.py.


Filesystem Tool (Initial Capability)

The first tool implementation provides read-only filesystem access.

Tool: read_file

Arguments:

  • path — path to the file to read

Example action:

{
  "action": "tool",
  "tool": "read_file",
  "args": {
    "path": "notes.txt"
  }
}

The tool returns the text content of the file or a safe error message if the file does not exist.

This provides a simple but practical demonstration of agent-driven tool usage.


Structured Agent Output

Worker agents now return structured JSON responses rather than free-form text.

Supported actions:

{"action": "respond", "content": "text to return to the user"}

or

{"action": "tool", "tool": "<tool_name>", "args": {...}}

This structure enables deterministic parsing and execution while keeping the worker model responsible only for deciding what action to request.


Safe Action Parsing

Agent output is parsed through a dedicated parse_agent_output function that:

  • strips markdown fences
  • parses JSON safely
  • validates structure through the AgentAction model
  • logs parsing failures

If parsing fails, the system gracefully falls back to treating the raw output as direct user content.

This ensures the system remains robust to imperfect LLM output.


Tool Execution Logging

Tool execution is fully observable through structured logs.

Example events:

event=agent_output_received
event=tool_execute tool=read_file
event=tool_execute_complete tool=read_file

If a tool lookup fails or execution errors occur, these are logged explicitly, allowing developers to trace the entire execution path.


Expanded Test Coverage

The test suite has been expanded to include comprehensive coverage of the tool execution layer.

New tests validate:

  • tool registration
  • duplicate tool detection
  • tool lookup failures
  • agent action parsing
  • executor dispatch logic
  • graceful fallback behaviour

All Ollama calls remain fully mocked to ensure deterministic tests.


🧱 Updated Architecture

The request pipeline now includes a deterministic tool execution step.

User (browser)
  └► OpenWebUI  (port 3000)
        └► POST /v1/chat/completions
              └► POST /ingest
                    ├► Classifier  — LLM call 1/2 → intent + confidence
                    ├► Router      — pure Python dict lookup → handler
                    └► Worker      — LLM call 2/2 → JSON action envelope
                                │
                          parse_agent_output
                                │
                          ToolExecutor.execute
                                │
                        Tool result or direct response

This architecture preserves the original two-LLM-call invariant while allowing agents to safely request external capabilities.

🎯 Design Principles Reinforced

Deterministic Execution

Tools are executed exclusively through the ToolExecutor, ensuring predictable and auditable behaviour.

Strict Separation of Concerns

Agents decide what action to request, while the system decides how to execute it.

Explicit Capabilities

All available tools are registered at startup rather than discovered dynamically.

Robust Failure Handling

Invalid JSON, unknown tools, or worker failures are handled gracefully without crashing the orchestration pipeline.

⚠️ Current Limitations

This release intentionally avoids more advanced agent capabilities while validating the tool execution architecture.

Still not implemented:

  • multi-step tool chaining
  • planner-driven tool workflows
  • multi-agent collaboration
  • memory or conversation history
  • streaming responses
  • persistent storage
  • authentication or rate limiting
  • multiple model providers

Tool execution currently supports single-action responses only.

🚧 Next Steps

The next development phases will focus on expanding agent capabilities while maintaining deterministic orchestration.

Planned areas of exploration include:

  • Tool Ecosystem Expansion
  • Additional tools such as:
    • HTTP API access
    • database queries
    • vector search
    • shell command execution
    • structured data processing

Planner and Task Graphs

Introducing a deterministic planning layer capable of constructing multi-step execution graphs.

Multi-Agent Workflows

Enabling specialised agents to collaborate through orchestrated task pipelines.

Persistent Memory

Adding optional memory layers while preserving the platform's local-first design.

🧪 Status

This release represents the first operational integration of agent-driven tool execution within the CortX architecture.

The platform now supports:

  • deterministic intent routing
  • structured agent responses
  • safe tool invocation
  • observable execution paths

The system remains intentionally minimal but now establishes the foundation required for building complex agent workflows on top of a deterministic core.

Full Changelog:

https://github.com/philbudden/cortex/commits/v0.2.0

PoC

06 Mar 11:56

Choose a tag to compare

PoC

v0.1.0 — Local-First Agent Orchestration PoC

Overview

This release introduces the first working Proof of Concept for a local-first AI orchestration platform.

The system focuses on clarity, determinism, and debuggability, avoiding opaque “agent frameworks” and instead implementing a simple, inspectable architecture that can serve as a solid foundation for future expansion.

This release establishes the core architecture required to build a reliable agent system before introducing more complex features such as tool execution, memory, or multi-agent orchestration.


✨ Features

Local-First Architecture

The system is designed to run entirely locally, avoiding reliance on cloud services or proprietary platforms.

Key benefits:

  • No external orchestration services
  • Works offline
  • Full control over infrastructure
  • Easy to self-host

Deterministic Intent Routing

User requests are routed through a deterministic intent router rather than relying on emergent LLM behaviour.

This ensures:

  • predictable routing
  • transparent debugging
  • consistent agent selection

Example log line:

event=intent_router request_id=<id> intent=analysis route=worker confidence=0.90 input="Compare Kubernetes and Nomad"

Agent Separation of Concerns

Agents are implemented as focused components responsible for a single domain.

Intent categories:

  • execution — direct task completion (write, generate, create, summarise)
  • planning — step-by-step breakdown (how to build, launch, implement)
  • analysis — open-ended thinking (compare, evaluate, design)

Each intent routes to the same worker with a different prompt template, keeping
response style consistent with what the user asked for.

This avoids the “do-everything agent” anti-pattern common in early agent frameworks.


OpenWebUI as a Thin UI Layer

The UI layer is provided by OpenWebUI, used strictly as a frontend interface.

The orchestration system runs independently and communicates through an API layer.

Benefits:

  • clean separation of UI and orchestration
  • UI can be replaced without changing backend logic
  • orchestration remains framework-agnostic

Transparent Logging

The system emits structured logs for key orchestration steps, enabling full traceability.

Example execution trace:

event=request_received      request_id=<id>
event=classifier_result     request_id=<id> intent=analysis confidence=0.90 source=llm
event=intent_router         request_id=<id> intent=analysis route=worker confidence=0.90
event=worker_start          request_id=<id> worker=worker intent=analysis
event=worker_complete       request_id=<id> worker=worker latency_ms=3240
event=request_complete      request_id=<id> intent=analysis total_latency_ms=5063

This allows developers to understand exactly how a request moved through the system.


🧱 Architecture

Current request flow:

User (browser)
  └► OpenWebUI  (port 3000)
        └► POST /v1/chat/completions  (Ingress API, port 8000)
              └► POST /ingest
                    ├► Classifier  — LLM call 1/2 → intent + confidence
                    ├► Router      — pure Python dict lookup → handler
                    └► Worker      — LLM call 2/2 → response text

The architecture deliberately avoids:

  • hidden agent loops
  • automatic tool execution
  • black-box memory systems
  • implicit orchestration

Every step in the pipeline is explicit and inspectable.


🎯 Design Principles

This project prioritises:

Determinism

Agent behaviour should be predictable and observable.

Local Control

The platform should run entirely on local infrastructure.

Transparency

System behaviour should be visible through logs and simple architecture.

Incremental Complexity

Capabilities will be added gradually rather than introducing large frameworks.


⚠️ Current Limitations

This release intentionally excludes several features that will be introduced in later phases:

  • tool execution
  • async task execution
  • multi-agent collaboration
  • long-term memory
  • distributed task orchestration
  • cloud brokers

The focus of this phase was validating the core orchestration architecture.


🚧 Next Steps

The next development phase will introduce a deterministic Tool Execution Layer, enabling agents to request actions such as:

  • filesystem access
  • API calls
  • database queries
  • vector search
  • shell commands

This will be implemented using a centralised executor and tool registry, ensuring safe and observable tool usage.

Future phases will explore:

  • task graphs and planners
  • multi-agent workflows
  • async execution
  • persistent memory systems

🧪 Status

This release represents a stable architectural PoC, suitable for experimentation and further development.

The system is intentionally minimal but establishes the foundations required to build a a robust agent platform.

Full Changelog: https://github.com/philbudden/cortex/commits/v0.1.0