kbot meets cpp 1/3

This commit is contained in:
lovebird 2026-03-30 10:46:50 +02:00
parent d9ebde911f
commit 2f7c18adb5
12 changed files with 148 additions and 351 deletions

View File

@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.20)
project(polymech-cli
project(kbot-cli
VERSION 0.1.0
DESCRIPTION "Polymech C++ CLI"
DESCRIPTION "KBot C++ CLI"
LANGUAGES CXX C
)
@ -112,6 +112,9 @@ add_executable(${PROJECT_NAME}
src/sys_metrics.cpp
)
# Output file name is kbot.exe / kbot (not kbot-cli)
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "kbot")
target_link_libraries(${PROJECT_NAME} PRIVATE CLI11::CLI11 tomlplusplus::tomlplusplus logger html postgres http json polymech ipc geo gadm_reader grid search enrichers kbot)
target_include_directories(${PROJECT_NAME} PRIVATE

View File

@ -28,77 +28,6 @@ polymech-cli --help
polymech-cli --version
```
## Worker Mode & Gridsearch
The `worker` subcommand is designed to be spawned by the Node.js frontend orchestrator (`GridSearchUdsManager`) for background gridsearch execution. It accepts length-prefixed JSON frames over a Unix Domain Socket (UDS) or a local TCP port on Windows.
```bash
polymech-cli worker --uds <path_or_port> --daemon --user-uid <id> --config <path>
```
### IPC Resiliency and Logging
The C++ worker pipeline incorporates extensive feedback and retry instrumentation:
1. **Watchdog Heartbeats (`ping` / `pong`)**
- The Node orchestrator sweeps the active worker pool every 15 seconds. It explicitly logs when a ping is sent and when a `pong` (or other active events like `log`, `job_progress`, or `ack`) are received.
- If a C++ worker stops responding to IPC events for 60 seconds (hanging thread or deadlock), it is automatically killed (`SIGKILL`) and evicted from the pool.
2. **Socket Traceability**
- The UDS socket actively traps unexpected closures and TCP faults (like `ECONNRESET`). If the pipe breaks mid-job, explicit socket `error` event handlers in the Node orchestrator will instantly fail the job and log the stack trace, preventing indefinite client-side UI hangs, especially during heavy re-runs.
3. **Persistent Crash Logging (`logs/uds.json`)**
- The C++ worker initializes a multi-sink logger (`logger::init_uds`). It pumps standard logs to `stderr` while simultaneously persisting an append-only file trace to `server/logs/uds.json`.
- The file sink guarantees synchronization to disk aggressively (every 1 second, and immediately on `info` severity). If the worker process vanishes or crashes, `uds.json` acts as the black-box flight recorder for post-mortem debugging.
4. **Job Specification Transparency**
- Gridsearch payloads (including `retry` and `expand` endpoints) aggressively log their input shape (`guided` bounds flag, `enrichers` subset) within the Node console before passing work to the C++ orchestrator. This allows for clear traceability from UI action -> Node submission -> C++ execution.
5. **Thread Safety & Frame Synchronization (Mutexes)**
- The UDS socket handles dual-direction asynchronous streams. The background execution graph (powered by Taskflow) emits high-frequency events (`location`, `waypoint-start`) via `GridsearchCallbacks`. Concurrently, the orchestrator Node.js process sends periodic commands (`ping`, `cancel`) that the C++ socket loop must instantly acknowledge.
- To prevent overlapping payload frames (which corrupt the critical 4-byte `len` header), a global `g_uds_socket_mutex` is strictly enforced. It guarantees that direct UI acknowledgments (`pong`, `cancel_ack`) and background logging (`uds_sink` / Taskflow events) never interleave their `asio::write` bursts onto the pipe.
### IPC Framing & Payload Protocol
Communication runs strictly via length-prefixed JSON frames. This safeguards against TCP fragmentation during heavy event streams.
**Binary Frame Format:**
`[4-byte Unsigned Little-Endian Integer (Payload Length)] [UTF-8 JSON Object]`
#### Control Commands (Node → C++)
If the JSON object contains an `"action"` field, it is handled synchronously on the socket thread:
- **Health Check:** `{"action": "ping"}`
*Replies:* `{"type": "pong", "data": {"memoryMb": 120, "cpuTimeMs": 4500}}`
- **Cancellation:** `{"action": "cancel", "jobId": "job_123"}`
→ Worker sets the atomic cancellation token to safely halt the target `taskflow`, instantly replying `{"type": "cancel_ack", "data": "job_123"}`
- **Daemon Teardown:** `{"action": "stop"}`
→ Flushes all streams and exits cleanly.
#### Gridsearch Payload (Node → C++)
If no `"action"` field exists, the message is treated as a gridsearch spec and pushed into a lock-free `ConcurrentQueue` for the background execution graph:
```json
{
"jobId": "run_9a8bc7",
"configPath": "config/postgres.toml",
"cacheDir": "../packages/gadm/cache",
"enrich": true,
"guided": {
"areas": [{ "gid": "ESP.6_1", "level": 1 }],
"settings": { "gridMode": "hex", "cellSize": 5.0 }
},
"search": {
"types": ["restaurant"],
"limitPerArea": 500
}
}
```
#### Event Streaming (C++ → Node)
As the gridsearch pipeline executes, the `GridsearchCallbacks` emit standard length-prefixed events directly back to the active UDS socket:
- **`ack`**: Acknowledges job was successfully dequeued (`{"type": "ack", "data": {"jobId": "..."}}`).
- **`log`**: Passthrough of all internal C++ `spdlog` messages using the custom `uds_sink` adapter.
- **`location` / `node`**: Raw geolocation geometries and enriched contact details streamed incrementally.
- **`job_progress`**: Phase updates (Grid Generation → Search → Enrichment).
- **`job_result`**: The final statistical and timer summary (EnumMs, SearchMs, Total Emails, etc).
- **`error`**: Unrecoverable boundary parsing or database initialization faults.
## License

Binary file not shown.

View File

@ -1,58 +0,0 @@
MSBuild version 18.4.0+6e61e96ac for .NET Framework
libcurl_object.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_object.dir\Debug\libcurl_object.lib
Catch2.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\catch2-build\src\Debug\Catch2d.lib
Catch2WithMain.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\catch2-build\src\Debug\Catch2Maind.lib
lexbor_static.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\lexbor-build\Debug\lexbor_static.lib
html.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\html\Debug\html.lib
libcurl_static.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\Debug\libcurl-d.lib
http.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\http\Debug\http.lib
json.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\json\Debug\json.lib
spdlog.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\spdlog-build\Debug\spdlogd.lib
logger.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\logger\Debug\logger.lib
enrichers.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\enrichers\Debug\enrichers.lib
geo.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\geo\Debug\geo.lib
gadm_reader.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\gadm_reader\Debug\gadm_reader.lib
grid.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\grid\Debug\grid.lib
ipc.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\ipc\Debug\ipc.lib
azure.cpp
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): warning C4003: not enough arguments for function-like macro invocation 'max' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/azure.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2589: '(': illegal token on right side of '::' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/azure.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2059: syntax error: ')' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/azure.cpp')
chat.cpp
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): warning C4003: not enough arguments for function-like macro invocation 'max' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/chat.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2589: '(': illegal token on right side of '::' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/chat.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2059: syntax error: ')' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/chat.cpp')
Generating Code...
postgres.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\postgres\Debug\postgres.lib
polymech.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\polymech\Debug\polymech.lib
search.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\search\Debug\search.lib
test_enrichers.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_enrichers.exe
test_functional.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_functional.exe
test_gadm_reader.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_gadm_reader.exe
test_geo.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_geo.exe
test_grid.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_grid.exe
test_gridsearch_ipc.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_gridsearch_ipc.exe
test_html.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_html.exe
test_http.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_http.exe
test_ipc.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_ipc.exe
test_json.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_json.exe
test_logger.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_logger.exe
test_polymech.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_polymech.exe
test_polymech_e2e.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_polymech_e2e.exe
test_postgres.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_postgres.exe
test_postgres_live.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_postgres_live.exe
test_search.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_search.exe
test_supabase.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\dist\test_supabase.exe

View File

@ -1,147 +0,0 @@
MSBuild version 18.4.0+6e61e96ac for .NET Framework
Build started 3/29/2026 10:04:05 PM.
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" on node 1 (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (1) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\ZERO_CHECK.vcxproj" (2) on node 1 (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "x64\Debug\ZERO_CHECK\ZERO_CHECK.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "x64\Debug\ZERO_CHECK\ZERO_CHECK.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
FinalizeBuildStatus:
Deleting file "x64\Debug\ZERO_CHECK\ZERO_CHECK.tlog\unsuccessfulbuild".
Touching "x64\Debug\ZERO_CHECK\ZERO_CHECK.tlog\ZERO_CHECK.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\ZERO_CHECK.vcxproj" (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (1) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\json\json.vcxproj" (3) on node 1 (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "json.dir\Debug\json.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "json.dir\Debug\json.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
ClCompile:
All outputs are up-to-date.
Lib:
All outputs are up-to-date.
json.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\json\Debug\json.lib
FinalizeBuildStatus:
Deleting file "json.dir\Debug\json.tlog\unsuccessfulbuild".
Touching "json.dir\Debug\json.tlog\json.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\json\json.vcxproj" (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (1) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_static.vcxproj" (4) on node 1 (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_static.vcxproj" (4) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_object.vcxproj" (5) on node 1 (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "libcurl_object.dir\Debug\libcurl_object.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "libcurl_object.dir\Debug\libcurl_object.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
ClCompile:
All outputs are up-to-date.
Lib:
All outputs are up-to-date.
libcurl_object.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_object.dir\Debug\libcurl_object.lib
FinalizeBuildStatus:
Deleting file "libcurl_object.dir\Debug\libcurl_object.tlog\unsuccessfulbuild".
Touching "libcurl_object.dir\Debug\libcurl_object.tlog\libcurl_object.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_object.vcxproj" (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "libcurl_static.dir\Debug\libcurl_static.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "libcurl_static.dir\Debug\libcurl_static.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
Lib:
All outputs are up-to-date.
libcurl_static.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\Debug\libcurl-d.lib
FinalizeBuildStatus:
Deleting file "libcurl_static.dir\Debug\libcurl_static.tlog\unsuccessfulbuild".
Touching "libcurl_static.dir\Debug\libcurl_static.tlog\libcurl_static.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_static.vcxproj" (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (1) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\logger\logger.vcxproj" (6) on node 1 (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\logger\logger.vcxproj" (6) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\spdlog-build\spdlog.vcxproj" (7) on node 1 (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "spdlog.dir\Debug\spdlog.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "spdlog.dir\Debug\spdlog.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
ClCompile:
All outputs are up-to-date.
Lib:
All outputs are up-to-date.
spdlog.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\spdlog-build\Debug\spdlogd.lib
FinalizeBuildStatus:
Deleting file "spdlog.dir\Debug\spdlog.tlog\unsuccessfulbuild".
Touching "spdlog.dir\Debug\spdlog.tlog\spdlog.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\spdlog-build\spdlog.vcxproj" (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "logger.dir\Debug\logger.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "logger.dir\Debug\logger.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
ClCompile:
All outputs are up-to-date.
Lib:
All outputs are up-to-date.
logger.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\logger\Debug\logger.lib
FinalizeBuildStatus:
Deleting file "logger.dir\Debug\logger.tlog\unsuccessfulbuild".
Touching "logger.dir\Debug\logger.tlog\logger.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\logger\logger.vcxproj" (default targets).
Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (1) is building "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\liboai\liboai\oai.vcxproj" (8) on node 1 (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Creating "oai.dir\Debug\oai.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
Touching "oai.dir\Debug\oai.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
ClCompile:
All outputs are up-to-date.
Lib:
All outputs are up-to-date.
oai.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\liboai\liboai\Debug\oaid.lib
FinalizeBuildStatus:
Deleting file "oai.dir\Debug\oai.tlog\unsuccessfulbuild".
Touching "oai.dir\Debug\oai.tlog\oai.lastbuildstate".
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\liboai\liboai\oai.vcxproj" (default targets).
PrepareForBuild:
Structured output is enabled. The formatting of compiler diagnostics will reflect the error hierarchy. See https://aka.ms/cpp/structured-output for more details.
InitializeBuildStatus:
Touching "kbot.dir\Debug\kbot.tlog\unsuccessfulbuild".
CustomBuild:
All outputs are up-to-date.
ClCompile:
C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.50.35717\bin\HostX64\x64\CL.exe /c /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\kbot" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\taskflow-src" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\logger\include" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\spdlog-src\include" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\json\include" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\rapidjson-src\include" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\liboai\liboai\include" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\nlohmann_json-src\include" /I"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-src\include" /Zi /nologo /W1 /WX- /diagnostics:column /Od /Ob0 /D _MBCS /D WIN32 /D _WINDOWS /D SPDLOG_COMPILED_LIB /D CURL_STATICLIB /D "CMAKE_INTDIR=\"Debug\"" /EHsc /RTC1 /MDd /std:c++17 /Fo"kbot.dir\Debug\\" /Fd"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\Debug\kbot.pdb" /external:W1 /TP /errorReport:queue /utf-8 "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\kbot\llm_client.cpp"
llm_client.cpp
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\kbot\llm_client.cpp(64,19): error C2039: 'SetBaseUrl': is not a member of 'liboai::Authorization' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj]
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\liboai\liboai\include\core\authorization.h(22,8):
see declaration of 'liboai::Authorization'
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\kbot\llm_client.cpp(69,22): warning C4834: discarding return value of function with [[nodiscard]] attribute [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj]
Done Building Project "C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (default targets) -- FAILED.
Build FAILED.
"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (default target) (1) ->
(ClCompile target) ->
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\kbot\llm_client.cpp(69,22): warning C4834: discarding return value of function with [[nodiscard]] attribute [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj]
"C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj" (default target) (1) ->
(ClCompile target) ->
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\packages\kbot\llm_client.cpp(64,19): error C2039: 'SetBaseUrl': is not a member of 'liboai::Authorization' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\packages\kbot\kbot.vcxproj]
1 Warning(s)
1 Error(s)
Time Elapsed 00:00:02.01

Binary file not shown.

View File

@ -1,25 +0,0 @@
MSBuild version 18.4.0+6e61e96ac for .NET Framework
libcurl_object.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\libcurl_object.dir\Debug\libcurl_object.lib
libcurl_static.vcxproj -> C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\curl-build\lib\Debug\libcurl-d.lib
azure.cpp
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): warning C4003: not enough arguments for function-like macro invocation 'max' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/azure.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2589: '(': illegal token on right side of '::' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/azure.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2059: syntax error: ')' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/azure.cpp')
chat.cpp
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): warning C4003: not enough arguments for function-like macro invocation 'max' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/chat.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2589: '(': illegal token on right side of '::' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/chat.cpp')
C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-src\liboai\include\components\chat.h(836,60): error C2059: syntax error: ')' [C:\Users\zx\Desktop\polymech\polymech-mono\packages\kbot\cpp\build\release\_deps\liboai-build\oai.vcxproj]
(compiling source file '../liboai-src/liboai/components/chat.cpp')
Generating Code...

View File

@ -1,18 +1,22 @@
/**
* orchestrator/test-ipc.mjs
*
* Integration test: spawn the C++ worker, exchange messages, verify responses.
* Integration test: spawn the C++ worker in UDS mode, exchange messages, verify responses.
*
* Run: node orchestrator/test-ipc.mjs
* Needs: npm run build (to compile the C++ binary first)
* Run: npm run test:ipc
*/
import { spawnWorker } from './spawn.mjs';
import { spawn } from 'node:child_process';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import net from 'node:net';
import { randomUUID } from 'node:crypto';
import { existsSync, unlinkSync } from 'node:fs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const EXE = resolve(__dirname, '..', 'dist', 'polymech-cli.exe');
const IS_WIN = process.platform === 'win32';
const EXE_NAME = IS_WIN ? 'kbot.exe' : 'kbot';
const EXE = resolve(__dirname, '..', 'dist', EXE_NAME);
let passed = 0;
let failed = 0;
@ -28,24 +32,109 @@ function assert(condition, label) {
}
async function run() {
console.log('\n🔧 IPC Integration Tests\n');
console.log('\n🔧 IPC [UDS] Integration Tests\n');
if (!existsSync(EXE)) {
console.error(`❌ Binary not found at ${EXE}`);
process.exit(1);
}
const CPP_UDS_ARG = IS_WIN ? '4001' : '/tmp/kbot-test-ipc.sock';
if (!IS_WIN && existsSync(CPP_UDS_ARG)) {
unlinkSync(CPP_UDS_ARG);
}
// ── 1. Spawn & ready ────────────────────────────────────────────────────
console.log('1. Spawn worker and wait for ready signal');
const worker = spawnWorker(EXE);
console.log('1. Spawn worker (UDS mode) and wait for ready signal');
const workerProc = spawn(EXE, ['worker', '--uds', CPP_UDS_ARG], { stdio: 'pipe' });
workerProc.stderr.on('data', d => {
const txt = d.toString().trim();
if (txt) console.error(`[worker:stderr] ${txt}`);
});
const readyMsg = await worker.ready;
let socket;
for (let i = 0; i < 15; i++) {
try {
await new Promise((res, rej) => {
if (IS_WIN) {
socket = net.connect({ port: 4001, host: '127.0.0.1' });
} else {
socket = net.connect(CPP_UDS_ARG);
}
socket.once('connect', res);
socket.once('error', rej);
});
break;
} catch (e) {
if (i === 14) throw e;
await new Promise(r => setTimeout(r, 400));
}
}
assert(true, 'Socket connected successfully');
// Pending request map: id → { resolve, reject, timer }
const pending = new Map();
let readyResolve;
const readyPromise = new Promise(res => { readyResolve = res; });
let buffer = Buffer.alloc(0);
socket.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk]);
while (buffer.length >= 4) {
const len = buffer.readUInt32LE(0);
if (buffer.length >= 4 + len) {
const payload = buffer.toString('utf8', 4, 4 + len);
buffer = buffer.subarray(4 + len);
try {
const msg = JSON.parse(payload);
if (msg.type === 'ready') {
readyResolve(msg);
} else if (msg.id && pending.has(msg.id)) {
const p = pending.get(msg.id);
clearTimeout(p.timer);
pending.delete(msg.id);
p.resolve(msg);
}
} catch (e) {
console.error('[orchestrator] frame parse error', e);
}
} else {
break;
}
}
});
function request(msg, timeoutMs = 5000) {
return new Promise((resolve, reject) => {
const id = msg.id || randomUUID();
msg.id = id;
const timer = setTimeout(() => {
pending.delete(id);
reject(new Error(`IPC request timed out`));
}, timeoutMs);
pending.set(id, { resolve, reject, timer });
const str = JSON.stringify(msg);
const lenBuf = Buffer.alloc(4);
lenBuf.writeUInt32LE(Buffer.byteLength(str));
socket.write(lenBuf);
socket.write(str);
});
}
const readyMsg = await readyPromise;
assert(readyMsg.type === 'ready', 'Worker sends ready message on startup');
// ── 2. Ping / Pong ─────────────────────────────────────────────────────
console.log('2. Ping → Pong');
const pong = await worker.request({ type: 'ping' });
const pong = await request({ type: 'ping' });
assert(pong.type === 'pong', `Response type is "pong" (got "${pong.type}")`);
// ── 3. Job echo ─────────────────────────────────────────────────────────
console.log('3. Job → Job Result (echo payload)');
const payload = { action: 'resize', width: 1024, format: 'webp' };
const jobResult = await worker.request({ type: 'job', payload });
const jobResult = await request({ type: 'job', payload });
assert(jobResult.type === 'job_result', `Response type is "job_result" (got "${jobResult.type}")`);
assert(
jobResult.payload?.action === 'resize' && jobResult.payload?.width === 1024,
@ -54,14 +143,14 @@ async function run() {
// ── 4. Unknown type → error ─────────────────────────────────────────────
console.log('4. Unknown type → error response');
const errResp = await worker.request({ type: 'nonsense' });
const errResp = await request({ type: 'nonsense' });
assert(errResp.type === 'error', `Response type is "error" (got "${errResp.type}")`);
// ── 5. Multiple rapid requests ──────────────────────────────────────────
console.log('5. Multiple concurrent requests');
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(worker.request({ type: 'ping', payload: { seq: i } }));
promises.push(request({ type: 'ping', payload: { seq: i } }));
}
const results = await Promise.all(promises);
assert(results.length === 10, `All 10 responses received`);
@ -69,12 +158,13 @@ async function run() {
// ── 6. Graceful shutdown ────────────────────────────────────────────────
console.log('6. Graceful shutdown');
const shutdownRes = await worker.shutdown();
const shutdownRes = await request({ type: 'shutdown' });
assert(shutdownRes.type === 'shutdown_ack', `Shutdown acknowledged (got "${shutdownRes.type}")`);
// Wait a beat for process exit
await new Promise(r => setTimeout(r, 200));
assert(worker.process.exitCode === 0, `Worker exited with code 0 (got ${worker.process.exitCode})`);
socket.destroy();
assert(workerProc.exitCode === 0, `Worker exited with code 0 (got ${workerProc.exitCode})`);
// ── Summary ─────────────────────────────────────────────────────────────
console.log(`\n────────────────────────────────`);

View File

@ -1,7 +1,7 @@
{
"name": "mono-cpp",
"name": "kbot-cpp",
"version": "1.0.0",
"description": "Cross-platform C++ CLI built with CMake.",
"description": "KBot C++ CLI built with CMake.",
"directories": {
"test": "tests"
},
@ -15,14 +15,12 @@
"test:release": "ctest --test-dir build/release -C Release --output-on-failure",
"clean": "cmake -E rm -rf build dist",
"rebuild": "npm run clean && npm run build",
"run": ".\\dist\\polymech-cli.exe --help",
"worker": ".\\dist\\polymech-cli.exe worker",
"test:ipc": "node orchestrator/test-gridsearch-ipc.mjs",
"gridsearch": ".\\dist\\polymech-cli.exe gridsearch ABW recycling --dry-run",
"gridsearch:settings": ".\\dist\\polymech-cli.exe gridsearch --settings config/gridsearch-sample.json --dry-run",
"gridsearch:settings:live": ".\\dist\\polymech-cli.exe gridsearch --settings config/gridsearch-sample.json",
"gridsearch:enrich": ".\\dist\\polymech-cli.exe gridsearch --settings config/gridsearch-sample.json --enrich",
"gridsearch:enrich-test": ".\\dist\\polymech-cli.exe gridsearch --settings config/gridsearch-test-bcn.json --enrich --persistence-postgres",
"run": ".\\dist\\kbot.exe --help",
"worker": ".\\dist\\kbot.exe worker",
"worker:uds": ".\\dist\\kbot.exe worker --uds \\\\.\\pipe\\kbot-worker",
"kbot:ai": ".\\dist\\kbot.exe kbot ai --prompt \"hi\"",
"kbot:run": ".\\dist\\kbot.exe kbot run --list",
"test:ipc": "node orchestrator/test-ipc.mjs",
"test:gridsearch-ipc": "node orchestrator/test-gridsearch-ipc.mjs",
"test:gridsearch-filter-ipc": "cmake --build build/release --target test_gridsearch_ipc && .\\dist\\test_gridsearch_ipc.exe",
"test:ipc:daemon": "node orchestrator/test-gridsearch-ipc-daemon.mjs",

View File

@ -8,7 +8,7 @@ namespace polymech {
namespace kbot {
int run_kbot_ai_pipeline(const KBotOptions& opts, const KBotCallbacks& cb) {
logger::info("Starting kbot ai pipeline (stub)");
logger::debug("Starting kbot ai pipeline");
if (opts.dry_run) {
logger::info("Dry run triggered for kbot ai");
}
@ -18,14 +18,14 @@ int run_kbot_ai_pipeline(const KBotOptions& opts, const KBotCallbacks& cb) {
tf::Taskflow taskflow;
taskflow.emplace([opts, cb](){
logger::info("Executing kbot ai completion via LLMClient...");
logger::debug("Executing kbot ai completion via LLMClient...");
LLMClient client(opts);
std::string target_prompt = opts.prompt.empty() ? "Respond with 'Hello from KBot C++ AI Pipeline!'" : opts.prompt;
LLMResponse res = client.execute_chat(target_prompt);
if (res.success) {
logger::info("AI Response:\n" + res.text);
std::cout << res.text << "\n";
if (cb.onEvent) {
cb.onEvent("ai_progress", "{\"message\":\"Task completion received\"}");
}

View File

@ -1,6 +1,7 @@
#include "llm_client.h"
#include "logger/logger.h"
#include <liboai.h>
#include <nlohmann/json.hpp>
#include <iostream>
namespace polymech {
@ -43,17 +44,17 @@ LLMClient::~LLMClient() = default;
LLMResponse LLMClient::execute_chat(const std::string& prompt) {
LLMResponse res;
logger::info("LLMClient::execute_chat: Starting. api_key length: " + std::to_string(api_key_.length()));
logger::debug("LLMClient::execute_chat: Starting. api_key length: " + std::to_string(api_key_.length()));
if (api_key_.empty()) {
res.success = false;
res.error = "API Key is empty.";
return res;
}
logger::info("LLMClient::execute_chat: base_url_: " + base_url_);
logger::debug("LLMClient::execute_chat: base_url_: " + base_url_);
liboai::OpenAI oai_impl(base_url_.empty() ? "https://api.openai.com/v1" : base_url_);
logger::info("LLMClient::execute_chat: Setting API Key");
logger::debug("LLMClient::execute_chat: Setting API Key");
bool success = oai_impl.auth.SetKey(api_key_);
if (!success) {
res.success = false;
@ -62,24 +63,37 @@ LLMResponse LLMClient::execute_chat(const std::string& prompt) {
}
std::string target_model = model_.empty() ? "gpt-4o" : model_;
logger::info("LLMClient::execute_chat: Target model: " + target_model);
logger::debug("LLMClient::execute_chat: Target model: " + target_model);
logger::info("LLMClient::execute_chat: Init Conversation");
logger::debug("LLMClient::execute_chat: Init Conversation");
liboai::Conversation convo;
convo.AddUserData(prompt);
logger::info("LLMClient::execute_chat: Calling create()");
logger::debug("LLMClient::execute_chat: Calling create()");
try {
liboai::Response response = oai_impl.ChatCompletion->create(
target_model,
convo
);
logger::info("LLMClient::execute_chat: Got response with status: " + std::to_string(response.status_code));
logger::debug("LLMClient::execute_chat: Got response with status: " + std::to_string(response.status_code));
if (!response.raw_json.contains("choices") || response.raw_json["choices"].empty()) {
// liboai may not populate raw_json for custom base URLs — parse content directly.
nlohmann::json j;
bool json_ok = false;
if (!response.raw_json.empty() && response.raw_json.contains("choices")) {
j = response.raw_json;
json_ok = true;
} else if (!response.content.empty()) {
try {
j = nlohmann::json::parse(response.content);
json_ok = j.contains("choices");
} catch (...) {}
}
if (!json_ok || j["choices"].empty()) {
res.success = false;
if (response.raw_json.contains("error")) {
res.error = "API Error: " + response.raw_json["error"].dump();
if (json_ok && j.contains("error")) {
res.error = "API Error: " + j["error"].dump();
} else {
res.error = "Invalid response format: no choices found. Raw: " + response.content;
}
@ -87,7 +101,7 @@ LLMResponse LLMClient::execute_chat(const std::string& prompt) {
}
res.success = true;
res.text = response.raw_json["choices"][0]["message"]["content"].get<std::string>();
res.text = j["choices"][0]["message"]["content"].get<std::string>();
} catch (std::exception& e) {
logger::error("LLMClient::execute_chat: Exception caught: " + std::string(e.what()));

View File

@ -29,7 +29,7 @@
#endif
int main(int argc, char *argv[]) {
CLI::App app{"polymech-cli — Polymech C++ CLI", "polymech-cli"};
CLI::App app{"kbot — KBot C++ CLI", "kbot"};
app.set_version_flag("-v,--version", PROJECT_VERSION);
std::string log_level = "info";
@ -89,11 +89,9 @@ int main(int argc, char *argv[]) {
worker_cmd->add_option("--user-uid", daemon_uid, "User ID to bind this daemon to (needed for place owner)");
worker_cmd->add_option("--uds", uds_path, "Run over Unix Domain Socket / Named Pipe at the given path");
// Subcommand: gridsearch — Run a full gridsearch pipeline
auto* gs_cmd = polymech::setup_cmd_gridsearch(app);
// Subcommand: kbot — AI workflows & task configurations
auto* kbot_cmd = polymech::setup_cmd_kbot(app);
(void)kbot_cmd;
CLI11_PARSE(app, argc, argv);
@ -294,11 +292,6 @@ int main(int argc, char *argv[]) {
return 0;
}
// ── gridsearch subcommand ──────────────────────────────────────────────
if (gs_cmd->parsed()) {
return polymech::run_cmd_gridsearch();
}
// ── kbot subcommand ──────────────────────────────────────────────────
if (polymech::is_kbot_ai_parsed()) {
return polymech::run_cmd_kbot_ai();