Skip to content

Commit f4a5ed0

Browse files
committed
fix: reduce llm token usage by using sqlite-mcp virtual tables instead of raw json functions
1 parent 4b30cd6 commit f4a5ed0

File tree

3 files changed

+65
-36
lines changed

3 files changed

+65
-36
lines changed

src/sqlite-agent.c

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,64 +34,93 @@ static void agent_version(
3434
static char* agent_call_mcp_tool(sqlite3 *db, const char *tool_name, const char *tool_args) {
3535
sqlite3_stmt *stmt;
3636
char sql[1024];
37-
snprintf(sql, sizeof(sql), "SELECT mcp_call_tool_json(?, ?)");
37+
snprintf(sql, sizeof(sql), "SELECT text FROM mcp_call_tool_respond(?, ?)");
3838

3939
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
4040
if (rc != SQLITE_OK) {
41-
DF("Failed to prepare mcp_call_tool_json(): %s", sqlite3_errmsg(db));
41+
DF("Failed to prepare mcp_call_tool_respond(): %s", sqlite3_errmsg(db));
4242
return NULL;
4343
}
4444

4545
sqlite3_bind_text(stmt, 1, tool_name, -1, SQLITE_TRANSIENT);
4646
sqlite3_bind_text(stmt, 2, tool_args, -1, SQLITE_TRANSIENT);
4747

48-
rc = sqlite3_step(stmt);
49-
if (rc != SQLITE_ROW) {
50-
DF("Failed to execute mcp_call_tool_json(): %s", sqlite3_errmsg(db));
48+
// Collect all text results from the virtual table
49+
char *result_buffer = malloc(32768);
50+
if (!result_buffer) {
5151
sqlite3_finalize(stmt);
5252
return NULL;
5353
}
54-
55-
const char *result = (const char*)sqlite3_column_text(stmt, 0);
56-
if (!result) {
57-
sqlite3_finalize(stmt);
58-
return NULL;
54+
result_buffer[0] = '\0';
55+
56+
int has_results = 0;
57+
while (sqlite3_step(stmt) == SQLITE_ROW) {
58+
const char *text = (const char*)sqlite3_column_text(stmt, 0);
59+
if (text) {
60+
if (has_results) {
61+
strncat(result_buffer, "\n", 32767 - strlen(result_buffer));
62+
}
63+
strncat(result_buffer, text, 32767 - strlen(result_buffer));
64+
has_results = 1;
65+
}
5966
}
60-
61-
char *result_copy = strdup(result);
67+
6268
sqlite3_finalize(stmt);
63-
return result_copy;
69+
70+
if (!has_results) {
71+
free(result_buffer);
72+
return NULL;
73+
}
74+
75+
return result_buffer;
6476
}
6577

6678
static char* agent_get_tools_list(sqlite3 *db) {
6779
sqlite3_stmt *stmt;
68-
int rc = sqlite3_prepare_v2(db, "SELECT mcp_list_tools_json()", -1, &stmt, NULL);
80+
int rc = sqlite3_prepare_v2(db, "SELECT name, description, inputschema FROM mcp_list_tools_respond", -1, &stmt, NULL);
6981
if (rc != SQLITE_OK) {
70-
DF("Failed to prepare mcp_list_tools_json(): %s", sqlite3_errmsg(db));
82+
DF("Failed to prepare mcp_list_tools_respond query: %s", sqlite3_errmsg(db));
7183
return NULL;
7284
}
7385

74-
rc = sqlite3_step(stmt);
75-
if (rc != SQLITE_ROW) {
76-
DF("Failed to execute mcp_list_tools_json(): %s", sqlite3_errmsg(db));
86+
char *formatted = malloc(65536); // Increased buffer size for schemas
87+
if (!formatted) {
7788
sqlite3_finalize(stmt);
7889
return NULL;
7990
}
8091

81-
const char *tools_result = (const char*)sqlite3_column_text(stmt, 0);
82-
if (!tools_result) {
83-
sqlite3_finalize(stmt);
84-
return NULL;
92+
strcpy(formatted, "Available tools:\n");
93+
int tool_count = 0;
94+
95+
while (sqlite3_step(stmt) == SQLITE_ROW) {
96+
const char *name = (const char*)sqlite3_column_text(stmt, 0);
97+
const char *description = (const char*)sqlite3_column_text(stmt, 1);
98+
const char *inputschema = (const char*)sqlite3_column_text(stmt, 2);
99+
100+
if (name) {
101+
tool_count++;
102+
char tool_line[1024];
103+
snprintf(tool_line, sizeof(tool_line),
104+
"- %s: %s\n%s\n",
105+
name,
106+
description ? description : "(no description)",
107+
inputschema ? inputschema : "(no input schema)");
108+
109+
size_t remaining = 65535 - strlen(formatted);
110+
if (strlen(tool_line) < remaining) {
111+
strcat(formatted, tool_line);
112+
}
113+
}
85114
}
86-
87-
char *formatted = malloc(32768);
88-
if (!formatted) {
89-
sqlite3_finalize(stmt);
115+
116+
sqlite3_finalize(stmt);
117+
118+
if (tool_count == 0) {
119+
free(formatted);
90120
return NULL;
91121
}
92-
93-
snprintf(formatted, 32768, "Available tools (JSON):\n%s", tools_result);
94-
sqlite3_finalize(stmt);
122+
123+
DF("Formatted %d tools for agent context", tool_count);
95124
return formatted;
96125
}
97126

@@ -432,7 +461,7 @@ static void agent_run_func(
432461
" {\"tool\": \"tool_name\", \"args\": {\"param1\": \"value1\", \"param2\": 123}}\n"
433462
"2. Do NOT include explanations, reasoning, or any other text\n"
434463
"3. Do NOT use markdown code blocks or backticks\n"
435-
"4. ONLY use the exact parameter names shown in the tool signatures above\n"
464+
"4. Use the exact parameter names from the reference above\n"
436465
"5. Use proper JSON: keys in \"quotes\", boolean as true/false (lowercase), strings in \"quotes\"\n"
437466
"6. You can make MULTIPLE tool calls across iterations to gather detailed data\n"
438467
"7. Type DONE only when you have retrieved sufficient detailed information\n\n"

src/sqlite-agent.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
extern "C" {
2828
#endif
2929

30-
#define SQLITE_AGENT_VERSION "0.1.4"
30+
#define SQLITE_AGENT_VERSION "0.1.5"
3131

3232
/**
3333
* SQLite extension entry point

test/github.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ int main(void) {
196196

197197
const char *analysis_goal =
198198
"Use search_repositories tool with query 'user:sqliteai' and sort 'updated' to find the 2 most recently updated repositories. "
199-
"Then for each repository, use list_commits tool with owner 'sqliteai' and the repo name to get 5 recent commits. "
200-
"Insert into team_activity table with these exact fields: username (author.name or author.login), repository (repo name), "
201-
"activity_type (always 'commit'), title (commit.message), description (commit.message), "
202-
"timestamp (commit.author.date), url (commit.html_url). "
203-
"Parse all JSON responses carefully and extract real values, never insert template strings like {{variable}}.";
199+
"Then for each repository, use list_commits tool with owner 'sqliteai' and repo name to get 5 recent commits. "
200+
"Insert into team_activity table with these exact fields: username (commit author name), repository (repo name), "
201+
"activity_type (always 'commit'), title (commit message), description (commit message), "
202+
"timestamp (commit date), url (commit URL). "
203+
"Use exact parameter names as shown in tool descriptions. Extract real values from responses, never use template syntax.";
204204

205205
rc = sqlite3_prepare_v2(db, "SELECT agent_run(?, 'team_activity', ?)", -1, &stmt, 0);
206206
if (rc != SQLITE_OK) {

0 commit comments

Comments
 (0)