hi @orimdominic
In your index.js you wrote:
const agent = createAgent({
model: chatModel,
tool: [executeSql],
});
The correct parameter name is tools (plural):
const agent = createAgent({
model: chatModel,
tools: [executeSql],
});
Source: createAgent type definition - CreateAgentParams.tools:
tools?: (ServerTool | ClientTool)[];
Even after fixing the tools typo, the tool would crash with a ReferenceError. Here’s why:
Your executeSql tool is defined at the module level and references db:
// Module level
const executeSql = tool(
async ({ query }) => {
// ...
const result = await db.run(q); // <-- what `db`?
},
// ...
);
But db is only created inside the post() function:
async function post(req, res) {
// ...
const db = await SqlDatabase.fromDataSourceParams({ appDataSource: datasource });
// `db` is local to post() -- executeSql can't see it
}
The tutorial solves this with a module-level singleton pattern (see tutorial code):
let db;
async function getDb() {
if (!db) {
const datasource = new DataSource({ type: "sqlite", database: "./companies.db" });
db = await SqlDatabase.fromDataSourceParams({ appDataSource: datasource });
}
return db;
}
Then the tool references the module-level db (or calls getDb()):
const executeSql = tool(
async ({ query }) => {
const q = sanitizeSqlQuery(query);
const database = await getDb();
const result = await database.run(q);
return typeof result === "string" ? result : JSON.stringify(result, null, 2);
},
// ...
);
Bonus: use the systemPrompt parameter
The tutorial passes the system prompt as a parameter to createAgent, not via the messages array:
const agent = createAgent({
model: chatModel,
tools: [executeSql],
systemPrompt: getSystemPrompt,
});
Your current approach of injecting a SystemMessage into the messages array works, but using the dedicated systemPrompt parameter is cleaner and ensures the system prompt is handled optimally by the framework (e.g., with Anthropic’s cache control support).
Source: CreateAgentParams.systemPrompt