Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions include/ai/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@
/// #include <ai/core.h>
///
/// // Use core types like ai::GenerateOptions, ai::Message, etc.
/// ai::GenerateOptions options{
/// .model = "some-model",
/// .prompt = "Hello world"
/// };
/// ai::GenerateOptions options("some-model", "Hello world");
/// ```
namespace ai {}
38 changes: 36 additions & 2 deletions include/ai/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,55 @@ class ConsoleLogger final : public Logger {

namespace detail {

#if defined(__cpp_lib_atomic_shared_ptr)

inline std::atomic<std::shared_ptr<Logger>>& logger_instance() {
static std::atomic<std::shared_ptr<Logger>> instance(
std::make_shared<ConsoleLogger>());
return instance;
}

inline std::shared_ptr<Logger> load_logger() {
return logger_instance().load();
}

inline void store_logger(std::shared_ptr<Logger> logger) {
logger_instance().store(std::move(logger));
}

#else
// Fall back to the atomic shared_ptr free functions on standard libraries
// that have not implemented std::atomic<std::shared_ptr> (notably libc++).

inline std::shared_ptr<Logger>& logger_instance() {
static std::shared_ptr<Logger> instance = std::make_shared<ConsoleLogger>();
return instance;
}

inline std::shared_ptr<Logger> load_logger() {
return std::atomic_load(&logger_instance());
}

inline void store_logger(std::shared_ptr<Logger> logger) {
std::atomic_store(&logger_instance(), std::move(logger));
}

#endif

} // namespace detail

inline void install_logger(std::shared_ptr<Logger> logger) {
if (logger) {
std::atomic_store(&detail::logger_instance(), std::move(logger));
detail::store_logger(std::move(logger));
}
}

/// Returns the currently installed logger. The reference stays valid until
/// the next logger()/log_* call on the same thread; do not cache it across
/// calls that may log.
inline Logger& logger() {
auto ptr = std::atomic_load(&detail::logger_instance());
thread_local std::shared_ptr<Logger> ptr;
ptr = detail::load_logger();
return *ptr;
}

Expand Down
2 changes: 1 addition & 1 deletion src/langfuse/tracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ std::string Trace::to_iso8601(std::chrono::system_clock::time_point t) {
#else
gmtime_r(&tt, &tm);
#endif
char buf[40];
char buf[80];
std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lldZ",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec, static_cast<long long>(ms));
Expand Down
12 changes: 6 additions & 6 deletions src/providers/anthropic/anthropic_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

#include "ai/errors.h"
#include "anthropic_client.h"
#include "utils/env_utils.h"

#include <cstdlib>
#include <memory>
#include <optional>

Expand All @@ -18,13 +18,13 @@ std::string get_api_key_or_default(const std::string& api_key) {
return api_key;
}

const char* env_api_key = std::getenv("ANTHROPIC_API_KEY");
auto env_api_key = utils::non_empty_env("ANTHROPIC_API_KEY");
if (!env_api_key) {
throw ConfigurationError(
"API key not provided and ANTHROPIC_API_KEY environment variable not "
"set");
}
return env_api_key;
return *std::move(env_api_key);
}

std::string get_base_url_or_default(const std::string& base_url) {
Expand All @@ -48,12 +48,12 @@ Client create_client(const std::string& api_key, const std::string& base_url) {
}

std::optional<Client> try_create_client() {
const char* api_key = std::getenv("ANTHROPIC_API_KEY");
auto api_key = utils::non_empty_env("ANTHROPIC_API_KEY");
if (!api_key) {
return std::nullopt;
}
return Client(std::make_unique<AnthropicClient>(api_key, kDefaultBaseUrl));
return Client(std::make_unique<AnthropicClient>(*api_key, kDefaultBaseUrl));
}

} // namespace anthropic
} // namespace ai
} // namespace ai
4 changes: 2 additions & 2 deletions src/providers/anthropic/anthropic_response_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ EmbeddingResult AnthropicResponseParser::parse_success_embedding_response(

// Extract choices
if (response.contains("data") && !response["data"].empty()) {
result.data = std::move(response["data"]);
result.data = response["data"];
}

// Extract usage
Expand Down Expand Up @@ -150,4 +150,4 @@ FinishReason AnthropicResponseParser::parse_stop_reason(
}

} // namespace anthropic
} // namespace ai
} // namespace ai
3 changes: 2 additions & 1 deletion src/providers/base_provider_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ GenerateResult BaseProviderClient::generate_text_single_step(
}

StreamResult BaseProviderClient::stream_text(const StreamOptions& options) {
(void)options;
// This needs to be implemented with provider-specific stream implementations
// For now, return an error
ai::logger::log_error("Streaming not yet implemented in BaseProviderClient");
Expand Down Expand Up @@ -197,4 +198,4 @@ EmbeddingResult BaseProviderClient::embeddings(
}

} // namespace providers
} // namespace ai
} // namespace ai
12 changes: 6 additions & 6 deletions src/providers/openai/openai_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

#include "ai/errors.h"
#include "openai_client.h"
#include "utils/env_utils.h"

#include <cstdlib>
#include <memory>
#include <optional>

Expand All @@ -18,12 +18,12 @@ std::string get_api_key_or_default(const std::string& api_key) {
return api_key;
}

const char* env_api_key = std::getenv("OPENAI_API_KEY");
auto env_api_key = utils::non_empty_env("OPENAI_API_KEY");
if (!env_api_key) {
throw ConfigurationError(
"API key not provided and OPENAI_API_KEY environment variable not set");
}
return env_api_key;
return *std::move(env_api_key);
}

std::string get_base_url_or_default(const std::string& base_url) {
Expand Down Expand Up @@ -55,12 +55,12 @@ Client create_client(const std::string& api_key,
}

std::optional<Client> try_create_client() {
const char* api_key = std::getenv("OPENAI_API_KEY");
auto api_key = utils::non_empty_env("OPENAI_API_KEY");
if (!api_key) {
return std::nullopt;
}
return Client(std::make_unique<OpenAIClient>(api_key, kDefaultBaseUrl));
return Client(std::make_unique<OpenAIClient>(*api_key, kDefaultBaseUrl));
}

} // namespace openai
} // namespace ai
} // namespace ai
4 changes: 2 additions & 2 deletions src/providers/openai/openai_response_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ EmbeddingResult OpenAIResponseParser::parse_success_embedding_response(

// Extract choices
if (response.contains("data") && !response["data"].empty()) {
result.data = std::move(response["data"]);
result.data = response["data"];
}

// Extract usage
Expand Down Expand Up @@ -192,4 +192,4 @@ FinishReason OpenAIResponseParser::parse_finish_reason(
}

} // namespace openai
} // namespace ai
} // namespace ai
4 changes: 3 additions & 1 deletion src/tools/tool_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ Tool create_simple_tool(const std::string& name,
const std::string& description,
const std::map<std::string, std::string>& parameters,
ToolExecuteFunction execute_func) {
(void)name; // The ToolSet key is the canonical tool name.
JsonValue schema = create_object_schema(parameters);
return create_tool(description, schema, std::move(execute_func));
}
Expand All @@ -241,6 +242,7 @@ Tool create_simple_async_tool(
const std::string& description,
const std::map<std::string, std::string>& parameters,
AsyncToolExecuteFunction execute_func) {
(void)name; // The ToolSet key is the canonical tool name.
JsonValue schema = create_object_schema(parameters);
return create_async_tool(description, schema, std::move(execute_func));
}
Expand Down Expand Up @@ -280,4 +282,4 @@ std::string generate_tool_call_id() {
return id;
}

} // namespace ai
} // namespace ai
20 changes: 20 additions & 0 deletions src/utils/env_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <cstdlib>
#include <optional>
#include <string>

namespace ai {
namespace utils {

/// Read an environment variable, treating unset and empty values as absent.
inline std::optional<std::string> non_empty_env(const char* name) {
const char* value = std::getenv(name);
if (!value || *value == '\0') {
return std::nullopt;
}
return std::string(value);
}

} // namespace utils
} // namespace ai
Loading