kbot cpp testing - classifiers
This commit is contained in:
parent
8cfa1b7c89
commit
2f2d507baa
@ -130,9 +130,14 @@ else()
|
||||
endif()
|
||||
|
||||
# ── Install ──────────────────────────────────────────────────────────────────
|
||||
# Library + headers: see packages/kbot/CMakeLists.txt and packages/ipc/CMakeLists.txt
|
||||
# Optional DLL/so: configure with -DIPC_BUILD_SHARED=ON -DPOLYMECH_KBOT_SHARED=ON
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/cmd_kbot.h
|
||||
DESTINATION include/polymech
|
||||
)
|
||||
|
||||
# ── Tests ────────────────────────────────────────────────────────────────────
|
||||
enable_testing()
|
||||
|
||||
@ -21,6 +21,16 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-dll",
|
||||
"displayName": "Dev (Debug, ipc + kbot as DLL)",
|
||||
"binaryDir": "${sourceDir}/build/dev-dll",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"IPC_BUILD_SHARED": "ON",
|
||||
"POLYMECH_KBOT_SHARED": "ON"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
@ -31,6 +41,10 @@
|
||||
{
|
||||
"name": "release",
|
||||
"configurePreset": "release"
|
||||
},
|
||||
{
|
||||
"name": "dev-dll",
|
||||
"configurePreset": "dev-dll"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,40 +1,251 @@
|
||||
# polymech-cli
|
||||
# kbot (C++)
|
||||
|
||||
Cross-platform C++ CLI built with CMake.
|
||||
CMake-based C++ toolchain for **kbot**: HTML/HTTP/JSON utilities, **length-prefixed JSON IPC**, optional **UDS/TCP worker** for Node orchestrators, and **LLM chat** via liboai (OpenRouter, OpenAI, Ollama-compatible servers, etc.). The main binary is **`kbot`** (`kbot.exe` on Windows).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Tool | Version |
|
||||
|------|---------|
|
||||
| Requirement | Notes |
|
||||
|-------------|--------|
|
||||
| CMake | ≥ 3.20 |
|
||||
| C++ compiler | C++17 (MSVC, GCC, or Clang) |
|
||||
| C++ compiler | C++17 (MSVC, GCC, Clang) |
|
||||
| Git | For `FetchContent` dependencies |
|
||||
| Node.js | Optional; for `orchestrator/` IPC integration tests (`npm run test:ipc`) |
|
||||
|
||||
## Build
|
||||
On Windows, use a **Developer Command Prompt** or **PowerShell** with MSVC in `PATH`. **Git Bash** helps if you use shell scripts under `scripts/`.
|
||||
|
||||
## Quick start (build)
|
||||
|
||||
From this directory (`packages/kbot/cpp`):
|
||||
|
||||
```bash
|
||||
npm install # optional; only needed if you use npm scripts
|
||||
npm run build
|
||||
```
|
||||
|
||||
Artifacts go to **`dist/`** (e.g. `dist/kbot.exe`, test tools).
|
||||
|
||||
Equivalent CMake:
|
||||
|
||||
```bash
|
||||
# Debug
|
||||
cmake --preset dev
|
||||
cmake --build --preset dev
|
||||
|
||||
# Release
|
||||
cmake --preset release
|
||||
cmake --build --preset release
|
||||
```
|
||||
|
||||
## Usage
|
||||
### Presets
|
||||
|
||||
| Preset | Role |
|
||||
|--------|------|
|
||||
| `dev` | Debug, static `ipc` + `kbot` libraries (default) |
|
||||
| `release` | Release build |
|
||||
| `dev-dll` | Debug with **`ipc.dll`** and **`kbot.dll`** (`IPC_BUILD_SHARED=ON`, `POLYMECH_KBOT_SHARED=ON`) |
|
||||
|
||||
```bash
|
||||
polymech-cli --help
|
||||
polymech-cli --version
|
||||
cmake --preset dev-dll
|
||||
cmake --build --preset dev-dll --config Debug
|
||||
```
|
||||
|
||||
Place **`ipc.dll`** and **`kbot.dll`** next to **`kbot.exe`** (or on `PATH`) when using the DLL configuration.
|
||||
|
||||
### npm scripts (reference)
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `npm run build` | Configure `dev` + build |
|
||||
| `npm run build:release` | Release preset |
|
||||
| `npm run test` | `ctest` in `build/dev` |
|
||||
| `npm run clean` | Remove `build/` and `dist/` |
|
||||
| `npm run test:ipc` | Node UDS IPC integration test |
|
||||
| `npm run worker` | Run worker (stdio IPC) |
|
||||
|
||||
## Installation
|
||||
|
||||
Install the CLI and headers into a prefix (e.g. local tree or system root):
|
||||
|
||||
```bash
|
||||
cmake --install build/dev --prefix "C:/path/to/install"
|
||||
```
|
||||
|
||||
This installs:
|
||||
|
||||
- **`bin/kbot`** (runtime)
|
||||
- **`include/polymech/`** — `kbot.h`, `llm_client.h`, `polymech_export.h`, `cmd_kbot.h`
|
||||
- **`include/ipc/`** — `ipc.h`, `ipc_export.h`
|
||||
- **`lib/`** — import libraries / archives (depending on static vs shared)
|
||||
|
||||
Library layout is defined in `packages/kbot/CMakeLists.txt` and `packages/ipc/CMakeLists.txt`.
|
||||
|
||||
### CMake options (libraries)
|
||||
|
||||
| Cache variable | Effect |
|
||||
|----------------|--------|
|
||||
| `IPC_BUILD_SHARED` | Build **`ipc`** as a shared library (`OFF` default) |
|
||||
| `POLYMECH_KBOT_SHARED` | Build **`kbot`** as a shared library (`OFF` default) |
|
||||
|
||||
Static builds define `IPC_STATIC_BUILD` / `POLYMECH_STATIC_BUILD` for consumers via `INTERFACE` compile definitions. Shared builds export **`IPC_API`** / **`POLYMECH_API`** (see `ipc_export.h`, `polymech_export.h`).
|
||||
|
||||
## CLI overview
|
||||
|
||||
Top-level:
|
||||
|
||||
```bash
|
||||
kbot --help
|
||||
kbot -v,--version
|
||||
kbot --log-level debug|info|warn|error
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `parse <html>` | Parse HTML and list elements |
|
||||
| `select <html> <selector>` | CSS-select elements |
|
||||
| `config <file>` | Load and print a TOML file |
|
||||
| `fetch <url>` | HTTP GET |
|
||||
| `json <input>` | Prettify JSON |
|
||||
| `db [-c config] [table] [-l limit]` | Supabase / DB helper (uses `config/postgres.toml` by default) |
|
||||
| `worker [--uds <arg>]` | IPC worker (see below) |
|
||||
| `kbot ai ...` / `kbot run ...` | AI and run pipelines (`setup_cmd_kbot` — use `kbot kbot ai --help`) |
|
||||
|
||||
### Worker mode (`kbot worker`)
|
||||
|
||||
Used by orchestrators and tests.
|
||||
|
||||
- **Stdio IPC** (length-prefixed JSON frames on stdin/stdout):
|
||||
|
||||
```bash
|
||||
kbot worker
|
||||
```
|
||||
|
||||
- **UDS / TCP** (Windows: TCP port string, e.g. `4001`; Unix: socket path):
|
||||
|
||||
```bash
|
||||
kbot worker --uds 4001
|
||||
```
|
||||
|
||||
Framing: `[uint32 LE length][UTF-8 JSON object with id, type, payload]`. Message types include `ping`, `job`, `kbot-ai`, `kbot-run`, `shutdown`, etc. See `src/main.cpp` and `orchestrator/test-ipc.mjs`.
|
||||
|
||||
### `kbot kbot` (nested)
|
||||
|
||||
CLI for AI tasks and run configurations:
|
||||
|
||||
```bash
|
||||
kbot kbot ai --help
|
||||
kbot kbot run --help
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
kbot kbot ai --prompt "Hello" --config config/postgres.toml
|
||||
```
|
||||
|
||||
API keys are typically resolved from **`config/postgres.toml`** (`[services]`).
|
||||
|
||||
## Using in other CMake projects
|
||||
|
||||
There is no single `find_package(kbot)` config yet. Practical options:
|
||||
|
||||
### 1. Same repository / superbuild (recommended)
|
||||
|
||||
Add this repo’s `cpp` tree as a subdirectory from a parent `CMakeLists.txt` so `FetchContent` and internal targets (`logger`, `json`, `ipc`, `oai`, `kbot`, …) resolve once. Then:
|
||||
|
||||
```cmake
|
||||
target_link_libraries(your_app PRIVATE ipc kbot)
|
||||
```
|
||||
|
||||
`kbot` pulls in `logger`, `json`, `liboai` (`oai`) per `packages/kbot/CMakeLists.txt`.
|
||||
|
||||
### 2. Install prefix + explicit `IMPORTED` libraries
|
||||
|
||||
After `cmake --install`, link import libraries under `lib/` and add `include/` for **`ipc`** and **`polymech`**. You must still satisfy **transitive** dependencies (`oai`, `logger`, `json`, …) from the **same** build/install of this project, or duplicate their build—usually easier to use option 1.
|
||||
|
||||
### 3. Minimal example: IPC framing only
|
||||
|
||||
If you only need **`ipc::encode` / `ipc::decode`** (and can build `logger` + `json` the same way this project does), mirror `packages/ipc/CMakeLists.txt`:
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(myapp CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_subdirectory(path/to/polymech-mono/packages/kbot/cpp/packages/logger)
|
||||
add_subdirectory(path/to/polymech-mono/packages/kbot/cpp/packages/json)
|
||||
add_subdirectory(path/to/polymech-mono/packages/kbot/cpp/packages/ipc)
|
||||
|
||||
add_executable(myapp main.cpp)
|
||||
target_link_libraries(myapp PRIVATE ipc)
|
||||
```
|
||||
|
||||
**`main.cpp`** (stdio-style framing helpers):
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <ipc/ipc.h>
|
||||
|
||||
int main() {
|
||||
ipc::Message msg{"1", "ping", "{}"};
|
||||
auto frame = ipc::encode(msg);
|
||||
// frame: 4-byte LE length + JSON object bytes
|
||||
|
||||
ipc::Message roundtrip;
|
||||
if (frame.size() > 4 &&
|
||||
ipc::decode(frame.data() + 4, frame.size() - 4, roundtrip)) {
|
||||
std::cout << roundtrip.type << "\n"; // ping
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Example: LLM pipeline API (`kbot` library)
|
||||
|
||||
Headers: `kbot.h`, `llm_client.h`, `polymech_export.h`. You need a valid API key and options (see `KBotOptions` in `kbot.h`).
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include "kbot.h"
|
||||
#include "llm_client.h"
|
||||
|
||||
int main() {
|
||||
polymech::kbot::KBotOptions opts;
|
||||
opts.prompt = "Say hello in one sentence.";
|
||||
opts.api_key = "YOUR_KEY";
|
||||
opts.router = "openrouter";
|
||||
opts.model = "openai/gpt-4o-mini";
|
||||
|
||||
polymech::kbot::LLMClient client(opts);
|
||||
polymech::kbot::LLMResponse r = client.execute_chat(opts.prompt);
|
||||
if (r.success) {
|
||||
std::cout << r.text << "\n";
|
||||
} else {
|
||||
std::cerr << r.error << "\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Or use the callback-based pipeline:
|
||||
|
||||
```cpp
|
||||
polymech::kbot::KBotCallbacks cb;
|
||||
cb.onEvent = [](const std::string& type, const std::string& json) {
|
||||
std::cout << type << ": " << json << "\n";
|
||||
};
|
||||
return polymech::kbot::run_kbot_ai_pipeline(opts, cb);
|
||||
```
|
||||
|
||||
Link **`kbot`** (and its public dependencies). **`cmd_kbot.h`** entry points (`run_kbot_ai_ipc`, `run_cmd_kbot_uds`, …) are implemented in **`src/cmd_kbot*.cpp`** in this project; to reuse them, compile those sources into your binary or vendor the logic.
|
||||
|
||||
## Node / IPC tests
|
||||
|
||||
Integration tests live under **`orchestrator/`** (see comments in `orchestrator/test-ipc.mjs`). Typical run from `cpp/`:
|
||||
|
||||
```bash
|
||||
npm run test:ipc
|
||||
```
|
||||
|
||||
Requires a built **`dist/kbot.exe`** (or `kbot` on Unix).
|
||||
|
||||
## License
|
||||
|
||||
BSD-3-Clause
|
||||
|
||||
## Requirements
|
||||
|
||||
- [https://github.com/taskflow/taskflow](https://github.com/taskflow/taskflow)
|
||||
- [https://github.com/cameron314/concurrentqueue](https://github.com/cameron314/concurrentqueue)
|
||||
- [https://github.com/chriskohlhoff/asio](https://github.com/chriskohlhoff/asio)
|
||||
See [LICENSE](LICENSE) in this directory.
|
||||
|
||||
@ -1,11 +1,45 @@
|
||||
add_library(ipc STATIC
|
||||
src/ipc.cpp
|
||||
)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(ipc CXX)
|
||||
|
||||
option(IPC_BUILD_SHARED "Build ipc as a shared library (DLL/so)" OFF)
|
||||
|
||||
set(_ipc_sources src/ipc.cpp)
|
||||
|
||||
if(IPC_BUILD_SHARED)
|
||||
add_library(ipc SHARED ${_ipc_sources})
|
||||
target_compile_definitions(ipc PRIVATE IPC_BUILDING_LIBRARY)
|
||||
else()
|
||||
add_library(ipc STATIC ${_ipc_sources})
|
||||
target_compile_definitions(ipc PRIVATE IPC_STATIC_BUILD=1)
|
||||
target_compile_definitions(ipc INTERFACE IPC_STATIC_BUILD=1)
|
||||
endif()
|
||||
|
||||
target_include_directories(ipc
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(ipc
|
||||
PUBLIC json logger
|
||||
PUBLIC json logger
|
||||
)
|
||||
|
||||
if(IPC_BUILD_SHARED)
|
||||
set_target_properties(ipc PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist"
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/dist"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/dist"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS ipc
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/ipc/ipc.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/ipc/ipc_export.h
|
||||
DESTINATION include/ipc
|
||||
)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ipc/ipc_export.h"
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
@ -16,19 +17,19 @@ struct Message {
|
||||
|
||||
/// Encode a Message into a length-prefixed binary frame.
|
||||
/// Layout: [4-byte LE uint32 length][JSON bytes]
|
||||
std::vector<uint8_t> encode(const Message &msg);
|
||||
IPC_API std::vector<uint8_t> encode(const Message &msg);
|
||||
|
||||
/// Decode a binary frame (without the 4-byte length prefix) into a Message.
|
||||
/// Returns false if the JSON is invalid or missing required fields.
|
||||
bool decode(const uint8_t *data, size_t len, Message &out);
|
||||
bool decode(const std::vector<uint8_t> &frame, Message &out);
|
||||
IPC_API bool decode(const uint8_t *data, size_t len, Message &out);
|
||||
IPC_API bool decode(const std::vector<uint8_t> &frame, Message &out);
|
||||
|
||||
/// Blocking: read exactly one length-prefixed message from a FILE*.
|
||||
/// Returns false on EOF or read error.
|
||||
bool read_message(Message &out, FILE *in = stdin);
|
||||
IPC_API bool read_message(Message &out, FILE *in = stdin);
|
||||
|
||||
/// Write one length-prefixed message to a FILE*. Flushes after write.
|
||||
/// Returns false on write error.
|
||||
bool write_message(const Message &msg, FILE *out = stdout);
|
||||
IPC_API bool write_message(const Message &msg, FILE *out = stdout);
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
@ -2,10 +2,18 @@ cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(kbot CXX)
|
||||
|
||||
add_library(kbot STATIC
|
||||
kbot.cpp
|
||||
llm_client.cpp
|
||||
)
|
||||
option(POLYMECH_KBOT_SHARED "Build kbot as a shared library (DLL/so)" OFF)
|
||||
|
||||
set(_kbot_sources kbot.cpp llm_client.cpp)
|
||||
|
||||
if(POLYMECH_KBOT_SHARED)
|
||||
add_library(kbot SHARED ${_kbot_sources})
|
||||
target_compile_definitions(kbot PRIVATE POLYMECH_BUILDING_LIBRARY)
|
||||
else()
|
||||
add_library(kbot STATIC ${_kbot_sources})
|
||||
target_compile_definitions(kbot PRIVATE POLYMECH_STATIC_BUILD=1)
|
||||
target_compile_definitions(kbot INTERFACE POLYMECH_STATIC_BUILD=1)
|
||||
endif()
|
||||
|
||||
target_include_directories(kbot PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
@ -17,3 +25,25 @@ target_link_libraries(kbot PUBLIC
|
||||
json
|
||||
oai
|
||||
)
|
||||
|
||||
if(POLYMECH_KBOT_SHARED)
|
||||
set_target_properties(kbot PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist"
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/dist"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/dist"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS kbot
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/kbot.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/llm_client.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/polymech_export.h
|
||||
DESTINATION include/polymech
|
||||
)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "polymech_export.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@ -65,8 +66,8 @@ struct KBotCallbacks {
|
||||
std::function<void(const std::string& type, const std::string& json)> onEvent;
|
||||
};
|
||||
|
||||
int run_kbot_ai_pipeline(const KBotOptions& opts, const KBotCallbacks& cb);
|
||||
int run_kbot_run_pipeline(const KBotRunOptions& opts, const KBotCallbacks& cb);
|
||||
POLYMECH_API int run_kbot_ai_pipeline(const KBotOptions& opts, const KBotCallbacks& cb);
|
||||
POLYMECH_API int run_kbot_run_pipeline(const KBotRunOptions& opts, const KBotCallbacks& cb);
|
||||
|
||||
} // namespace kbot
|
||||
} // namespace polymech
|
||||
|
||||
@ -14,7 +14,7 @@ struct LLMResponse {
|
||||
std::string provider_meta_json;
|
||||
};
|
||||
|
||||
class LLMClient {
|
||||
class POLYMECH_API LLMClient {
|
||||
public:
|
||||
// Initialize the client with the options (api_key, model, router).
|
||||
explicit LLMClient(const KBotOptions& opts);
|
||||
|
||||
@ -14,7 +14,7 @@ CLI::App* setup_cmd_kbot(CLI::App& app);
|
||||
int run_cmd_kbot_ai();
|
||||
int run_cmd_kbot_run();
|
||||
|
||||
/// IPC / UDS Entry points
|
||||
/// IPC / UDS Entry points (implemented in src/cmd_kbot*.cpp — not in libkbot; compile those TU into your binary).
|
||||
int run_kbot_ai_ipc(const std::string& payload, const std::string& jobId, const kbot::KBotCallbacks& cb);
|
||||
int run_kbot_run_ipc(const std::string& payload, const std::string& jobId, const kbot::KBotCallbacks& cb);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user