Skip to content

Programmatic API

Use the SqlAgent facade to ask questions and receive structured responses:

use Knobik\SqlAgent\Facades\SqlAgent;
$response = SqlAgent::run('How many users registered last week?');
$response->answer; // "There are 42 users who registered last week."
$response->sql; // "SELECT COUNT(*) as count FROM users WHERE ..."
$response->results; // [['count' => 42]]
$response->toolCalls; // All tool calls made during execution
$response->iterations; // Detailed iteration data
$response->error; // Error message if failed, null otherwise
$response->usage; // Token usage data (see Token Usage Tracking below)
$response->isSuccess(); // true if no error occurred
$response->hasResults(); // true if results is not empty

For real-time output, use the stream method which returns a generator of chunks:

use Knobik\SqlAgent\Facades\SqlAgent;
foreach (SqlAgent::stream('Show me the top 5 customers') as $chunk) {
echo $chunk->content;
if ($chunk->isComplete()) {
// Stream finished
}
}

The stream method accepts the same parameters as run, plus conversation history:

SqlAgent::stream(
string $question,
?string $connection = null,
array $history = [],
): Generator

Query a specific database connection by passing it as the second argument:

$response = SqlAgent::run('How many orders today?', 'analytics');

For multi-turn conversations, pass previous messages as history:

$history = [
['role' => 'user', 'content' => 'Show me all products'],
['role' => 'assistant', 'content' => 'Here are the products...'],
];
foreach (SqlAgent::stream('Now filter by price > 100', null, $history) as $chunk) {
echo $chunk->content;
}

You may also resolve the agent via dependency injection using the Agent contract:

use Knobik\SqlAgent\Contracts\Agent;
class ReportController extends Controller
{
public function __construct(
private Agent $agent,
) {}
public function generate(Request $request)
{
$response = $this->agent->run($request->input('question'));
return [
'answer' => $response->answer,
'sql' => $response->sql,
'data' => $response->results,
];
}
}

Every response from the agent includes token usage data from the LLM provider. This is useful for monitoring costs, debugging prompt sizes, and observability.

The usage property on AgentResponse contains an array of token counts:

$response = SqlAgent::run('How many users are there?');
$response->usage;
// [
// 'prompt_tokens' => 1234,
// 'completion_tokens' => 567,
// 'cache_write_input_tokens' => null,
// 'cache_read_input_tokens' => null,
// 'thought_tokens' => null,
// ]
FieldDescription
prompt_tokensNumber of tokens in the input prompt
completion_tokensNumber of tokens generated by the LLM
cache_write_input_tokensTokens written to prompt cache (provider-dependent)
cache_read_input_tokensTokens read from prompt cache (provider-dependent)
thought_tokensTokens used for chain-of-thought reasoning (provider-dependent)

Cache and thought token fields are null when the provider does not support them.

When using the web interface or the SSE streaming endpoint, usage data is included in the done event:

{"event": "done", "data": {"queryCount": 2, "usage": {"prompt_tokens": 1234, "completion_tokens": 567, ...}}}

Usage data is automatically persisted in the message metadata column for every assistant response. You can access it via the usage accessor on the Message model:

$message = Message::find(1);
$message->usage; // ['prompt_tokens' => 1234, 'completion_tokens' => 567, ...]