|
NeuralPlus 0.2.0
An open-source, provider-independent C++17 AI SDK and LLM client library
|
Use FunctionTool unless the tool needs a reusable class:
A tool should validate all model-generated input, use stable names, keep its output concise, and avoid global session data. The SDK serializes calls to the same shared Tool object. Different tool objects can run in parallel and must synchronize any captured services they share.
ToolSpec::provider_options can add declaration fields understood only by the selected provider. The adapter applies the stable name, description, and input_schema after these options, so portable fields always win. To combine provider-native server tools with local tools, put the native declarations in the tools array of ModelDescriptor::provider_options or GenerateOptions::provider_options; the adapter appends local declarations. Provider options cannot enable OpenAI or Anthropic streaming, or OpenAI background responses, because AIClient::generate exposes a synchronous complete-response contract.
The AIClient constructor snapshots every validated ToolSpec. Do not rely on mutating a declaration after client construction. Mutable execution state belongs in the tool implementation or SessionState, with the synchronization required by the application's concurrency policy.
Subclass Tool when lifecycle, dependency ownership, or test seams make a class clearer. Implement spec() and invoke(); no registry or task wrapper is needed.
Subclass AIClient and implement exactly one method:
Keep these concerns inside the adapter:
HttpTransport;ProviderError.Set AIResponse::requires_continuation when the provider protocol requires another round even though there are no local tool calls. Preserve the native assistant material in Message::provider_metadata; AIClient appends that message and calls generate_once again. Anthropic pause_turn is the built-in example. The base class applies the same round limit to continuation rounds.
Populate only the TokenUsage fields the response actually reports or that the adapter can calculate safely. Do not convert a missing counter to zero. The base class preserves this distinction while accumulating multi-round usage.
Do not reimplement session mutation, multi-round tool execution, or tracer fan-out. Tests should inject MockHttpTransport with sanitized JSON. The default suite must not need credentials or network access.
One client may process different sessions concurrently. Built-in adapters support this; a custom provider's generate_once implementation must be thread-safe.
Use FunctionAIClient for an in-process runtime, test double, or thin application adapter. Populate ModelDescriptor::capabilities accurately so unsupported content and tools fail before a request is sent. The convenience class serializes calls to its callback.
Subclass Tracer for a reusable backend, or supply a FunctionTracer:
A custom Tracer::record must be thread-safe, bounded, and non-blocking enough for the application's latency goals. FunctionTracer serializes calls to its callback. The client catches tracer exceptions, but a backend should still report its own delivery failures out of band.
Treat payload as sensitive. Preserve the default metadata-only policy, use allowlisted attributes, and avoid authorization headers and request bodies.
For OpenTelemetry, translate the event in a FunctionTracer to the official OpenTelemetry C++ API. Use run_id for the logical generation, operation_id for a model round or tool call, and provider request IDs as attributes. An application owns SDK initialization, exporters, sampling, and shutdown. NeuralPlus does not force-link the OpenTelemetry SDK.
A minimal bridge keeps the OpenTelemetry objects in application code:
Map generation_start/generation_end to a run span, provider_start/provider_end and tool_start/tool_end to child spans, and error to an error status. Do not attach payload unless the application's telemetry policy explicitly permits it.
SyslogTracer follows POSIX syslog and is unavailable on Windows. It supplies the facility with each record and uses an identity prefix without changing process-global openlog state.
Implement HttpTransport::send to integrate an application HTTP stack. Preserve these security properties of the built-in libcurl transport:
HttpTransportOptions defaults to a 16 MiB response-body limit and a 256 KiB aggregate response-header limit. Custom transports should apply equivalent application-appropriate bounds and should never return partial data as a successful response after crossing one.
Transport instances may be shared by multiple clients, so implementations must be safe for the application's concurrency pattern.