diff --git a/CLAUDE.md b/CLAUDE.md index cc4212d5..5ec8e6ec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,6 +33,7 @@ Code and comments are in English. The code must read as if an experienced produc ### Comments +- These rules apply to every language in the repo, not just C++: `//` in C++, Swift, Kotlin, and Dart, and `#` in CMake, Makefile, YAML, and shell all follow the same standard. No `====`/`----` banner rows and no capitalized section headers anywhere, including build files. - Comments are rare and used only where naming cannot carry the meaning. If it is obvious, decorative, or restates the code, delete it. - A comment explains intent or context, not the literal code. - Never add artificial section separators like `helpers`, `validators`, or `public methods`. Never write header comments that describe a method, a member, or a section. diff --git a/CMakeLists.txt b/CMakeLists.txt index 52077af0..0f311450 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ if(IONCLAW_BUILD_SHARED) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() -# Apple platform deployment targets +# apple platform deployment targets if(CMAKE_SYSTEM_NAME STREQUAL "iOS") set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "iOS deployment target") elseif(CMAKE_SYSTEM_NAME STREQUAL "watchOS") diff --git a/Makefile b/Makefile index eeca47bc..d0c04e0f 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -# IonClaw - Build System -# Usage: make help +# ionclaw build system +# run make help for the list of targets .DEFAULT_GOAL := help @@ -45,9 +45,7 @@ ANDROID_ABIS := arm64-v8a armeabi-v7a x86_64 x86 # --- helpers --- NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu) -# ============================================================ -# Help -# ============================================================ +# help .PHONY: help help: @@ -117,9 +115,7 @@ help: @echo " make build-android ANDROID_NDK=/path/to/ndk" @echo "" -# ============================================================ -# Build -# ============================================================ +# build .PHONY: build build: ## Build server executable (release) @@ -384,9 +380,7 @@ build-docker: ## Build Docker image docker build -t ionclaw . @echo "==> Done: docker image 'ionclaw'" -# ============================================================ -# Run -# ============================================================ +# run .PHONY: run run: build ## Build and run server (release) @@ -429,9 +423,7 @@ run-android: build-android-aar ## Build (if needed), install and launch the nati adb shell am start -n com.ionclaw.app/.MainActivity @echo "==> Done." -# ============================================================ -# Setup -# ============================================================ +# setup .PHONY: setup-web setup-web: ## Install web client npm dependencies @@ -495,9 +487,7 @@ link-android: build-android-arm64 build-android-x86_64 ## Copy Android .so files cp $$(find $(ANDROID_NDK)/toolchains/llvm/prebuilt -path '*/lib/linux/x86_64/libomp.so' | head -1) $(ANDROID_AAR_JNILIBS)/x86_64/libomp.so @echo "==> Done: $(ANDROID_AAR_JNILIBS)/" -# ============================================================ -# Release -# ============================================================ +# release .PHONY: release-macos release-macos: link-flutter-macos link-flutter-web ## Build macOS release @@ -534,9 +524,7 @@ android-gen-key: ## Generate Android upload keystore and certificate flutter-deps: ## Install and upgrade Flutter dependencies cd $(FLUTTER_RUNNER_DIR) && flutter pub get && flutter pub upgrade -# ============================================================ -# Clean -# ============================================================ +# clean .PHONY: clean clean: ## Remove all build directories @@ -569,9 +557,7 @@ clean-android: ## Remove Android build directories and jniLibs rm -rf $(ANDROID_AAR_JNILIBS) rm -rf $(BUILD_ANDROID_AAR) -# ============================================================ -# Version -# ============================================================ +# version .PHONY: version version: ## Set project version: make version V=1.0.0+2 @@ -597,9 +583,7 @@ version: ## Set project version: make version V=1.0.0+2 echo " web/sw.js → $$VER"; \ echo "==> Done." -# ============================================================ -# Code -# ============================================================ +# code .PHONY: format format: ## Format all C/C++/ObjC sources with clang-format diff --git a/apps/android/app/src/main/java/com/ionclaw/app/ui/theme/Type.kt b/apps/android/app/src/main/java/com/ionclaw/app/ui/theme/Type.kt index d41d6445..9931b18c 100644 --- a/apps/android/app/src/main/java/com/ionclaw/app/ui/theme/Type.kt +++ b/apps/android/app/src/main/java/com/ionclaw/app/ui/theme/Type.kt @@ -6,7 +6,6 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -// Set of Material typography styles to start with val Typography = Typography( bodyLarge = TextStyle( fontFamily = FontFamily.Default, diff --git a/apps/apple/Shared/Sources/Platform/PlatformBridge.swift b/apps/apple/Shared/Sources/Platform/PlatformBridge.swift index 9a4a6540..c9f94f85 100644 --- a/apps/apple/Shared/Sources/Platform/PlatformBridge.swift +++ b/apps/apple/Shared/Sources/Platform/PlatformBridge.swift @@ -3,8 +3,7 @@ import Foundation import UserNotifications // bridges the native invoke_platform tool to apple platform features. -// the agent calls invoke_platform("local-notification.send", {title, message}) and the core -// forwards it here via the async c callback; we must respond exactly once per request. +// the core forwards each invoke_platform call here via the async c callback, and we respond exactly once per request. final class IonClawPlatform: NSObject, UNUserNotificationCenterDelegate { static let shared = IonClawPlatform() @@ -36,7 +35,7 @@ final class IonClawPlatform: NSObject, UNUserNotificationCenterDelegate { UNUserNotificationCenter.current().requestAuthorization(options: options) { _, _ in } } - // dispatches a request coming from the native core. runs on a core thread and must not block; + // dispatches a request from the native core on a core thread and must not block. // the response is delivered later from the async completion handler. func handle(requestId: Int64, function: String, paramsJson: String) { switch function { diff --git a/apps/apple/Shared/Sources/UI/QRCode.swift b/apps/apple/Shared/Sources/UI/QRCode.swift index 2f65fbd2..9671258d 100644 --- a/apps/apple/Shared/Sources/UI/QRCode.swift +++ b/apps/apple/Shared/Sources/UI/QRCode.swift @@ -1,7 +1,7 @@ import Foundation // pure-swift qr code generator (byte mode), so it works on watchos where coreimage is unavailable. -// follows the qr code model 2 specification (iso/iec 18004); algorithm based on project nayuki (mit). +// follows the qr code model 2 specification (iso/iec 18004), algorithm based on project nayuki (mit). struct QRCode { enum Correction: Int { case low = 0 diff --git a/apps/flutter/runner/lib/screen/browser_screen.dart b/apps/flutter/runner/lib/screen/browser_screen.dart index 2f6856e2..762d17ab 100644 --- a/apps/flutter/runner/lib/screen/browser_screen.dart +++ b/apps/flutter/runner/lib/screen/browser_screen.dart @@ -44,7 +44,7 @@ class _BrowserScreenState extends State { return NavigationDecision.prevent; } - // Intercept file download URLs + // intercept file download urls if (uri.path.startsWith('/api/files/download/')) { _downloadFile(uri); return NavigationDecision.prevent; diff --git a/cmake/embed-resources.cmake b/cmake/embed-resources.cmake index 6446b46c..d9bc3578 100644 --- a/cmake/embed-resources.cmake +++ b/cmake/embed-resources.cmake @@ -1,11 +1,4 @@ -# embed-resources.cmake -# Creates a ZIP of SOURCE_DIR and generates C++ source/header with the data as a byte array. -# -# Input variables: -# SOURCE_DIR - directory to embed -# OUTPUT_CPP - output .cpp file path -# OUTPUT_HPP - output .hpp file path -# NAMESPACE - C++ namespace for the generated code +# zips SOURCE_DIR and generates a c++ source and header embedding the bytes under NAMESPACE if(NOT SOURCE_DIR OR NOT OUTPUT_CPP OR NOT OUTPUT_HPP OR NOT NAMESPACE) message(FATAL_ERROR "embed-resources.cmake requires SOURCE_DIR, OUTPUT_CPP, OUTPUT_HPP, NAMESPACE") @@ -15,7 +8,7 @@ if(NOT EXISTS "${SOURCE_DIR}") message(FATAL_ERROR "embed-resources.cmake: SOURCE_DIR does not exist: ${SOURCE_DIR}") endif() -# create ZIP archive +# create the zip archive set(ZIP_FILE "${OUTPUT_CPP}.zip") execute_process( COMMAND ${CMAKE_COMMAND} -E tar cf "${ZIP_FILE}" --format=zip -- . @@ -27,16 +20,16 @@ if(NOT ZIP_RESULT EQUAL 0) message(FATAL_ERROR "embed-resources.cmake: failed to create ZIP from ${SOURCE_DIR}") endif() -# read ZIP as hex +# read the zip as hex file(READ "${ZIP_FILE}" ZIP_HEX HEX) file(SIZE "${ZIP_FILE}" ZIP_SIZE) -# format as C byte array: "0xAB,0xCD,..." +# format as a c byte array like 0xAB,0xCD string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," HEX_ARRAY "${ZIP_HEX}") # generate .cpp file(WRITE "${OUTPUT_CPP}" -"// Auto-generated by embed-resources.cmake - DO NOT EDIT +"// generated by embed-resources.cmake, do not edit #include namespace ${NAMESPACE} { @@ -51,7 +44,7 @@ size_t getSize() { return ${ZIP_SIZE}; } # generate .hpp file(WRITE "${OUTPUT_HPP}" -"// Auto-generated by embed-resources.cmake - DO NOT EDIT +"// generated by embed-resources.cmake, do not edit #pragma once #include diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index da4af70e..7c4c3524 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -135,7 +135,7 @@ set(IONCLAW_LIB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/lib/src/ionclaw/server/handler/McpHandler.cpp ) -# --- embed resources (shared by server and shared library) --- +# embed resources shared by the server and the shared library # web client file(GLOB_RECURSE IONCLAW_WEB_FILES "${CMAKE_CURRENT_SOURCE_DIR}/resources/web/*") add_custom_command( diff --git a/main/lib/include/ionclaw/bus/MessageBus.hpp b/main/lib/include/ionclaw/bus/MessageBus.hpp index 592d22f8..6f8e894c 100644 --- a/main/lib/include/ionclaw/bus/MessageBus.hpp +++ b/main/lib/include/ionclaw/bus/MessageBus.hpp @@ -43,7 +43,7 @@ class MessageBus std::condition_variable inboundCv; std::condition_variable outboundCv; - // bounds inbound memory under a flood; a burst beyond this is rejected with a clear error rather than buffered without limit + // bounds inbound memory under a flood by rejecting a burst beyond this with a clear error instead of buffering without limit static constexpr size_t MAX_INBOUND_QUEUE = 1000; // bounds each channel's outbound backlog so a stalled runner cannot grow it without limit diff --git a/main/lib/include/ionclaw/channel/TelegramRunner.hpp b/main/lib/include/ionclaw/channel/TelegramRunner.hpp index f85c6452..e3005c8c 100644 --- a/main/lib/include/ionclaw/channel/TelegramRunner.hpp +++ b/main/lib/include/ionclaw/channel/TelegramRunner.hpp @@ -53,7 +53,7 @@ class TelegramRunner void sendTextMessage(const std::string &chatId, const std::string &text, int replyToMessageId = 0); void sendChunkedMessage(const std::string &chatId, const std::string &text, int replyToMessageId = 0); - // sends a media attachment by public url; kind is image|audio|video|document + // sends a media attachment by public url with kind image, audio, video, or document void sendMediaByUrl(const std::string &chatId, const std::string &kind, const std::string &url, const std::string &caption, int replyToMessageId = 0); // turns a workspace media path into its public url, passing absolute urls through unchanged diff --git a/main/lib/include/ionclaw/channel/WebhookDedup.hpp b/main/lib/include/ionclaw/channel/WebhookDedup.hpp index 3c337402..171ccf85 100644 --- a/main/lib/include/ionclaw/channel/WebhookDedup.hpp +++ b/main/lib/include/ionclaw/channel/WebhookDedup.hpp @@ -16,7 +16,7 @@ namespace channel class WebhookDedup { public: - // returns true if this id is new (process it); false if it was already seen within the retention window + // returns true if this id is new and false if it was already seen within the retention window bool markSeen(const std::string &msgId); size_t size() const; diff --git a/main/lib/include/ionclaw/channel/WhatsAppSender.hpp b/main/lib/include/ionclaw/channel/WhatsAppSender.hpp index 0b1013c1..67041c2d 100644 --- a/main/lib/include/ionclaw/channel/WhatsAppSender.hpp +++ b/main/lib/include/ionclaw/channel/WhatsAppSender.hpp @@ -24,13 +24,13 @@ class WhatsAppSender // z-api base url is https://api.z-api.io/instances/{id}/token/{token}; client token goes in a header on every call static OutboundRequest zApiSendText(const std::string &baseUrl, const std::string &clientToken, const std::string &phone, const std::string &text, int delayTyping = 3); - // z-api media fields accept either a base64 data url or a public url; kind is image|audio|video|document + // z-api media fields accept a base64 data url or a public url with kind image, audio, video, or document static OutboundRequest zApiSendMedia(const std::string &baseUrl, const std::string &clientToken, const std::string &phone, const std::string &kind, const std::string &dataUrl, const std::string &caption, const std::string &fileName); // meta graph endpoint is https://graph.facebook.com/{version}/{phoneNumberId}/messages with a bearer token static OutboundRequest metaSendText(const std::string &graphVersion, const std::string &phoneNumberId, const std::string &accessToken, const std::string &to, const std::string &text); - // meta sends media by a public link; kind is image|audio|video|document, caption applies to everything except audio + // meta sends media by a public link where the caption applies to everything except audio static OutboundRequest metaSendMedia(const std::string &graphVersion, const std::string &phoneNumberId, const std::string &accessToken, const std::string &to, const std::string &kind, const std::string &link, const std::string &caption, const std::string &fileName); // meta marks the last inbound message read and shows a typing indicator in one call diff --git a/main/lib/include/ionclaw/channel/WhatsAppWebhook.hpp b/main/lib/include/ionclaw/channel/WhatsAppWebhook.hpp index 9ac6ff38..dc22b39f 100644 --- a/main/lib/include/ionclaw/channel/WhatsAppWebhook.hpp +++ b/main/lib/include/ionclaw/channel/WhatsAppWebhook.hpp @@ -15,8 +15,8 @@ namespace channel struct WebhookMedia { std::string kind; // image | audio | video | document - std::string url; // direct download url (z-api); empty for meta - std::string mediaId; // media id to fetch in two steps (meta); empty for z-api + std::string url; // direct download url for z-api, empty for meta + std::string mediaId; // media id fetched in two steps for meta, empty for z-api std::string mimeType; std::string caption; std::string fileName; // documents only @@ -43,7 +43,7 @@ class WhatsAppWebhook // z-api posts a single message object per webhook call static ParsedWebhookMessage parseZApi(const nlohmann::json &body); - // meta wraps messages under entry[].changes[].value.messages[]; one call may carry several + // meta wraps messages under entry[].changes[].value.messages[] and one call may carry several static std::vector parseMeta(const nlohmann::json &body); // validates the meta X-Hub-Signature-256 header (sha256=) against hmac-sha256(rawBody, appSecret) diff --git a/main/lib/include/ionclaw/provider/ModelCapabilities.hpp b/main/lib/include/ionclaw/provider/ModelCapabilities.hpp index a179b77f..0fda73fe 100644 --- a/main/lib/include/ionclaw/provider/ModelCapabilities.hpp +++ b/main/lib/include/ionclaw/provider/ModelCapabilities.hpp @@ -29,7 +29,7 @@ class ModelCapabilities // returns the record for a model (exact key, then after stripping a provider/ prefix), or nullopt if unknown static std::optional lookup(const std::string &model); - // capability queries; an unknown model defaults to permissive so a valid but unlisted model is never silently degraded + // capability queries default an unknown model to permissive so a valid but unlisted model is never silently degraded static bool supportsVision(const std::string &model, bool defaultIfUnknown = true); static bool supportsReasoning(const std::string &model, bool defaultIfUnknown = true); static bool supportsFunctionCalling(const std::string &model, bool defaultIfUnknown = true); diff --git a/main/lib/include/ionclaw/server/Routes.hpp b/main/lib/include/ionclaw/server/Routes.hpp index efbbd4b2..5f45b6ab 100644 --- a/main/lib/include/ionclaw/server/Routes.hpp +++ b/main/lib/include/ionclaw/server/Routes.hpp @@ -38,7 +38,7 @@ class Routes void handleAuthLogin(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp); - // inbound whatsapp webhooks (unauthenticated; verified by provider signature/token) + // inbound whatsapp webhooks that are unauthenticated but verified by the provider signature or token void handleWhatsAppZApiWebhook(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp); void handleWhatsAppMetaWebhook(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp); diff --git a/main/lib/src/ionclaw.cpp b/main/lib/src/ionclaw.cpp index 1ef6eca0..7c5e4a7e 100644 --- a/main/lib/src/ionclaw.cpp +++ b/main/lib/src/ionclaw.cpp @@ -98,7 +98,7 @@ extern "C" return jsonToMalloc({{"success", false}, {"error", "failed to extract template"}}); } - // orchestrator state lives at the project root; the agent workspace holds the agent's own files, including public/ + // orchestrator state lives at the project root while the agent workspace holds the agent's own files under public/ std::filesystem::create_directories(targetDir + "/sessions", ec); std::filesystem::create_directories(targetDir + "/workspace/skills", ec); std::filesystem::create_directories(targetDir + "/workspace/memory", ec); diff --git a/main/lib/src/ionclaw/agent/AgentLoop.cpp b/main/lib/src/ionclaw/agent/AgentLoop.cpp index 763dc0f7..c26fedb6 100644 --- a/main/lib/src/ionclaw/agent/AgentLoop.cpp +++ b/main/lib/src/ionclaw/agent/AgentLoop.cpp @@ -296,7 +296,7 @@ nlohmann::json AgentLoop::resolveMedia(const std::vector &paths, co for (const auto &path : paths) { - // only process audio files for transcription; images are handled via vision tool + // only audio files are transcribed here, images go through the vision tool auto ext = fs::path(path).extension().string(); ionclaw::util::StringHelper::toLowerInPlace(ext); @@ -404,8 +404,7 @@ void UsageTracker::record(const nlohmann::json &usage) return; } - // a proxy may send a token field as null (e.g. cache_creation_input_tokens when caching is unused), and value() - // throws type_error.302 on an explicit null, so read each field only when it is actually an integer + // a proxy may send a token field as an explicit null, so read each field only when it is actually an integer // clang-format off auto readInt = [&usage](const char *key) { auto it = usage.find(key); @@ -471,9 +470,8 @@ void AgentLoop::processMessage(const ionclaw::bus::InboundMessage &message, cons auto sessionKey = (message.metadata.contains("agent_session_key") && message.metadata["agent_session_key"].is_string()) ? message.metadata["agent_session_key"].get() : message.sessionKey(); auto baseKey = message.sessionKey(); - // per-turn state lives on the stack; the active-turn handle and session queue are still shared members, so this is - // safe only because the orchestrator serializes turns on one worker thread and never runs two turns on one AgentLoop - // at once. enabling real per-agent concurrency would require threading these through TurnState instead of the members. + // per-turn state lives on the stack and is safe only because the orchestrator serializes turns on one worker thread. + // per-agent concurrency would require threading the shared active-turn handle and session queue through TurnState. TurnState turnState; turnState.sessionQueuePtr = defaultSessionQueuePtr.load(std::memory_order_acquire); turnState.activeTurnHandle = defaultActiveTurnHandle.load(std::memory_order_acquire); @@ -643,10 +641,8 @@ void AgentLoop::processMessage(const ionclaw::bus::InboundMessage &message, cons } } - // save user message to the agent-scoped session - // channels pre-save under base key for immediate persistence; we also persist - // under the agent-scoped key so each agent has its own conversation history - // skip synthetic messages (steer injections, wake prompts) — not real user input + // channels pre-save under the base key, and this also persists under the agent-scoped key so each agent keeps its own history + // skip synthetic messages like steer injections and wake prompts that are not real user input bool isSynthetic = message.metadata.contains("synthetic") && message.metadata["synthetic"].is_boolean() && message.metadata["synthetic"].get(); if (!isSynthetic) @@ -759,8 +755,7 @@ void AgentLoop::processMessage(const ionclaw::bus::InboundMessage &message, cons // run agent loop auto responseText = runAgentLoop(messages, taskId, baseKey, sessionKey, agentName, toolContext, callback, turnState); - // resolve empty/silent responses: prefer message-tool content from this turn, - // then fall back to last sent content from a previous turn + // for an empty or silent response prefer message-tool content from this turn, then the last sent content from a previous turn if (responseText == "[SILENT]") { responseText = !messageToolDeliveredContent.empty() ? messageToolDeliveredContent : !turnState.lastSentContent.empty() ? turnState.lastSentContent @@ -1437,8 +1432,7 @@ std::string AgentLoop::runAgentLoop(std::vector &mes } } - // assemble final text: use last iteration's content if non-empty, - // otherwise fall back to accumulated text from all iterations + // use the last iteration's content when non-empty, otherwise the text accumulated across all iterations std::string finalText = response.content; if (finalText.empty() && iteration > 0) diff --git a/main/lib/src/ionclaw/agent/Orchestrator.cpp b/main/lib/src/ionclaw/agent/Orchestrator.cpp index 6932d2b2..f719d0b9 100644 --- a/main/lib/src/ionclaw/agent/Orchestrator.cpp +++ b/main/lib/src/ionclaw/agent/Orchestrator.cpp @@ -90,7 +90,7 @@ void Orchestrator::start() // create hook runner hookRunner = std::make_shared(); - // create subagent registry and announce queue; orchestrator state lives at the project root, outside the agent's workspace + // create the subagent registry and announce queue whose state lives at the project root, outside the agent workspace auto newSubagentRegistry = std::make_shared(config.projectPath); newSubagentRegistry->load(); newSubagentRegistry->recoverStaleRuns(); @@ -146,7 +146,7 @@ void Orchestrator::start() // prefix-based providers (e.g. claude-cli) have no config entry and no provider-level params if (providerConfig && providerConfig->modelParams.is_object() && !providerConfig->modelParams.empty()) { - // provider params are the base; agent params override + // provider params are the base and agent params override them auto merged = providerConfig->modelParams; if (resolvedAgentConfig.modelParams.is_object()) { @@ -916,8 +916,7 @@ void Orchestrator::processMessageDirect(const ionclaw::bus::InboundMessage &mess handleSubagentCompletion(subagentRunId, outcome, turnAborted); } - // if this parent turn spawned children that are still running, - // keep the task in Doing so the UI shows the agent is still working + // keep the task in Doing while this parent turn still has children running so the ui shows the agent is working if (subagentRunId.empty() && subagentRegistry && !turnHandle->taskId.empty() && !subagentRegistry->allChildrenTerminal(sessionKey)) { // re-mark task as Doing (processMessage already set it to Done) diff --git a/main/lib/src/ionclaw/bus/MessageBus.cpp b/main/lib/src/ionclaw/bus/MessageBus.cpp index 1d26cfd8..935d9b5b 100644 --- a/main/lib/src/ionclaw/bus/MessageBus.cpp +++ b/main/lib/src/ionclaw/bus/MessageBus.cpp @@ -25,7 +25,7 @@ bool MessageBus::isDuplicate(const InboundMessage &msg) purgeExpiredDedup(); - // test only; the key is recorded once the message is actually accepted so a rejected retry is not swallowed + // test only, since the key is recorded once the message is accepted so a rejected retry is not swallowed auto it = recentInbound.find(dedupKey(msg)); if (it != recentInbound.end()) @@ -91,7 +91,7 @@ bool MessageBus::exceedsSessionRate(const InboundMessage &msg) times.pop_front(); } - // test only; the timestamp is recorded on accept so a message dropped by a later check does not burn a rate slot + // test only, since the timestamp is recorded on accept so a message dropped by a later check does not burn a rate slot return times.size() >= MAX_PER_SESSION_IN_WINDOW; } diff --git a/main/lib/src/ionclaw/image/GeminiImageGenerator.cpp b/main/lib/src/ionclaw/image/GeminiImageGenerator.cpp index 0c5312ac..9c6f6c96 100644 --- a/main/lib/src/ionclaw/image/GeminiImageGenerator.cpp +++ b/main/lib/src/ionclaw/image/GeminiImageGenerator.cpp @@ -59,7 +59,7 @@ std::string GeminiImageGenerator::generate(const std::string &prompt, const std: Poco::URI baseUri(baseUrl); baseUrl = baseUri.getScheme() + "://" + baseUri.getAuthority(); - // imagen models use :predict endpoint; gemini models use :generateContent + // imagen models use the :predict endpoint and gemini models use :generateContent if (isImagenModel(modelId)) { return predict(prompt, filename, params, context, apiKey, baseUrl, modelId); diff --git a/main/lib/src/ionclaw/provider/AnthropicProvider.cpp b/main/lib/src/ionclaw/provider/AnthropicProvider.cpp index a8e51fbf..f0359244 100644 --- a/main/lib/src/ionclaw/provider/AnthropicProvider.cpp +++ b/main/lib/src/ionclaw/provider/AnthropicProvider.cpp @@ -76,7 +76,7 @@ nlohmann::json AnthropicProvider::validateTranscript(const nlohmann::json &messa } else { - // non-mergeable array content; insert placeholder to maintain alternation + // non-mergeable array content needs a placeholder to maintain alternation nlohmann::json placeholder; placeholder["role"] = "assistant"; placeholder["content"] = "(continued)"; diff --git a/main/lib/src/ionclaw/provider/ClaudeCliProvider.cpp b/main/lib/src/ionclaw/provider/ClaudeCliProvider.cpp index ab43a926..63ec9f01 100644 --- a/main/lib/src/ionclaw/provider/ClaudeCliProvider.cpp +++ b/main/lib/src/ionclaw/provider/ClaudeCliProvider.cpp @@ -334,7 +334,7 @@ ClaudeCliProvider::CliResult ClaudeCliProvider::runClaude(const std::string &, c return result; } -#else // POSIX (Linux, macOS) +#else // posix branch for linux and macos extern "C" char **environ; diff --git a/main/lib/src/ionclaw/provider/OpenAiProvider.cpp b/main/lib/src/ionclaw/provider/OpenAiProvider.cpp index 045e74d4..1651865b 100644 --- a/main/lib/src/ionclaw/provider/OpenAiProvider.cpp +++ b/main/lib/src/ionclaw/provider/OpenAiProvider.cpp @@ -332,7 +332,7 @@ nlohmann::json OpenAiProvider::buildRequestBody(const ChatCompletionRequest &req m["name"] = msg.name; } - // the tool message keeps only text; images are moved to a following user message so openai accepts the request + // the tool message keeps only text and moves images to a following user message so openai accepts the request if (msg.contentBlocks.is_array() && !msg.contentBlocks.empty()) { std::string toolText; diff --git a/main/lib/src/ionclaw/server/ServerInstance.cpp b/main/lib/src/ionclaw/server/ServerInstance.cpp index 5b551bfe..12ca9e45 100644 --- a/main/lib/src/ionclaw/server/ServerInstance.cpp +++ b/main/lib/src/ionclaw/server/ServerInstance.cpp @@ -128,7 +128,7 @@ ServerResult ServerInstance::start(const std::string &projectPath, const std::st configStore = std::make_shared(cfg); - // create core components; orchestrator state lives at the project root, outside the agent's workspace + // create the core components whose state lives at the project root, outside the agent workspace dispatcher = std::make_shared(); bus = std::make_shared(); sessionManager = std::make_shared(resolvedPath + "/sessions", cfg.sessionBudget.maxDiskBytes, cfg.sessionBudget.highWaterRatio); @@ -244,7 +244,7 @@ ServerResult ServerInstance::start(const std::string &projectPath, const std::st heartbeatService = std::make_shared(bus, sessionManager, defaultWorkspace, cfg.heartbeat.interval, cfg.heartbeat.enabled, cfg.heartbeat.agent); heartbeatService->start(); - // create and start cron service; its job store lives at the project root, outside the agent's workspace + // create and start the cron service whose job store lives at the project root, outside the agent workspace cronService = std::make_shared(bus, taskManager, resolvedPath); cronService->start(); diff --git a/main/lib/src/ionclaw/server/routes/ChannelRoutes.cpp b/main/lib/src/ionclaw/server/routes/ChannelRoutes.cpp index 71cd7dff..4eeabc4a 100644 --- a/main/lib/src/ionclaw/server/routes/ChannelRoutes.cpp +++ b/main/lib/src/ionclaw/server/routes/ChannelRoutes.cpp @@ -63,7 +63,7 @@ void Routes::handleChannelGet(Poco::Net::HTTPServerRequest &, Poco::Net::HTTPSer out["require_auth"] = ch.raw["require_auth"].get(); } - // whatsapp string fields; secrets are masked so they are never echoed back to the client + // whatsapp string fields with secrets masked so they are never echoed back to the client static const std::vector> whatsAppFields = {{"instance_id", false}, {"instance_token", true}, {"client_token", true}, {"access_token", true}, {"phone_number_id", false}, {"verify_token", true}, {"app_secret", true}, {"graph_version", false}}; for (const auto &[key, secret] : whatsAppFields) @@ -87,7 +87,7 @@ void Routes::handleChannelUpdate(Poco::Net::HTTPServerRequest &req, Poco::Net::H auto configData = body.value("config", nlohmann::json::object()); { - // the whatsapp channels can be created from the api on first configuration; other unknown names are rejected + // the whatsapp channels can be created from the api on first configuration while other unknown names are rejected auto config = configStore->snapshot(); if (name != "whatsapp_zapi" && name != "whatsapp_meta" && config->channels.find(name) == config->channels.end()) { @@ -137,7 +137,7 @@ void Routes::handleChannelUpdate(Poco::Net::HTTPServerRequest &req, Poco::Net::H ch.raw["require_auth"] = configData["require_auth"].get(); } - // whatsapp string fields; a masked or empty secret keeps the stored value so it is not wiped + // whatsapp string fields where a masked or empty secret keeps the stored value so it is not wiped static const std::vector> whatsAppFields = {{"instance_id", false}, {"instance_token", true}, {"client_token", true}, {"access_token", true}, {"phone_number_id", false}, {"verify_token", true}, {"app_secret", true}, {"graph_version", false}}; for (const auto &[key, secret] : whatsAppFields) diff --git a/main/lib/src/ionclaw/server/routes/ChatRoutes.cpp b/main/lib/src/ionclaw/server/routes/ChatRoutes.cpp index 34e4051f..81168211 100644 --- a/main/lib/src/ionclaw/server/routes/ChatRoutes.cpp +++ b/main/lib/src/ionclaw/server/routes/ChatRoutes.cpp @@ -140,8 +140,7 @@ void Routes::handleChatSend(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPSe inbound.queueMode = ionclaw::bus::SessionQueue::normalizeQueueMode(body["queue_mode"].get()); } - // steer bypass: if session has an active turn and mode is steer_compatible, - // inject directly into SessionQueue (bypasses MessageBus which blocks during turns) + // steer a session that has an active turn straight into the SessionQueue, bypassing the MessageBus that blocks during turns auto config = configStore->snapshot(); if (inbound.queueMode.has_value() && orchestrator && config && orchestrator->isSessionActive(sessionKey)) { diff --git a/main/lib/src/ionclaw/server/routes/WhatsAppWebhookRoutes.cpp b/main/lib/src/ionclaw/server/routes/WhatsAppWebhookRoutes.cpp index 69039699..b6c97890 100644 --- a/main/lib/src/ionclaw/server/routes/WhatsAppWebhookRoutes.cpp +++ b/main/lib/src/ionclaw/server/routes/WhatsAppWebhookRoutes.cpp @@ -25,7 +25,7 @@ void Routes::downloadWhatsAppMedia(ionclaw::channel::WebhookMedia &media, const std::string url = media.url; std::map headers; - // meta media: resolve the id to a temporary url; both this and the download use the bearer token + // meta media resolves the id to a temporary url, and both this and the download use the bearer token if (url.empty() && !media.mediaId.empty() && !accessToken.empty()) { headers["Authorization"] = "Bearer " + accessToken; @@ -144,7 +144,7 @@ void Routes::publishWhatsAppInbound(const ionclaw::channel::ParsedWebhookMessage void Routes::handleWhatsAppZApiWebhook(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) { - // z-api only posts inbound messages; a stray get is answered so the provider stops retrying + // z-api only posts inbound messages, so a stray get is answered to stop the provider retrying if (req.getMethod() != "POST") { sendJson(resp, {{"status", "ok"}}); diff --git a/main/lib/src/ionclaw/session/SessionManager.cpp b/main/lib/src/ionclaw/session/SessionManager.cpp index ea6afa71..8c3bf28e 100644 --- a/main/lib/src/ionclaw/session/SessionManager.cpp +++ b/main/lib/src/ionclaw/session/SessionManager.cpp @@ -145,8 +145,7 @@ Session &SessionManager::getOrCreateLocked(const std::string &sessionKey) loadFromDisk(sessionKey); } - // covers both a missing file and an existing file that failed to load; a bare cache[key] here would default-construct - // a session with an empty key and empty timestamps that masks the real file, so build a properly keyed session instead + // a bare cache[key] would default-construct a session with an empty key that masks the real file, so build a properly keyed one if (cache.find(sessionKey) == cache.end()) { Session session; @@ -273,7 +272,7 @@ bool SessionManager::addMessage(const std::string &sessionKey, const SessionMess if (it == cache.end()) { - // session was evicted between ensureSession and here; reload from disk to preserve timestamps + // the session was evicted between ensureSession and here, so reload from disk to preserve timestamps auto filePath = sessionFilePath(sessionKey); if (fs::exists(filePath)) diff --git a/main/lib/src/ionclaw/task/TaskManager.cpp b/main/lib/src/ionclaw/task/TaskManager.cpp index 2986b2a4..93682e5d 100644 --- a/main/lib/src/ionclaw/task/TaskManager.cpp +++ b/main/lib/src/ionclaw/task/TaskManager.cpp @@ -351,7 +351,7 @@ void TaskManager::appendToFile(const Task &task) { std::lock_guard flock(fileMutex); - // callers hold the data mutex, so tasks can be read here; periodically rewrite the whole file to bound its growth + // callers hold the data mutex so tasks can be read here, and the whole file is periodically rewritten to bound its growth if (++appendsSinceCompaction >= COMPACTION_APPEND_THRESHOLD) { appendsSinceCompaction = 0; diff --git a/main/lib/src/ionclaw/tool/ToolRegistry.cpp b/main/lib/src/ionclaw/tool/ToolRegistry.cpp index a207cfbe..c43beb8a 100644 --- a/main/lib/src/ionclaw/tool/ToolRegistry.cpp +++ b/main/lib/src/ionclaw/tool/ToolRegistry.cpp @@ -316,7 +316,7 @@ std::vector ToolRegistry::applyToolPolicy(const std::vector allowSet; for (const auto &name : policy.allow) { diff --git a/main/lib/src/ionclaw/tool/builtin/BrowserTool.cpp b/main/lib/src/ionclaw/tool/builtin/BrowserTool.cpp index 3ad6398a..43fdaa9e 100644 --- a/main/lib/src/ionclaw/tool/builtin/BrowserTool.cpp +++ b/main/lib/src/ionclaw/tool/builtin/BrowserTool.cpp @@ -568,7 +568,7 @@ class ChromeManager ChromeManager() = default; ~ChromeManager() { shutdown(); } - // terminate the browser we launched and forget it; caller must hold mutex + // terminate the browser we launched and forget it, with the caller holding the mutex bool terminateProcessLocked() { if (pid <= 0) @@ -3773,8 +3773,7 @@ static std::string actionSetTimezone(CdpTab &tab, const nlohmann::json ¶ms) if (timezone.empty()) { - // cdp requires a valid timezone id; use utc to effectively "clear" the override, - // then reload to apply the system timezone via a fresh page load + // cdp requires a valid timezone id, so use utc to clear the override and reload to apply the system timezone tab.sendCommand(cdp::emulation::SetTimezoneOverride, {{"timezoneId", "Etc/UTC"}}); return "Timezone override set to UTC. To fully restore the system timezone, reload the page after clearing."; } diff --git a/main/lib/src/ionclaw/util/ProcessRunner.cpp b/main/lib/src/ionclaw/util/ProcessRunner.cpp index b72de90f..a3599eea 100644 --- a/main/lib/src/ionclaw/util/ProcessRunner.cpp +++ b/main/lib/src/ionclaw/util/ProcessRunner.cpp @@ -164,7 +164,7 @@ ProcessResult ProcessRunner::run(const std::string &, int, size_t, const std::fu return result; } -#else // POSIX (Linux, macOS) +#else // posix branch for linux and macos void ProcessRunner::collectExitStatus(ProcessResult &result, int status) {