Add testsystem
This commit is contained in:
parent
2210e3a260
commit
5ae22ff9f8
165
.acf/tasks.json
165
.acf/tasks.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"projectName": "metal-kompanion-mcp",
|
||||
"projectDescription": "MCP backend for Kompanion: memory/context/embedding provider over MCP, built from scratch (qtmcp-based) to persist conversation state and serve embeddings + retrieval to avoid forgetting across threads.",
|
||||
"lastTaskId": 20,
|
||||
"lastTaskId": 23,
|
||||
"tasks": [
|
||||
{
|
||||
"id": 1,
|
||||
|
|
@ -441,6 +441,169 @@
|
|||
"message": "Task created with title: \"Claude Code integration rescue plan\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"title": "DAL Phase 1: libpq/pqxx wiring + SQL calls",
|
||||
"description": "Link pqxx, implement PgDal against Postgres+pgvector: connect/tx, ensureNamespace, upsertItem/Chunks/Embeddings, searchText (FTS/trgm), searchVector (<->). Provide DSN via env; add cmake find + link.",
|
||||
"status": "todo",
|
||||
"priority": 510,
|
||||
"priorityDisplay": "P0",
|
||||
"dependsOn": [],
|
||||
"createdAt": "2025-10-14T00:29:55.327Z",
|
||||
"updatedAt": "2025-10-14T00:29:55.327Z",
|
||||
"subtasks": [
|
||||
{
|
||||
"id": "21.1",
|
||||
"title": "CMake: find_package(pqxx) and link; CI env var DSN",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:00.856Z",
|
||||
"updatedAt": "2025-10-14T00:30:00.857Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:00.856Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"CMake: find_package(pqxx) and link; CI env var DSN\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "21.2",
|
||||
"title": "PgDal: implement connect/tx + prepared statements",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:06.138Z",
|
||||
"updatedAt": "2025-10-14T00:30:06.138Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:06.138Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"PgDal: implement connect/tx + prepared statements\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "21.3",
|
||||
"title": "SQL: ensureNamespace, upsertItem/Chunks/Embeddings",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:11.519Z",
|
||||
"updatedAt": "2025-10-14T00:30:11.519Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:11.519Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"SQL: ensureNamespace, upsertItem/Chunks/Embeddings\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "21.4",
|
||||
"title": "Search: FTS/trgm + vector <-> with filters (namespace/thread/tags)",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:17.290Z",
|
||||
"updatedAt": "2025-10-14T00:30:17.290Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:17.290Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"Search: FTS/trgm + vector <-> with filters (namespace/thread/tags)\""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"lastSubtaskIndex": 4,
|
||||
"relatedFiles": [],
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:29:55.327Z",
|
||||
"type": "log",
|
||||
"message": "Task created with title: \"DAL Phase 1: libpq/pqxx wiring + SQL calls\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"title": "Handlers → DAL integration",
|
||||
"description": "Wire kom.memory.v1.upsert_memory/search_memory to IDatabase. Parse JSON with a real parser, validate against schemas, enforce scope and sensitivity rules.",
|
||||
"status": "todo",
|
||||
"priority": 490,
|
||||
"priorityDisplay": "P0",
|
||||
"dependsOn": [],
|
||||
"createdAt": "2025-10-14T00:30:26.285Z",
|
||||
"updatedAt": "2025-10-14T00:30:26.285Z",
|
||||
"subtasks": [
|
||||
{
|
||||
"id": "22.1",
|
||||
"title": "Replace ad-hoc JSON with parser (nlohmann/json or simdjson)",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:33.761Z",
|
||||
"updatedAt": "2025-10-14T00:30:33.761Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:33.761Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"Replace ad-hoc JSON with parser (nlohmann/json or simdjson)\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "22.2",
|
||||
"title": "Validate request bodies against schemas before DAL calls",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:39.868Z",
|
||||
"updatedAt": "2025-10-14T00:30:39.868Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:39.868Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"Validate request bodies against schemas before DAL calls\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "22.3",
|
||||
"title": "Scope & sensitivity enforcement (namespace/user + skip secret embeddings)",
|
||||
"status": "todo",
|
||||
"createdAt": "2025-10-14T00:30:45.261Z",
|
||||
"updatedAt": "2025-10-14T00:30:45.261Z",
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:45.261Z",
|
||||
"type": "log",
|
||||
"message": "Subtask created with title: \"Scope & sensitivity enforcement (namespace/user + skip secret embeddings)\""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"lastSubtaskIndex": 3,
|
||||
"relatedFiles": [],
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:26.285Z",
|
||||
"type": "log",
|
||||
"message": "Task created with title: \"Handlers → DAL integration\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"title": "Contract tests: DAL-backed tools",
|
||||
"description": "Expand CTest to cover DAL-backed upsert/search and backup export/import; include error cases and schema violations; run against build-komhands.",
|
||||
"status": "todo",
|
||||
"priority": 511,
|
||||
"priorityDisplay": "P1",
|
||||
"dependsOn": [],
|
||||
"createdAt": "2025-10-14T00:30:51.716Z",
|
||||
"updatedAt": "2025-10-14T00:30:51.716Z",
|
||||
"subtasks": [],
|
||||
"lastSubtaskIndex": 0,
|
||||
"relatedFiles": [],
|
||||
"activityLog": [
|
||||
{
|
||||
"timestamp": "2025-10-14T00:30:51.716Z",
|
||||
"type": "log",
|
||||
"message": "Task created with title: \"Contract tests: DAL-backed tools\""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -8,25 +8,18 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||
# find_package(Qt6 COMPONENTS Core Network REQUIRED)
|
||||
# find_package(qtmcp REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(PQXX REQUIRED libpqxx)
|
||||
add_subdirectory(src/dal)
|
||||
|
||||
add_executable(kom_mcp
|
||||
src/main.cpp
|
||||
src/dal/PgDal.cpp
|
||||
)
|
||||
# target_link_libraries(kom_mcp PRIVATE Qt6::Core Qt6::Network qtmcp)
|
||||
target_include_directories(kom_mcp PRIVATE src ${PQXX_INCLUDE_DIRS})
|
||||
target_link_libraries(kom_mcp PRIVATE ${PQXX_LIBRARIES})
|
||||
target_include_directories(kom_mcp PRIVATE src)
|
||||
target_link_libraries(kom_mcp PRIVATE kom_dal)
|
||||
|
||||
install(TARGETS kom_mcp RUNTIME DESTINATION bin)
|
||||
|
||||
add_executable(test_mcp_tools
|
||||
tests/contract/test_mcp_tools.cpp
|
||||
src/dal/PgDal.cpp
|
||||
)
|
||||
target_include_directories(test_mcp_tools PRIVATE src ${PQXX_INCLUDE_DIRS})
|
||||
target_link_libraries(test_mcp_tools PRIVATE ${PQXX_LIBRARIES})
|
||||
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
if (BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_test(NAME contract_mcp_tools COMMAND test_mcp_tools)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
-- Kompanion quick checks
|
||||
|
|
@ -1 +0,0 @@
|
|||
-- placeholder: see chat for full Branch Embeddings schema
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
add_library(kom_dal STATIC
|
||||
PgDal.cpp
|
||||
)
|
||||
|
||||
target_compile_features(kom_dal PUBLIC cxx_std_20)
|
||||
target_include_directories(kom_dal PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
|
@ -3,11 +3,11 @@ MCP backend for Kompanion: memory/context/embedding provider over MCP, built fro
|
|||
|
||||
> ## 📈 Project Summary
|
||||
>
|
||||
> **✅ Done**: 0 | **🔄 In Progress**: 0 | **⬜ Todo**: 19 | **❌ Blocked**: 0
|
||||
> **✅ Done**: 0 | **🔄 In Progress**: 0 | **⬜ Todo**: 29 | **❌ Blocked**: 0
|
||||
>
|
||||
> **Progress**: 0% `░░░░░░░░░░░░░░░░░░░░` 0/19 tasks
|
||||
> **Progress**: 0% `░░░░░░░░░░░░░░░░░░░░` 0/29 tasks
|
||||
>
|
||||
> **Priorities**: 🚨 **Critical**: 0 | 🔴 **High**: 1 | 🟡 **Medium**: 20 | 🟢 **Low**: 0
|
||||
> **Priorities**: 🚨 **Critical**: 0 | 🔴 **High**: 1 | 🟡 **Medium**: 30 | 🟢 **Low**: 0
|
||||
|
||||
## Tasks
|
||||
|
||||
|
|
@ -33,6 +33,9 @@ MCP backend for Kompanion: memory/context/embedding provider over MCP, built fro
|
|||
| #18 | ⬜ todo | 492 | **Expose Agentic-Control-Framework as a tool** | Wrap ACF endpoints into a too... |
|
||||
| #19 | ⬜ todo | 509 | **DAL skeleton + SQL calls (pgvector)** | Create DAL interfaces and pgv... |
|
||||
| #20 | ⬜ todo | 491 | **Claude Code integration rescue plan** | Stabilize Qwen-2.5-Coder insi... |
|
||||
| #21 | ⬜ todo | 510 | **DAL Phase 1: libpq/pqxx wiring + SQL calls** | Link pqxx, implement PgDal ag... |
|
||||
| #22 | ⬜ todo | 490 | **Handlers → DAL integration** | Wire kom.memory.v1.upsert_mem... |
|
||||
| #23 | ⬜ todo | 511 | **Contract tests: DAL-backed tools** | Expand CTest to cover DAL-bac... |
|
||||
|
||||
|
||||
### Task #2: Design MCP memory/context API - Subtasks
|
||||
|
|
@ -41,3 +44,20 @@ MCP backend for Kompanion: memory/context/embedding provider over MCP, built fro
|
|||
|:--:|:------:|:------|
|
||||
| #2.1 | ⬜ todo | Write JSON Schemas for tools (done) |
|
||||
|
||||
### Task #21: DAL Phase 1: libpq/pqxx wiring + SQL calls - Subtasks
|
||||
|
||||
| ID | Status | Title |
|
||||
|:--:|:------:|:------|
|
||||
| #21.1 | ⬜ todo | CMake: find_package(pqxx) and link; CI env var DSN |
|
||||
| #21.2 | ⬜ todo | PgDal: implement connect/tx + prepared statements |
|
||||
| #21.3 | ⬜ todo | SQL: ensureNamespace, upsertItem/Chunks/Embeddings |
|
||||
| #21.4 | ⬜ todo | Search: FTS/trgm + vector <-> with filters (namespace/thread/tags) |
|
||||
|
||||
### Task #22: Handlers → DAL integration - Subtasks
|
||||
|
||||
| ID | Status | Title |
|
||||
|:--:|:------:|:------|
|
||||
| #22.1 | ⬜ todo | Replace ad-hoc JSON with parser (nlohmann/json or simdjson) |
|
||||
| #22.2 | ⬜ todo | Validate request bodies against schemas before DAL calls |
|
||||
| #22.3 | ⬜ todo | Scope & sensitivity enforcement (namespace/user + skip secret embeddings) |
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
add_executable(test_mcp_tools
|
||||
contract/test_mcp_tools.cpp
|
||||
)
|
||||
target_include_directories(test_mcp_tools PRIVATE ${PROJECT_SOURCE_DIR}/src)
|
||||
target_link_libraries(test_mcp_tools PRIVATE kom_dal)
|
||||
|
||||
add_test(NAME contract_mcp_tools COMMAND test_mcp_tools)
|
||||
|
||||
add_library(contract_memory STATIC
|
||||
contract_memory.cpp
|
||||
)
|
||||
target_include_directories(contract_memory PRIVATE ${PROJECT_SOURCE_DIR}/src)
|
||||
target_link_libraries(contract_memory PRIVATE kom_dal)
|
||||
|
|
@ -20,15 +20,34 @@ int main() {
|
|||
KomMcpServer server;
|
||||
register_default_tools(server);
|
||||
|
||||
const std::string upsertReq = R"({"namespace":"tests","items":[{"text":"hello world"},{"text":"hola mundo"}]})";
|
||||
const std::string upsertReq = R"({"namespace":"tests","items":[{"text":"hello world","tags":["greeting"],"embedding":[0.1,0.2,0.3]},{"text":"hola mundo","embedding":[0.05,0.1,0.15]}]})";
|
||||
std::string upsertResp = server.dispatch("kom.memory.v1.upsert_memory", upsertReq);
|
||||
if (!expect_contains(upsertResp, "\"upserted\":2", "upsert_memory count")) return 1;
|
||||
if (!expect_contains(upsertResp, "\"status\":\"ok\"", "upsert_memory status")) return 1;
|
||||
|
||||
std::string firstId;
|
||||
const std::string idsAnchor = "\"ids\":[\"";
|
||||
auto idsPos = upsertResp.find(idsAnchor);
|
||||
if (idsPos != std::string::npos) {
|
||||
idsPos += idsAnchor.size();
|
||||
auto endPos = upsertResp.find("\"", idsPos);
|
||||
if (endPos != std::string::npos) {
|
||||
firstId = upsertResp.substr(idsPos, endPos - idsPos);
|
||||
}
|
||||
}
|
||||
if (firstId.empty()) {
|
||||
std::cerr << "Failed to extract first item id from upsert response: " << upsertResp << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const std::string searchReq = R"({"namespace":"tests","query":{"text":"hello","k":3}})";
|
||||
std::string searchResp = server.dispatch("kom.memory.v1.search_memory", searchReq);
|
||||
if (!expect_contains(searchResp, "\"matches\"", "search_memory matches key")) return 1;
|
||||
if (!expect_contains(searchResp, "\"text\":\"hello\"", "search_memory echo text")) return 1;
|
||||
if (!expect_contains(searchResp, "\"text\":\"hello world\"", "search_memory returns stored text")) return 1;
|
||||
|
||||
const std::string vectorReq = R"({"namespace":"tests","query":{"embedding":[0.1,0.2,0.3],"k":1}})";
|
||||
std::string vectorResp = server.dispatch("kom.memory.v1.search_memory", vectorReq);
|
||||
if (!expect_contains(vectorResp, "\"id\":\""+firstId+"\"", "vector search returns stored id")) return 1;
|
||||
|
||||
const std::string exportReq = R"({"namespace":"tests","destination":"/tmp/example.enc"})";
|
||||
std::string exportResp = server.dispatch("kom.local.v1.backup.export_encrypted", exportReq);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
#include "dal/PgDal.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static void contract_pgdal_basic() {
|
||||
kom::PgDal dal;
|
||||
dal.connect("stub://memory");
|
||||
auto ns = dal.ensureNamespace("tests");
|
||||
static_cast<void>(ns);
|
||||
|
||||
kom::ItemRow item;
|
||||
item.namespace_id = "tests";
|
||||
item.text = std::string("example");
|
||||
item.tags = {"alpha", "beta"};
|
||||
item.id = dal.upsertItem(item);
|
||||
|
||||
kom::ChunkRow chunk;
|
||||
chunk.item_id = item.id;
|
||||
chunk.text = "chunk-text";
|
||||
auto chunkIds = dal.upsertChunks(std::vector<kom::ChunkRow>{chunk});
|
||||
if (!chunkIds.empty()) {
|
||||
chunk.id = chunkIds.front();
|
||||
}
|
||||
|
||||
kom::EmbeddingRow embedding;
|
||||
embedding.chunk_id = chunk.id;
|
||||
embedding.model = "stub-model";
|
||||
embedding.dim = 3;
|
||||
embedding.vector = {0.1f, 0.2f, 0.3f};
|
||||
dal.upsertEmbeddings(std::vector<kom::EmbeddingRow>{embedding});
|
||||
|
||||
static_cast<void>(dal.searchText("tests", "chunk", 5));
|
||||
static_cast<void>(dal.searchVector("tests", embedding.vector, 5));
|
||||
static_cast<void>(dal.getItemById(item.id));
|
||||
static_cast<void>(dal.hybridSearch(embedding.vector, "stub-model", "tests", "chunk", 5));
|
||||
}
|
||||
|
||||
static const bool contract_pgdal_compiles = [] {
|
||||
contract_pgdal_basic();
|
||||
return true;
|
||||
}();
|
||||
Loading…
Reference in New Issue