Module client
Summary
The client module provides the public-facing asynchronous interface for interacting with large language model (LLM) endpoints. It exposes three primary templated functions: call_llm_async, call_completion_async, and call_structured_async. These functions accept model identifiers, prompts, and optional event loop pointers, returning integer handles or status codes. The module internally manages event loop selection through clore::net::detail::select_event_loop, ensuring asynchronous operations are dispatched on a valid kota::event_loop. The public scope also includes variables for request construction, such as system_prompt, model, prompt, and tool-related flags, enabling callers to configure and track LLM calls without directly handling low-level networking.
The module builds upon the http, protocol, schema, and support modules, leveraging their capabilities for HTTP dispatch, request/response data structures, structured output schemas, and logging utilities. Its responsibility centers on orchestrating the complete lifecycle of an LLM request—from parameter assembly and event loop binding to response handling—while abstracting protocol-specific details behind the Protocol template parameter. This design allows callers to focus on application logic while the module ensures reliable asynchronous execution and integration with the broader clore networking layer.
Imports
Imported By
Dependency Diagram
Functions
clore::net::call_completion_async
Declaration: network/client.cppm:16
Definition: network/client.cppm:57
Declaration: Namespace clore::net
The implementation of clore::net::call_completion_async employs a capability-probing retry loop (up to four attempts) to gracefully handle provider limitations exposed via HTTP 4xx rejection errors. On each iteration, the request is first sanitized against the current probed capabilities via sanitize_request_for_capabilities. The Protocol‑specific methods build_request_json, read_environment, build_url, and build_headers are then called to construct the outgoing payload and endpoint details. An asynchronous HTTP request is dispatched using clore::net::detail::perform_http_request_async on the event loop returned by clore::net::detail::select_event_loop. If the response carries a 4xx status and the body indicates a feature rejection (e.g., response_format, tool_choice, parallel_tool_calls, or tools), the corresponding capability flag in caps is updated to false, and the loop continues with the sanitized request as the new input. If the sanitization stripped tools while the original request required them, the function immediately fails with an LLMError. Otherwise, the raw response is parsed via Protocol::parse_response and the parsed result is returned. If all probing attempts are exhausted without success, the coroutine fails with an exhaustion error.
Side Effects
- mutates global capabilities cache via atomic stores
- performs HTTP I/O
- logs warnings via
logging::warn - may fail
co_awaitwithLLMError
Reads From
CompletionRequest request- global capabilities cache from
get_probed_capabilities - environment variables via
Protocol::read_environment - HTTP response body
- event loop reference
Writes To
- capabilities cache atomic booleans (
supports_json_schema,supports_tool_choice,supports_parallel_tool_calls,supports_tools) - output task result (either
CompletionResponseorLLMError) - log output
Usage Patterns
- retry loop with capability probing
- used by higher-level completion functions
- handles feature rejection errors
clore::net::call_llm_async
Declaration: network/client.cppm:20
Definition: network/client.cppm:137
Declaration: Namespace clore::net
The implementation of clore::net::call_llm_async is a coroutine that first resolves the active event loop via detail::select_event_loop, falling back to the provided loop or a default. It then delegates the core logic to detail::request_text_once_async, passing a lambda that invokes call_completion_async<Protocol> for the actual network request. The result is unwrapped using detail::unwrap_caught_result, and a cancellation of the inner kota::task is caught and re-raised as an LLMError. This design separates the retry and timeout logic (handled by request_text_once_async) from the single-shot completion call, while the template parameter Protocol allows the same flow to work with different LLM backends.
Side Effects
- performs an asynchronous LLM completion request via
call_completion_async - handles cancellation by setting a cancel error message
Reads From
- parameter
model - parameter
system_prompt - parameter
request - parameter
loop(used to select event loop) - result of
detail::select_event_loop
Writes To
- return value of type
kota::task<std::string, clore::net::LLMError>
Usage Patterns
- called to initiate an asynchronous LLM request with cancellation support
- used with an explicit event loop pointer or nullptr for default loop
- invoked as part of a coroutine chain for LLM completion
clore::net::call_llm_async
Declaration: network/client.cppm:27
Definition: network/client.cppm:156
Declaration: Namespace clore::net
The implementation of clore::net::call_llm_async begins by resolving the event loop via detail::select_event_loop, which returns a reference to either the provided pointer or a default loop. The coroutine then delegates all work to detail::request_text_once_async, a generic internal helper that orchestrates the actual LLM request life cycle. The first argument to that helper is a lambda that builds a CompletionRequest and forwards it to call_completion_async<Protocol>, ensuring that the completion path uses the same protocol and loop. The second, third, and fourth arguments are the model, system_prompt, and a PromptRequest struct containing the user prompt together with a Markdown output contract and no response format. After request_text_once_async completes, the function applies .or_fail() to unwrap the result or propagate any LLMError. The main dependency is detail::select_event_loop; the actual network interaction is abstracted into call_completion_async and the request_text_once_async machinery.
Side Effects
- Initiates asynchronous network I/O to an LLM provider
- Creates a coroutine task enabling suspension and later resumption
- Allocates
PromptRequest,CompletionRequest, and internal coroutine frame - May trigger rate-limit state updates or logging via called functions
Reads From
- Parameters
model,system_prompt,prompt - Global or function-static event loop state via
detail::select_event_loop - Probed capabilities cache via
get_probed_capabilities(indirectly throughcall_completion_async)
Writes To
- Event loop's pending task queue (via coroutine suspension)
- Rate-limit counters or logs (indirectly via callees)
- Promises and continuations in the coroutine pipeline
Usage Patterns
- Called by
clore::net::call_structured_async - Used in high-level async LLM request flows for text generation
- Invoked with template parameter
Protocolto select the LLM protocol (e.g.,OpenAI, Anthropic)
clore::net::call_structured_async
Declaration: network/client.cppm:34
Definition: network/client.cppm:177
Declaration: Namespace clore::net
The function template first retrieves a JSON schema describing the expected structured output by calling clore::net::schema::response_format<T>(). If the schema is unavailable, the coroutine immediately fails by yielding to kota::fail. Otherwise, a clore::net::CompletionRequest is constructed, containing the model identifier and a sequence of a system message and a user message, along with the obtained response_format and empty tool-related fields. The coroutine then delegates to clore::net::call_completion_async<Protocol>, passing the request and the event loop resolved via clore::net::detail::select_event_loop. After awaiting the completion call, the raw response string is parsed through clore::net::protocol::parse_response_text<T>. If parsing succeeds, the parsed value is returned; otherwise, the coroutine fails with the parse error. This flow ensures that the output strictly adheres to the type’s schema and that any failure in schema retrieval, API call, or response parsing is surfaced as a clore::net::LLMError via the coroutine’s error channel.
Side Effects
- allocates strings for request construction
- performs asynchronous I/O via
call_completion_async - may propagate errors via
kota::fail
Reads From
- model parameter
system_promptparameter- prompt parameter
- loop parameter
- global schema registry via
clore::net::schema::response_format<T>()
Writes To
- internal
CompletionRequestvariable - response string from
call_completion_async - returned task containing parsed T value
Usage Patterns
- invoked to obtain a structured typed response from an LLM
- used in coroutine contexts requiring a
kota::taskfor T - relies on schema registration for type T
clore::net::detail::select_event_loop
Declaration: network/client.cppm:45
Definition: network/client.cppm:45
Declaration: Namespace clore::net::detail
Implementation: Implementation
The function clore::net::detail::select_event_loop provides a single dispatch point for obtaining an active event loop reference. It first checks whether the incoming pointer loop is non‑null; if so, it dereferences and returns that loop directly. When loop is nullptr, the function falls back to kota::event_loop::current(), which must return a valid loop—this precondition is undefined if no event loop is active on the calling thread. The implementation thus relies on the runtime state of the kota::event_loop singleton and ensures the caller always receives a usable loop reference without further validation.
Side Effects
No observable side effects are evident from the extracted code.
Reads From
- parameter
loop - thread-local state accessed by
kota::event_loop::current()
Usage Patterns
- Used by async functions like
call_completion_asyncandcall_llm_asyncto resolve an optional event loop pointer to a valid reference before passing it to internal logic.
Internal Structure
The client module (implemented in network/client.cppm) serves as the top-level orchestration layer for asynchronous interactions with large language models. It imports the http module for low‑level network dispatch, the protocol module for structured request/response types, and the schema module for generating OpenAI‑compliant JSON schemas, along with support for foundational utilities. Its public API consists of templated functions—call_llm_async, call_completion_async, and call_structured_async—each accepting a kota::event_loop * that defaults to an internally selected loop via the detail::select_event_loop helper. These functions manage the full lifecycle of an LLM request, from constructing payloads (e.g., from system_prompt, model, and prompt variables) to parsing responses and handling tool calls.
Internally, the module maintains state for active requests through variables such as loop, active_loop, request_json, sanitized, tools_stripped, and caps, which are exposed as public members for use by callers or inspectors. The detail namespace encapsulates the event‑loop selection logic, decoupling client code from the loop management details. This decomposition keeps the public interface clean while allowing the module to handle multiple concurrent asynchronous operations, rate‑limiting (via the http module), and structured‑output formatting transparently.