-
Notifications
You must be signed in to change notification settings - Fork 0
feat(qortex): HTTP transport for QortexConnection #89
Description
Context
qortex is becoming a persistent HTTP service (port 8400) instead of an MCP subprocess. The migration is phased:
- Phase 1 (done, qortex-track-c): async
VectorIndex+PgVectorIndex— qortex can run against pgvector - Phase 2+3 (done, openclaw-sandbox): pgvector Docker role + systemd service —
qortex serveruns as a daemon on the sandbox - Phase 4 (this issue): gateway side — make openclaw talk to qortex over HTTP instead of spawning a subprocess
The QortexConnection interface (src/qortex/types.ts:8-17) is already transport-agnostic:
export interface QortexConnection {
readonly isConnected: boolean;
init(): Promise<void>;
callTool(
name: string,
args: Record<string, unknown>,
opts?: { timeout?: number },
): Promise<unknown>;
close(): Promise<void>;
}Today the only implementation is QortexMcpConnection (src/qortex/connection.ts:86-171), which spawns a subprocess via StdioClientTransport. This issue adds a parallel QortexHttpConnection that hits the qortex REST API, a factory to pick the right transport at boot, and wires everything together.
Prerequisite (separate repo: qortex-track-c)
4 missing HTTP routes added: ingest/message, learning/reset, learning/sessions/start, learning/sessions/end.
Implementation Steps
Step 2: QortexHttpConnection class
New file: src/qortex/http-connection.ts
Implements the QortexConnection interface. Static TOOL_ROUTE_MAP maps MCP tool names to HTTP endpoints:
| MCP tool name | HTTP method | Path | Call sites |
|---|---|---|---|
qortex_query |
POST | /v1/query |
src/memory/providers/qortex.ts:148 |
qortex_feedback |
POST | /v1/feedback |
src/memory/providers/qortex.ts:278 |
qortex_ingest |
POST | /v1/ingest |
src/memory/providers/qortex.ts:236 |
qortex_ingest_message |
POST | /v1/ingest/message |
src/qortex/online-ingest.ts:39,51 |
qortex_learning_select |
POST | /v1/learning/select |
src/learning/qortex-client.ts:189 |
qortex_learning_observe |
POST | /v1/learning/observe |
src/learning/qortex-client.ts:216 |
qortex_learning_posteriors |
GET | /v1/learning/{learner}/posteriors |
src/learning/qortex-client.ts:245 |
qortex_learning_metrics |
GET | /v1/learning/{learner}/metrics |
src/learning/qortex-client.ts:269 |
qortex_learning_reset |
POST | /v1/learning/reset |
src/learning/qortex-client.ts:293 |
qortex_learning_session_start |
POST | /v1/learning/sessions/start |
src/learning/qortex-client.ts:315 |
qortex_learning_session_end |
POST | /v1/learning/sessions/end |
src/learning/qortex-client.ts:334 |
Behavior:
init(): GET/v1/health— setsisConnected = trueon 200, throws on failurecallTool(name, args, opts): lookup route map → fetch with AbortController timeout → parse JSON → throw matchingparseToolResultformat on error- Retry on 5xx + network errors (3 attempts, exponential backoff). No retry on 4xx.
- Optional health check heartbeat every 30s
Step 3: Connection factory
New file: src/qortex/connection-factory.ts
export function createQortexConnection(opts: {
transport: "mcp" | "http";
mcp?: { command: string; args: string[] };
http?: { baseUrl: string; headers?: Record<string, string> };
}): QortexConnection;Step 4: Config schema updates
Add transport + http fields to:
src/config/zod-schema.learning.ts— qortex sub-objectsrc/config/zod-schema.agent-runtime.ts— memorySearch.qortexsrc/learning/types.ts— LearningConfig.qortexsrc/config/types.tools.ts— MemorySearchConfig.qortex
Step 5: Gateway boot update
src/gateway/server-runtime-state.ts(lines 107-131): replaceQortexMcpConnectionwith factorysrc/learning/qortex-adapter.ts(lines 297-299): update fallback connectionsrc/memory/providers/qortex.ts(lines 135-139): update owned connection
Step 6: Tests
src/qortex/http-connection.test.ts: route mapping, arg transforms, retry, timeout, healthsrc/qortex/connection-factory.test.ts: transport switching
Files to create
| File | Purpose |
|---|---|
src/qortex/http-connection.ts |
HTTP implementation of QortexConnection |
src/qortex/connection-factory.ts |
Factory: createQortexConnection() |
src/qortex/http-connection.test.ts |
Tests for HTTP connection |
src/qortex/connection-factory.test.ts |
Tests for factory |
Files to modify
| File | Change |
|---|---|
src/gateway/server-runtime-state.ts |
Replace QortexMcpConnection with factory |
src/learning/qortex-adapter.ts |
Replace fallback QortexMcpConnection with factory |
src/memory/providers/qortex.ts |
Add transport to config, use factory |
src/config/zod-schema.learning.ts |
Add transport + http to qortex schema |
src/config/zod-schema.agent-runtime.ts |
Add transport + http to memorySearch qortex schema |
src/config/types.tools.ts |
Add transport + http to MemorySearchConfig.qortex |
src/learning/types.ts |
Add transport + http to LearningConfig.qortex |
Migration strategy
- Default transport stays
"mcp"— no existing deployments break - Opt-in via config:
learning.qortex.transport: "http" - Ansible injects
transport: "http"whenqortex_serve_enabledis true - Both transports can coexist in a mixed deployment