feat(ai-chat): wire llms.txt docs lookup tools into global chat mode

Add list_docs_pages/read_docs_page to globalTools and a docs system-prompt section so the workspace assistant can answer product questions from windmill.dev docs and cite canonical URLs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
centdix
2026-06-15 12:41:09 +02:00
co-authored by Claude Opus 4.8
parent 2cbc854577
commit 9e456d053e
3 changed files with 52 additions and 0 deletions
+24
View File
@@ -870,3 +870,27 @@
judgeChecklist:
- fetches the logs for the requested job id
- explains the failure from the returned logs (connection refused to the upstream API)
- id: global-test29-docs-lookup-scheduling
prompt: |-
How do I schedule a script to run every Monday at 9am in Windmill?
runtime:
maxTurns: 6
validate:
draftCountExactly: 0
toolExpect:
requiredToolsUsed:
- list_docs_pages
- read_docs_page
forbiddenToolsUsed:
- deploy_workspace_item
- delete_workspace_item
- write_script
# Answering a product-docs question produces no draft, so the global judge
# (which only sees the drafts artifact) would score it empty — validate the
# docs-lookup contract via tool use: browse the index first, then read a page.
skipJudge: true
judgeChecklist:
- lists the documentation pages before reading one
- reads the scheduling documentation page rather than answering from memory
- cites the canonical windmill.dev/docs scheduling URL in the answer
@@ -2020,6 +2020,25 @@ describe('session-only preview tools gating', () => {
})
})
describe('documentation lookup tools', () => {
it('exposes list_docs_pages and read_docs_page in both the session and non-session tool sets', () => {
// The docs tools are read-only references, not session-preview tools, so
// they must be present regardless of `sessionPreview`.
for (const sessionPreview of [false, true]) {
const names = globalToolsFor({ sessionPreview }).map((t) => t.def.function.name)
expect(names).toContain('list_docs_pages')
expect(names).toContain('read_docs_page')
}
})
it('instructs the model to look up product docs and cite the Source page URL', () => {
const content = prepareGlobalSystemMessage().content as string
expect(content).toContain('list_docs_pages')
expect(content).toContain('read_docs_page')
expect(content).toContain('Source page')
})
})
describe('prepareGlobalUserMessage', () => {
it('injects the active editor reference without contents', () => {
__resetUserDraftForTesting()
@@ -74,6 +74,7 @@ import {
} from '../shared'
import type { ContextElement } from '../context'
import { getDatatableTools } from '../datatableTools'
import { listDocsPagesTool, readDocsPageTool } from '../docs/core'
import { UserDraft, type UserDraftMeta } from '$lib/userDraft.svelte'
import { emptySchema } from '$lib/utils'
import { inferArgs } from '$lib/infer'
@@ -639,6 +640,12 @@ Rules:
: ''
}
Documentation:
- To answer questions about Windmill product features, concepts, or syntax, look them up in the official docs with list_docs_pages and read_docs_page rather than relying on memory.
- Call list_docs_pages FIRST to see the full index of documentation pages with their titles, URLs and descriptions. Then call read_docs_page on the 1 to 3 most relevant pages. If read_docs_page returns a list of section headings instead of the full page, call it again with the same path and a \`section\` argument to read the relevant section.
- Base documentation answers ONLY on what you read. Do not invent features, flags, syntax, or behavior you did not see in the docs.
- When you cite a docs page, use the exact "Source page" URL printed at the top of each read_docs_page result — never reconstruct a URL from a link inside the page body. If the docs do not cover the question, say so rather than inventing an answer.
Flows:
- read_workspace_item returns compact flow JSON. Inline script bodies appear as "inline_script.<moduleId>".
- Use read_flow_module_code and set_flow_module_code for inline script bodies.
@@ -1469,6 +1476,8 @@ export const globalTools: Tool<{}>[] = [
}
},
createSearchHubScriptsTool(false),
listDocsPagesTool,
readDocsPageTool,
{
def: createToolDef(
askUserQuestionSchema,