Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
6bbb82c
added flock metrics to all the providers
anasdorbani Dec 2, 2025
fa553a1
upgrade gh action to DuckDB 1.4.2
anasdorbani Dec 2, 2025
e0d4c1f
registered the metrics scalar functions
anasdorbani Dec 2, 2025
c79dfcd
added unit tests for the metrics feature
anasdorbani Dec 2, 2025
5abddab
added integration tests for the metrics feature
anasdorbani Dec 2, 2025
b90eac7
Removed old metrics wrapper
anasdorbani Dec 6, 2025
2b80454
Updated metrics registry
anasdorbani Dec 6, 2025
2965d81
Updated handlers to use MetricsManager
anasdorbani Dec 6, 2025
19ea07b
Merged scalar and aggregate metrics tests
anasdorbani Dec 6, 2025
12c2605
Updated metrics CMakeLists
anasdorbani Dec 6, 2025
7934bad
Added merged metrics integration tests
anasdorbani Dec 6, 2025
4de6e21
Fixed code formatting
anasdorbani Dec 6, 2025
03f58a4
Fixed include in llm_complete
anasdorbani Dec 6, 2025
d86c4c2
Replaced old FlockMetrics API call
anasdorbani Dec 6, 2025
5b7d511
Add missing metrics tracking to llm_complete function
anasdorbani Dec 6, 2025
12675b2
Update test prompts to ensure 1-2 word responses for faster, more pre…
anasdorbani Dec 6, 2025
c66bb3a
Remove legacy MetricsContext class (replaced by MetricsManager)
anasdorbani Dec 6, 2025
7aab760
Centralized shared standard library includes in common.hpp
anasdorbani Dec 6, 2025
d0325e8
Add metrics merging for aggregate functions
anasdorbani Dec 7, 2025
4ad6d1c
Add tests for metrics merging
anasdorbani Dec 7, 2025
ec3824a
Added URLHandler class for file download and validation utilities
anasdorbani Dec 10, 2025
50d3189
Refactored ExecuteBatch to use RequestType enum for unified request h…
anasdorbani Dec 10, 2025
42264eb
Implemented ExtractTranscriptionOutput for OpenAI, Azure, and Ollama …
anasdorbani Dec 10, 2025
17a6192
Added AddTranscriptionRequest implementation for OpenAI, Azure, and O…
anasdorbani Dec 10, 2025
c0adbc3
Added transcription request methods to IProvider interface and Model …
anasdorbani Dec 10, 2025
f4be1e2
Added audio transcription support to prompt manager and input parser
anasdorbani Dec 10, 2025
1b280c5
Added transcription mock methods and OLLAMA secret to test base classes
anasdorbani Dec 10, 2025
15537ff
Added unit tests for audio transcription in llm_complete and llm_filter
anasdorbani Dec 10, 2025
2a3da64
Added unit tests for audio transcription in aggregate LLM functions
anasdorbani Dec 10, 2025
cd2d869
Added unit tests for transcription in model provider adapters
anasdorbani Dec 10, 2025
72aa288
Added integration tests for audio transcription in scalar LLM functions
anasdorbani Dec 10, 2025
fc1d297
Added integration tests for audio transcription in aggregate LLM func…
anasdorbani Dec 10, 2025
893be86
Updated unit test database with audio transcription test data
anasdorbani Dec 10, 2025
64058f3
Added unit tests for TranscribeAudioColumn and made it public for tes…
anasdorbani Dec 10, 2025
ff53e8f
Added base64 encoding and regex URL detection to URL handler
anasdorbani Dec 11, 2025
8ae1f43
Improved null safety and type checking in prompt manager
anasdorbani Dec 11, 2025
29ada0b
Enhanced error handling and null checks in base handler
anasdorbani Dec 11, 2025
e918a81
Improved aggregate state initialization and metadata handling
anasdorbani Dec 11, 2025
285ab8d
Added null checks for transcription output in Azure and OpenAI handlers
anasdorbani Dec 11, 2025
1e61924
Updated Ollama handler to use chat API and improved response parsing
anasdorbani Dec 11, 2025
45cf50f
Updated scalar functions to use unique ID generation for metrics trac…
anasdorbani Dec 11, 2025
6f02270
Updated integration test configuration and database setup
anasdorbani Dec 11, 2025
58b827b
Updated integration tests for aggregate LLM functions
anasdorbani Dec 11, 2025
508c1a3
Updated integration tests for scalar LLM functions
anasdorbani Dec 11, 2025
4a7a5fe
Updated integration tests for metrics, parsers, and secret manager
anasdorbani Dec 11, 2025
9a4fe20
Updated unit tests for scalar LLM functions
anasdorbani Dec 11, 2025
85431b8
Updated unit tests for model manager and providers
anasdorbani Dec 11, 2025
ba54ffa
Updated unit test database with latest test data
anasdorbani Dec 11, 2025
a171c73
Added audio test file for integration tests
anasdorbani Dec 11, 2025
4c158a3
Updated temp file location to use flock storage directory instead of …
anasdorbani Dec 11, 2025
9095a07
Fix llm_filter to work without context_columns parameter
anasdorbani Dec 11, 2025
25036f1
Add unit and integration tests for llm_filter without context_columns
anasdorbani Dec 11, 2025
96d1794
Refactored storage attachment with RAII guard and retry mechanism
anasdorbani Dec 14, 2025
a7f7dac
Add LlmFunctionBindData structure and input parsing utilities
anasdorbani Dec 16, 2025
c0d644f
Add ResolveModelDetailsToJson and mock provider factory to model manager
anasdorbani Dec 16, 2025
1b17b8c
Refactor scalar functions to use LlmFunctionBindData structure
anasdorbani Dec 16, 2025
b00cc49
Refactor aggregate functions to use LlmFunctionBindData structure
anasdorbani Dec 16, 2025
990fc7f
Update tests to match new function signatures
anasdorbani Dec 16, 2025
7a6288f
Fix duplicate check for CREATE MODEL and CREATE PROMPT to check all t…
anasdorbani Dec 16, 2025
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
8 changes: 4 additions & 4 deletions .github/workflows/MainDistributionPipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ jobs:
name: Build extension binaries
uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@main
with:
duckdb_version: v1.4.0
duckdb_version: v1.4.2
extension_name: flock
ci_tools_version: main
exclude_archs: 'wasm_mvp;wasm_threads;wasm_eh'

duckdb-stable-build:
name: Build extension binaries
uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.4.0
uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.4.2
with:
duckdb_version: v1.4.0
ci_tools_version: v1.4.0
duckdb_version: v1.4.2
ci_tools_version: v1.4.2
extension_name: flock
exclude_archs: 'wasm_mvp;wasm_threads;wasm_eh'
2 changes: 1 addition & 1 deletion duckdb
Submodule duckdb updated 974 files
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(model_manager)
add_subdirectory(prompt_manager)
add_subdirectory(custom_parser)
add_subdirectory(secret_manager)
add_subdirectory(metrics)

set(EXTENSION_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/flock_extension.cpp ${EXTENSION_SOURCES}
Expand Down
59 changes: 57 additions & 2 deletions src/core/config/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ void Config::ConfigureGlobal() {
void Config::ConfigureLocal(duckdb::DatabaseInstance& db) {
auto con = Config::GetConnection(&db);
ConfigureTables(con, ConfigType::LOCAL);
con.Query(
duckdb_fmt::format("ATTACH DATABASE '{}' AS flock_storage;", Config::get_global_storage_path().string()));
}

void Config::ConfigureTables(duckdb::Connection& con, const ConfigType type) {
Expand All @@ -89,4 +87,61 @@ void Config::Configure(duckdb::ExtensionLoader& loader) {
}
}

void Config::AttachToGlobalStorage(duckdb::Connection& con, bool read_only) {
con.Query(duckdb_fmt::format("ATTACH DATABASE '{}' AS flock_storage {};",
Config::get_global_storage_path().string(), read_only ? "(READ_ONLY)" : ""));
}

void Config::DetachFromGlobalStorage(duckdb::Connection& con) {
con.Query("DETACH DATABASE flock_storage;");
}

bool Config::StorageAttachmentGuard::TryAttach(bool read_only) {
try {
Config::AttachToGlobalStorage(connection, read_only);
return true;
} catch (const std::exception&) {
return false;
}
}

bool Config::StorageAttachmentGuard::TryDetach() {
try {
Config::DetachFromGlobalStorage(connection);
return true;
} catch (const std::exception&) {
return false;
}
}

void Config::StorageAttachmentGuard::Wait(int milliseconds) {
auto start = std::chrono::steady_clock::now();
auto duration = std::chrono::milliseconds(milliseconds);
while (std::chrono::steady_clock::now() - start < duration) {
// Busy-wait until the specified duration has elapsed
}
}

Config::StorageAttachmentGuard::StorageAttachmentGuard(duckdb::Connection& con, bool read_only)
: connection(con), attached(false) {
for (int attempt = 0; attempt < MAX_RETRIES; ++attempt) {
if (TryAttach(read_only)) {
attached = true;
return;
}
Wait(RETRY_DELAY_MS);
}
Config::AttachToGlobalStorage(connection, read_only);
attached = true;
}

Config::StorageAttachmentGuard::~StorageAttachmentGuard() {
if (attached) {
try {
Config::DetachFromGlobalStorage(connection);
} catch (...) {
}
}
}

}// namespace flock
2 changes: 2 additions & 0 deletions src/core/config/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ void Config::SetupDefaultModelsConfig(duckdb::Connection& con, std::string& sche
"('default', 'gpt-4o-mini', 'openai'), "
"('gpt-4o-mini', 'gpt-4o-mini', 'openai'), "
"('gpt-4o', 'gpt-4o', 'openai'), "
"('gpt-4o-transcribe', 'gpt-4o-transcribe', 'openai'),"
"('gpt-4o-mini-transcribe', 'gpt-4o-mini-transcribe', 'openai'),"
"('text-embedding-3-large', 'text-embedding-3-large', 'openai'), "
"('text-embedding-3-small', 'text-embedding-3-small', 'openai');",
schema_name, table_name));
Expand Down
189 changes: 107 additions & 82 deletions src/custom_parser/query/model_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "flock/core/common.hpp"
#include "flock/core/config.hpp"
#include "flock/custom_parser/query_parser.hpp"
#include <sstream>
#include <stdexcept>

Expand Down Expand Up @@ -303,101 +304,123 @@ std::string ModelParser::ToSQL(const QueryStatement& statement) const {
switch (statement.type) {
case StatementType::CREATE_MODEL: {
const auto& create_stmt = static_cast<const CreateModelStatement&>(statement);
auto con = Config::GetConnection();
auto result = con.Query(duckdb_fmt::format(
" SELECT model_name"
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_DEFAULT_INTERNAL_TABLE"
" WHERE model_name = '{}'"
" UNION ALL "
" SELECT model_name "
" FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}';",
create_stmt.model_name, create_stmt.catalog.empty() ? "flock_storage." : "", create_stmt.model_name));
if (result->RowCount() != 0) {
throw std::runtime_error(duckdb_fmt::format("Model '{}' already exist.", create_stmt.model_name));
}
query = ExecuteQueryWithStorage([&create_stmt](duckdb::Connection& con) {
auto result = con.Query(duckdb_fmt::format(
" SELECT model_name"
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_DEFAULT_INTERNAL_TABLE"
" WHERE model_name = '{}'"
" UNION ALL "
" SELECT model_name "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}'"
" UNION ALL "
" SELECT model_name "
" FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}';",
create_stmt.model_name, create_stmt.model_name, create_stmt.model_name));

auto& materialized_result = result->Cast<duckdb::MaterializedQueryResult>();
if (materialized_result.RowCount() != 0) {
throw std::runtime_error(duckdb_fmt::format("Model '{}' already exist.", create_stmt.model_name));
}

query = duckdb_fmt::format(" INSERT INTO "
" {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" (model_name, model, provider_name, model_args) "
" VALUES ('{}', '{}', '{}', '{}');",
create_stmt.catalog, create_stmt.model_name, create_stmt.model,
create_stmt.provider_name, create_stmt.model_args.dump());
// Insert the new model
auto insert_query = duckdb_fmt::format(" INSERT INTO "
" {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" (model_name, model, provider_name, model_args) "
" VALUES ('{}', '{}', '{}', '{}');",
create_stmt.catalog, create_stmt.model_name, create_stmt.model,
create_stmt.provider_name, create_stmt.model_args.dump());
con.Query(insert_query);

return std::string("SELECT 'Model created successfully' AS status");
},
false);
break;
}
case StatementType::DELETE_MODEL: {
const auto& delete_stmt = static_cast<const DeleteModelStatement&>(statement);
auto con = Config::GetConnection();

con.Query(duckdb_fmt::format(" DELETE FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" WHERE model_name = '{}';",
delete_stmt.model_name));

query = duckdb_fmt::format(" DELETE FROM "
query = ExecuteSetQuery(
duckdb_fmt::format(" DELETE FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" WHERE model_name = '{}'; "
" DELETE FROM "
" flock_storage.flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" WHERE model_name = '{}';",
delete_stmt.model_name, delete_stmt.model_name);
delete_stmt.model_name, delete_stmt.model_name),
"Model deleted successfully",
false);
break;
}
case StatementType::UPDATE_MODEL: {
const auto& update_stmt = static_cast<const UpdateModelStatement&>(statement);
auto con = Config::GetConnection();
// get the location of the model_name if local or global
auto result = con.Query(
duckdb_fmt::format(" SELECT model_name, 'global' AS scope "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}'"
" UNION ALL "
" SELECT model_name, 'local' AS scope "
" FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}';",
update_stmt.model_name, update_stmt.model_name, update_stmt.model_name));
query = ExecuteQueryWithStorage([&update_stmt](duckdb::Connection& con) {
// Get the location of the model_name if local or global
auto result = con.Query(
duckdb_fmt::format(" SELECT model_name, 'global' AS scope "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}'"
" UNION ALL "
" SELECT model_name, 'local' AS scope "
" FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}';",
update_stmt.model_name, update_stmt.model_name, update_stmt.model_name));

auto& materialized_result = result->Cast<duckdb::MaterializedQueryResult>();
if (materialized_result.RowCount() == 0) {
throw std::runtime_error(duckdb_fmt::format("Model '{}' doesn't exist.", update_stmt.model_name));
}

if (result->RowCount() == 0) {
throw std::runtime_error(duckdb_fmt::format("Model '{}' doesn't exist.", update_stmt.model_name));
}
auto catalog = materialized_result.GetValue(1, 0).ToString() == "global" ? "flock_storage." : "";

auto catalog = result->GetValue(1, 0).ToString() == "global" ? "flock_storage." : "";
con.Query(duckdb_fmt::format(" UPDATE {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" SET model = '{}', provider_name = '{}', "
" model_args = '{}' WHERE model_name = '{}'; ",
catalog, update_stmt.new_model, update_stmt.provider_name,
update_stmt.new_model_args.dump(), update_stmt.model_name));

query = duckdb_fmt::format(" UPDATE {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
" SET model = '{}', provider_name = '{}', "
" model_args = '{}' WHERE model_name = '{}'; ",
catalog, update_stmt.new_model, update_stmt.provider_name,
update_stmt.new_model_args.dump(), update_stmt.model_name);
return std::string("SELECT 'Model updated successfully' AS status");
},
false);
break;
}
case StatementType::UPDATE_MODEL_SCOPE: {
const auto& update_stmt = static_cast<const UpdateModelScopeStatement&>(statement);
auto con = Config::GetConnection();
auto result =
con.Query(duckdb_fmt::format(" SELECT model_name "
" FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}';",
update_stmt.catalog, update_stmt.model_name));
if (result->RowCount() != 0) {
throw std::runtime_error(
duckdb_fmt::format("Model '{}' already exist in {} storage.", update_stmt.model_name,
update_stmt.catalog == "flock_storage." ? "global" : "local"));
}
query = ExecuteQueryWithStorage([&update_stmt](duckdb::Connection& con) {
auto result = con.Query(duckdb_fmt::format(" SELECT model_name "
" FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" WHERE model_name = '{}';",
update_stmt.catalog, update_stmt.model_name));

auto& materialized_result = result->Cast<duckdb::MaterializedQueryResult>();
if (materialized_result.RowCount() != 0) {
throw std::runtime_error(
duckdb_fmt::format("Model '{}' already exist in {} storage.", update_stmt.model_name,
update_stmt.catalog == "flock_storage." ? "global" : "local"));
}

con.Query(duckdb_fmt::format("INSERT INTO {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"(model_name, model, provider_name, model_args) "
"SELECT model_name, model, provider_name, model_args "
"FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"WHERE model_name = '{}'; ",
update_stmt.catalog,
update_stmt.catalog == "flock_storage." ? "" : "flock_storage.",
update_stmt.model_name));

query = duckdb_fmt::format("DELETE FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"WHERE model_name = '{}'; ",
update_stmt.catalog == "flock_storage." ? "" : "flock_storage.",
update_stmt.model_name);
con.Query(duckdb_fmt::format("INSERT INTO {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"(model_name, model, provider_name, model_args) "
"SELECT model_name, model, provider_name, model_args "
"FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"WHERE model_name = '{}'; ",
update_stmt.catalog,
update_stmt.catalog == "flock_storage." ? "" : "flock_storage.",
update_stmt.model_name));

con.Query(duckdb_fmt::format("DELETE FROM {}flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"WHERE model_name = '{}'; ",
update_stmt.catalog == "flock_storage." ? "" : "flock_storage.",
update_stmt.model_name));

return std::string("SELECT 'Model scope updated successfully' AS status");
},
false);
break;
}
case StatementType::GET_MODEL: {
const auto& get_stmt = static_cast<const GetModelStatement&>(statement);
query = duckdb_fmt::format("SELECT 'global' AS scope, * "
query = ExecuteGetQuery(
duckdb_fmt::format("SELECT 'global' AS scope, * "
"FROM flock_storage.flock_config.FLOCKMTL_MODEL_DEFAULT_INTERNAL_TABLE "
"WHERE model_name = '{}' "
"UNION ALL "
Expand All @@ -408,20 +431,22 @@ std::string ModelParser::ToSQL(const QueryStatement& statement) const {
"SELECT 'local' AS scope, * "
"FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE "
"WHERE model_name = '{}';",
get_stmt.model_name, get_stmt.model_name, get_stmt.model_name, get_stmt.model_name);
get_stmt.model_name, get_stmt.model_name, get_stmt.model_name, get_stmt.model_name),
true);
break;
}

case StatementType::GET_ALL_MODEL: {
query = duckdb_fmt::format(" SELECT 'global' AS scope, * "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_DEFAULT_INTERNAL_TABLE"
" UNION ALL "
" SELECT 'global' AS scope, * "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" UNION ALL "
" SELECT 'local' AS scope, * "
" FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE;",
Config::get_global_storage_path().string());
query = ExecuteGetQuery(
" SELECT 'global' AS scope, * "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_DEFAULT_INTERNAL_TABLE"
" UNION ALL "
" SELECT 'global' AS scope, * "
" FROM flock_storage.flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE"
" UNION ALL "
" SELECT 'local' AS scope, * "
" FROM flock_config.FLOCKMTL_MODEL_USER_DEFINED_INTERNAL_TABLE;",
true);
break;
}
default:
Expand Down
Loading
Loading