feat(ai): expose get_db_schema tool in global chat (#10207)

* feat(ai): expose get_db_schema tool in global chat

* fix(ai): skip cross-workspace editor cache write in global get_db_schema

* test(ai): add global eval case for get_db_schema resource lookup
This commit is contained in:
Guilhem
2026-07-20 17:32:59 +02:00
committed by GitHub
parent 542a4842a3
commit f4308cf033
3 changed files with 62 additions and 19 deletions
+28
View File
@@ -1533,3 +1533,31 @@
- saves the plan as a markdown artifact via create_artifact rather than only replying inline
- the artifact content has a title, a one-line summary, and three or four bullet steps for onboarding
- does not create a flow or script draft yet
- id: global-dbschema1-postgres-resource-tables
prompt: |-
I have a postgres resource at f/data/reports_pg in this workspace.
What tables does that database have?
initial: ai_evals/fixtures/frontend/global/initial/user_admin_empty.json
runtime:
maxTurns: 12
validate:
draftCountExactly: 0
toolExpect:
requiredToolsUsed:
- get_db_schema
forbiddenToolsUsed:
- write_script
- write_resource
- test_run_script
- deploy_workspace_item
toolCallArgs:
- tool: get_db_schema
field: resourcePath
stringIncludesAnyOf:
- f/data/reports_pg
skipJudge: true
judgeChecklist:
- fetches the schema through get_db_schema with the resource path f/data/reports_pg
- when the lookup fails, tells the user instead of inventing table names
- does not write scripts or resources to answer a read-only question
@@ -83,6 +83,7 @@ import {
type ToolDisplayAction
} from '../shared'
import { searchDocsTool, readDocsPageTool } from '../docs/core'
import { createDbSchemaTool } from '../script/core'
import type { ContextElement } from '../context'
import { getDatatableTools } from '../datatableTools'
import { fileTools } from '../files/fileTools'
@@ -969,6 +970,7 @@ Rules:
- Use discard_local_draft to remove a draft, including the matching open editor draft. Use delete_workspace_item only to delete a deployed workspace item.
- Variable values are never readable. For secrets, create a secret variable and reference it from resources as "$var:path/to/variable".
- Use search_resource_types before write_resource.
- Use get_db_schema with a database resource path to fetch its tables and columns before writing SQL (or a script querying that database).
- Use get_instructions before writing scripts, flows, resources, or apps. For scripts, pass the target language.
${pipelineBullet}
- After creating or editing a script or flow draft, run test_run_script, test_run_flow, or test_run_step with representative args before reporting that it works. These tools prefer drafts, so testing does not require deployment.
@@ -2789,6 +2791,11 @@ export const globalTools: Tool<{}>[] = [
)
}
},
createDbSchemaTool<{}>({
description:
'Fetch the schema (tables and columns) of a database resource by its path. Supports postgresql, mysql, ms_sql_server, snowflake and bigquery resources.',
updateEditorCache: false
}),
{
def: createToolDef(
readFlowModuleCodeSchema,
@@ -1,7 +1,6 @@
import { ResourceService, JobService } from '$lib/gen/services.gen'
import type { AIProvider, AIProviderModel, ResourceType, ScriptLang } from '$lib/gen/types.gen'
import { capitalize, isObject, toCamel } from '$lib/utils'
import { get } from 'svelte/store'
import { compile, phpCompile, pythonCompile } from '../../utils'
import type {
ChatCompletionSystemMessageParam,
@@ -460,10 +459,18 @@ export const resourceTypeTool: Tool<ScriptChatHelpers> = {
}
}
// Generic DB schema tool factory that can be used by both script and flow modes
export function createDbSchemaTool<T>(): Tool<T> {
// Generic DB schema tool factory shared by the script, flow and global modes
export function createDbSchemaTool<T>(
opts: { description?: string; updateEditorCache?: boolean } = {}
): Tool<T> {
const { description, updateEditorCache = true } = opts
return {
def: DB_SCHEMA_FUNCTION_DEF,
def: description
? {
...DB_SCHEMA_FUNCTION_DEF,
function: { ...DB_SCHEMA_FUNCTION_DEF.function, description }
}
: DB_SCHEMA_FUNCTION_DEF,
fn: async ({ args, workspace, toolCallbacks, toolId }) => {
if (!args.resourcePath) {
throw new Error('Database path not provided')
@@ -475,23 +482,24 @@ export function createDbSchemaTool<T>(): Tool<T> {
workspace: workspace,
path: args.resourcePath
})
const newDbSchemas = {
[args.resourcePath]: await getDbSchemas(
resource.resource_type,
args.resourcePath,
workspace,
(error) => {
console.error(error)
}
)
}
dbSchemas.update((schemas) => ({ ...schemas, ...newDbSchemas }))
const dbs = get(dbSchemas)
const db = dbs[args.resourcePath]
if (!db) {
const dbSchema = await getDbSchemas(
resource.resource_type,
args.resourcePath,
workspace,
(error) => {
console.error(error)
}
)
if (!dbSchema) {
throw new Error('Database not found')
}
const stringSchema = await formatDBSchema(db)
// The dbSchemas store is an editor cache keyed by resource path with no
// workspace dimension: a chat that may operate on a different workspace than
// the navigation one (global/session) must not write into it.
if (updateEditorCache) {
dbSchemas.update((schemas) => ({ ...schemas, [args.resourcePath]: dbSchema }))
}
const stringSchema = await formatDBSchema(dbSchema)
toolCallbacks.setToolStatus(toolId, {
content: 'Retrieved database schema for ' + args.resourcePath
})