mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-17 16:03:06 +00:00
feat: guide the AI when no resource type fits a service
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3f3b1c2c30
commit
bdb5d43425
@@ -11,6 +11,7 @@ import type {
|
||||
ListableResource,
|
||||
ListableVariable,
|
||||
Resource,
|
||||
ResourceType,
|
||||
Script
|
||||
} from '../../../frontend/src/lib/gen'
|
||||
import type {
|
||||
@@ -98,6 +99,51 @@ export interface BenchmarkWorkspaceResource {
|
||||
description?: string
|
||||
}
|
||||
|
||||
/** A resource type the instance holds. Only a seeded one has a schema to look up by name. */
|
||||
export interface BenchmarkWorkspaceResourceType {
|
||||
name: string
|
||||
schema?: unknown
|
||||
description?: string
|
||||
}
|
||||
|
||||
/** Names a hub-synced instance holds, for cases that seed no resource types. Their schemas are
|
||||
* not modelled, so a lookup by name misses them, as the similarity search does. */
|
||||
const SYNCED_RESOURCE_TYPE_NAMES = [
|
||||
'ai_instruction',
|
||||
'ai_skill',
|
||||
'airtable',
|
||||
'asana',
|
||||
'aws',
|
||||
'azure_blob',
|
||||
'clickup',
|
||||
'discord_webhook',
|
||||
'gcal',
|
||||
'gcp_service_account',
|
||||
'github',
|
||||
'gitlab',
|
||||
'gmail',
|
||||
'gsheets',
|
||||
'hubspot',
|
||||
'jira',
|
||||
'linear',
|
||||
'mailchimp',
|
||||
'mongodb',
|
||||
'mysql',
|
||||
'notion',
|
||||
'openai',
|
||||
'postgresql',
|
||||
's3',
|
||||
'salesforce',
|
||||
'sendgrid',
|
||||
'shopify',
|
||||
'slack',
|
||||
'smtp',
|
||||
'stripe',
|
||||
'supabase',
|
||||
'twilio',
|
||||
'zendesk'
|
||||
]
|
||||
|
||||
export interface BenchmarkWorkspaceJob {
|
||||
/** Stable id so a case prompt can reference a specific run (e.g. for get_run). */
|
||||
id?: string
|
||||
@@ -118,6 +164,8 @@ export interface BenchmarkWorkspaceRunnables {
|
||||
variables?: BenchmarkWorkspaceVariable[]
|
||||
aiProviders?: BenchmarkWorkspaceAiProvider[]
|
||||
resources?: BenchmarkWorkspaceResource[]
|
||||
/** Unset means an instance synced with the hub. */
|
||||
resourceTypes?: BenchmarkWorkspaceResourceType[]
|
||||
datatables?: BenchmarkDatatableSeed[]
|
||||
/** DuckLake catalog names, as `list_ducklakes` reports them. */
|
||||
ducklakes?: string[]
|
||||
@@ -328,6 +376,26 @@ export function listBenchmarkPlainResources(workspace: string): ListableResource
|
||||
}))
|
||||
}
|
||||
|
||||
/** Resource type names of a benchmark workspace, as `ResourceService.listResourceTypeNames`
|
||||
* returns them. Null when the workspace is not a benchmark one. */
|
||||
export function listBenchmarkResourceTypeNames(workspace: string): string[] | null {
|
||||
if (!benchmarkWorkspaces.has(workspace)) {
|
||||
return null
|
||||
}
|
||||
const seeded = benchmarkWorkspaceRunnables.get(workspace)?.resourceTypes
|
||||
return seeded ? seeded.map((rt) => rt.name) : SYNCED_RESOURCE_TYPE_NAMES
|
||||
}
|
||||
|
||||
/** A seeded resource type, as `ResourceService.getResourceType` returns it. */
|
||||
export function getBenchmarkResourceType(workspace: string, name: string): ResourceType | null {
|
||||
const seed = benchmarkWorkspaceRunnables
|
||||
.get(workspace)
|
||||
?.resourceTypes?.find((rt) => rt.name === name && rt.schema !== undefined)
|
||||
return seed
|
||||
? { workspace_id: 'admins', name: seed.name, schema: seed.schema, description: seed.description }
|
||||
: null
|
||||
}
|
||||
|
||||
/** A seeded resource with its value, as `ResourceService.getResource` returns it. Covers both
|
||||
* seed kinds, so it agrees with `existsResource` and `listResource` — both of those report AI
|
||||
* providers too, and a case that lists resources and then reads one by path would otherwise get
|
||||
|
||||
@@ -104,8 +104,10 @@ vi.mock('$lib/gen', async () => {
|
||||
getBenchmarkVariableByPath,
|
||||
hasBenchmarkWorkspace,
|
||||
getBenchmarkResource,
|
||||
getBenchmarkResourceType,
|
||||
listBenchmarkAiProviderResources,
|
||||
listBenchmarkPlainResources,
|
||||
listBenchmarkResourceTypeNames,
|
||||
listBenchmarkApps,
|
||||
listBenchmarkDatatables,
|
||||
listBenchmarkDataMetrics,
|
||||
@@ -463,7 +465,20 @@ vi.mock('$lib/gen', async () => {
|
||||
return value
|
||||
},
|
||||
queryResourceTypes: async (data: { workspace: string }) =>
|
||||
hasBenchmarkWorkspace(data.workspace) ? [] : actual.ResourceService.queryResourceTypes(data)
|
||||
hasBenchmarkWorkspace(data.workspace) ? [] : actual.ResourceService.queryResourceTypes(data),
|
||||
listResourceTypeNames: async (data: { workspace: string }) =>
|
||||
listBenchmarkResourceTypeNames(data.workspace) ??
|
||||
actual.ResourceService.listResourceTypeNames(data),
|
||||
getResourceType: async (data: { workspace: string; path: string }) => {
|
||||
if (!hasBenchmarkWorkspace(data.workspace)) {
|
||||
return actual.ResourceService.getResourceType(data)
|
||||
}
|
||||
const resourceType = getBenchmarkResourceType(data.workspace, data.path)
|
||||
if (!resourceType) {
|
||||
throw new Error(`Resource type "${data.path}" not found in benchmark workspace`)
|
||||
}
|
||||
return resourceType
|
||||
}
|
||||
}),
|
||||
VariableService: wrapService(actual.VariableService, {
|
||||
existsVariable: async (data: { workspace: string; path: string }) =>
|
||||
|
||||
@@ -759,6 +759,58 @@
|
||||
- keeps both drafts under a sensible eval/global Slack-related path
|
||||
- does not create schedules, triggers, or deployed workspace changes
|
||||
|
||||
# The instance never synced the hub's resource types, so the one Confluence takes is missing:
|
||||
# the script's connection picker stays empty until a superadmin syncs, which only the
|
||||
# assistant's reply can tell the user.
|
||||
- id: global-resource-type-hub-not-synced
|
||||
prompt: |-
|
||||
Write a script that creates a page in our Confluence space from a space key, a title and the page body.
|
||||
initial: ai_evals/fixtures/frontend/global/initial/resource_types_not_synced.json
|
||||
runtime:
|
||||
maxTurns: 10
|
||||
validate:
|
||||
requiredDrafts:
|
||||
- type: script
|
||||
valueExcludes:
|
||||
- getVariable
|
||||
- get_variable
|
||||
toolExpect:
|
||||
forbiddenToolsUsed:
|
||||
- write_variable
|
||||
- deploy_workspace_item
|
||||
assistantExpect:
|
||||
requiredMentionsAnyOf:
|
||||
- - sync
|
||||
judgeChecklist:
|
||||
- the script takes the Confluence connection as one resource-typed parameter rather than separate string credentials or a variable read inside the code
|
||||
- the script creates a Confluence page from a space key, a title and a body
|
||||
|
||||
# An in-house API has no hub resource type, so its connection needs a type of the workspace's
|
||||
# own: a token parameter or a variable read inside the code is the fallback the guidance rules out.
|
||||
- id: global-resource-type-custom-api
|
||||
prompt: |-
|
||||
Write a script that fetches an invoice by id from our internal billing API at https://billing.acme.internal/api/v1. It authenticates with a bearer token.
|
||||
runtime:
|
||||
maxTurns: 10
|
||||
userAnswers:
|
||||
- Yes, use a resource type
|
||||
validate:
|
||||
requiredDrafts:
|
||||
- type: script
|
||||
valueExcludes:
|
||||
- getVariable
|
||||
- get_variable
|
||||
toolExpect:
|
||||
forbiddenToolsUsed:
|
||||
- write_variable
|
||||
- deploy_workspace_item
|
||||
assistantExpect:
|
||||
requiredMentionsAnyOf:
|
||||
- - resource type
|
||||
judgeChecklist:
|
||||
- the script takes the billing API's base URL and token together as one resource-typed parameter, not a plain string token or a variable read inside the code
|
||||
- the script fetches an invoice by id with a bearer token
|
||||
|
||||
- id: global-test19-datatable-not-configured-asks-to-set-up
|
||||
prompt: |-
|
||||
Here are two newsletter signups: alice@example.com and bob@example.com.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"workspace": {
|
||||
"resourceTypes": [{ "name": "ai_skill" }, { "name": "ai_instruction" }]
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,19 @@ async function push(opts: PushOptions, filePath: string, name: string) {
|
||||
log.info(colors.bold.underline.green("Resource pushed"));
|
||||
}
|
||||
|
||||
// The hub publishes hundreds of resource types and an instance seeds only a few of its own,
|
||||
// so fewer than this means the instance never synced with the hub.
|
||||
const UNSYNCED_RESOURCE_TYPE_COUNT = 20;
|
||||
|
||||
function warnIfNotSyncedWithHub(resourceTypes: ResourceType[]) {
|
||||
const count = new Set(resourceTypes.map((rt) => rt.name)).size;
|
||||
if (count < UNSYNCED_RESOURCE_TYPE_COUNT) {
|
||||
log.warnAlways(
|
||||
`Only ${count} resource types exist on this instance, so it has most likely never synced with the Windmill Hub, which has types for most services. A superadmin can sync resource types from the hub with "Sync resource types with Hub" in the Add resource dialog of the Resources page, or by running the u/admin/hub_sync script in the admins workspace.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function list(opts: GlobalOptions & { schema?: boolean; json?: boolean }) {
|
||||
if (opts.json) log.setSilent(true);
|
||||
const workspace = await resolveWorkspace(opts);
|
||||
@@ -99,12 +112,9 @@ async function list(opts: GlobalOptions & { schema?: boolean; json?: boolean })
|
||||
workspace: workspace.workspaceId,
|
||||
});
|
||||
|
||||
warnIfNotSyncedWithHub(res);
|
||||
if (opts.json) {
|
||||
console.log(JSON.stringify(res));
|
||||
} else if (res.length === 0) {
|
||||
log.info("No custom resource types found in this workspace.");
|
||||
log.info("Built-in types like 'postgresql', 'slack', 'mysql', etc. are available from the Windmill Hub.");
|
||||
return;
|
||||
} else if (opts.schema) {
|
||||
new Table()
|
||||
.header(["Workspace", "Name", "Schema"])
|
||||
@@ -172,6 +182,7 @@ export async function generateRTNamespace(opts: GlobalOptions) {
|
||||
const rts = await wmill.listResourceType({
|
||||
workspace: workspace.workspaceId,
|
||||
});
|
||||
warnIfNotSyncedWithHub(rts);
|
||||
|
||||
let namespaceContent = "declare namespace RT {\n";
|
||||
namespaceContent += rts
|
||||
|
||||
Generated
+28
@@ -95,6 +95,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -259,6 +260,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -383,6 +385,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -500,6 +503,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -1323,6 +1327,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -2158,6 +2163,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -2274,6 +2280,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3099,6 +3106,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3249,6 +3257,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3382,6 +3391,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3502,6 +3512,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3615,6 +3626,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3731,6 +3743,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3848,6 +3861,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -3980,6 +3994,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -4095,6 +4110,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -4225,6 +4241,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -5234,6 +5251,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -5394,6 +5412,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -5544,6 +5563,7 @@ Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -7178,6 +7198,14 @@ The prefix must be on the string itself.
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## When No Resource Type Fits
|
||||
|
||||
The Windmill Hub publishes resource types for most services, and an instance gets them by syncing with the hub. When none fits the service:
|
||||
|
||||
- If looking up resource types reports that the instance is missing the hub's types, tell the user so that a superadmin syncs, and don't create a type for the service meanwhile: the hub most likely has one, and after the sync the workspace would hold two.
|
||||
- Otherwise propose a resource type holding the service's connection fields (base URL, account or region identifiers, credentials), as in "Custom Resource Types" below, and ask the user before creating it: every resource of that type and every script taking one depends on its fields.
|
||||
- Use a plain variable instead of a resource only when the user prefers it.
|
||||
|
||||
## Custom Resource Types
|
||||
|
||||
Create custom resource types with JSON Schema:
|
||||
|
||||
@@ -139,10 +139,7 @@ describe("resource-type commands", () => {
|
||||
);
|
||||
|
||||
expect(result.code).toEqual(0);
|
||||
// When empty, shows helpful message; when populated, shows table with Name header
|
||||
const hasTable = result.stdout.includes("Name");
|
||||
const hasEmptyMessage = result.stdout.includes("No custom resource types");
|
||||
expect(hasTable || hasEmptyMessage).toBe(true);
|
||||
expect(result.stdout).toContain("Name");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ import {
|
||||
createInlineScriptSession,
|
||||
findUnresolvedInlineScriptRefs
|
||||
} from '../flow/inlineScriptsUtils'
|
||||
import { searchNpmPackagesTool } from '../script/core'
|
||||
import { searchNpmPackagesTool, searchResourceTypes } from '../script/core'
|
||||
import type { McpServer } from './mcpTools'
|
||||
import { logFeatureUsage } from '$lib/utils/featureUsage'
|
||||
import { isSkillEnabled } from '../skills/enabledSkills'
|
||||
@@ -4283,19 +4283,16 @@ export const globalTools: SessionTool<{}>[] = [
|
||||
toolCallbacks.setToolStatus(toolId, {
|
||||
content: `Searching resource types for "${parsed.query}"...`
|
||||
})
|
||||
const results = await ResourceService.queryResourceTypes({
|
||||
const { resourceTypes, hubSyncNote } = await searchResourceTypes(
|
||||
parsed.query,
|
||||
workspace,
|
||||
text: parsed.query,
|
||||
limit: parsed.limit ?? 5
|
||||
})
|
||||
parsed.limit ?? 5
|
||||
)
|
||||
toolCallbacks.setToolStatus(toolId, {
|
||||
content: `Found ${results.length} resource type(s) for "${parsed.query}"`
|
||||
content: `Found ${resourceTypes.length} resource type(s) for "${parsed.query}"`
|
||||
})
|
||||
return JSON.stringify(
|
||||
results.map((rt) => ({
|
||||
name: rt.name,
|
||||
schema: rt.schema
|
||||
})),
|
||||
hubSyncNote ? { resource_types: resourceTypes, note: hubSyncNote } : resourceTypes,
|
||||
null,
|
||||
2
|
||||
)
|
||||
|
||||
@@ -14,7 +14,40 @@ vi.mock('@codingame/monaco-vscode-standalone-typescript-language-features', () =
|
||||
vi.mock('@codingame/monaco-vscode-languages-service-override', () => ({ default: () => ({}) }))
|
||||
vi.mock('$lib/components/vscode', () => ({}))
|
||||
|
||||
import { editCodeToolWithDiff } from './core'
|
||||
import { ResourceService } from '$lib/gen'
|
||||
import { editCodeToolWithDiff, searchResourceTypes } from './core'
|
||||
|
||||
describe('searchResourceTypes', () => {
|
||||
const syncedNames = Array.from({ length: 30 }, (_, i) => `type_${i}`)
|
||||
|
||||
// The similarity index trails the table by up to a day, and builds without embeddings
|
||||
// have none, so a type the query names must still be found.
|
||||
it('finds a type the query names when the similarity search misses it', async () => {
|
||||
vi.spyOn(ResourceService, 'queryResourceTypes').mockResolvedValue([])
|
||||
vi.spyOn(ResourceService, 'listResourceTypeNames').mockResolvedValue([...syncedNames, 'stripe'])
|
||||
vi.spyOn(ResourceService, 'getResourceType').mockResolvedValue({
|
||||
name: 'stripe',
|
||||
schema: { type: 'object' }
|
||||
})
|
||||
|
||||
const { resourceTypes, hubSyncNote } = await searchResourceTypes('Stripe payments', 'ws', 5)
|
||||
|
||||
expect(resourceTypes.map((rt) => rt.name)).toEqual(['stripe'])
|
||||
expect(hubSyncNote).toBeUndefined()
|
||||
})
|
||||
|
||||
it('notes an instance that never synced with the hub', async () => {
|
||||
vi.spyOn(ResourceService, 'queryResourceTypes').mockResolvedValue([])
|
||||
vi.spyOn(ResourceService, 'listResourceTypeNames').mockResolvedValue([
|
||||
'ai_skill',
|
||||
'ai_instruction'
|
||||
])
|
||||
|
||||
const { hubSyncNote } = await searchResourceTypes('stripe', 'ws', 5)
|
||||
|
||||
expect(hubSyncNote).toContain('never synced')
|
||||
})
|
||||
})
|
||||
|
||||
describe('editCodeToolWithDiff', () => {
|
||||
it('records the complete script diff after applying replacements', async () => {
|
||||
|
||||
@@ -19,7 +19,8 @@ import {
|
||||
type ScriptLintResult,
|
||||
formatScriptLintResult,
|
||||
createSearchWorkspaceTool,
|
||||
createGetRunnableDetailsTool
|
||||
createGetRunnableDetailsTool,
|
||||
HUB_SYNC_INSTRUCTIONS
|
||||
} from '../shared'
|
||||
import { createWorkspaceMutationTools } from '../workspaceTools'
|
||||
import { setupTypeAcquisition, type DepsToGet } from '$lib/ata'
|
||||
@@ -41,7 +42,7 @@ const TYPES_CONTEXT_PERCENTAGE = 1
|
||||
export const DIFF_BASED_EDIT_PROVIDERS: AIProvider[] = []
|
||||
|
||||
export function formatResourceTypes(
|
||||
allResourceTypes: ResourceType[],
|
||||
allResourceTypes: Pick<ResourceType, 'name' | 'schema'>[],
|
||||
lang: 'python3' | 'php' | 'bun' | 'deno' | 'nativets' | 'bunnative'
|
||||
) {
|
||||
if (lang === 'python3') {
|
||||
@@ -67,14 +68,52 @@ export function formatResourceTypes(
|
||||
}
|
||||
}
|
||||
|
||||
async function getResourceTypes(prompt: string, workspace: string) {
|
||||
const resourceTypes = await ResourceService.queryResourceTypes({
|
||||
workspace: workspace,
|
||||
text: prompt,
|
||||
limit: 5
|
||||
})
|
||||
// The hub publishes hundreds of resource types and an instance seeds only a few of its own,
|
||||
// so fewer than this means the instance never synced with the hub.
|
||||
const UNSYNCED_RESOURCE_TYPE_COUNT = 20
|
||||
|
||||
return resourceTypes
|
||||
/**
|
||||
* Similarity matches, led by any resource type the query names exactly: the similarity index
|
||||
* is rebuilt from the table once a day, and builds without embeddings have no index at all.
|
||||
*/
|
||||
export async function searchResourceTypes(
|
||||
query: string,
|
||||
workspace: string,
|
||||
limit: number
|
||||
): Promise<{ resourceTypes: Pick<ResourceType, 'name' | 'schema'>[]; hubSyncNote?: string }> {
|
||||
const [similar, names] = await Promise.all([
|
||||
ResourceService.queryResourceTypes({ workspace, text: query, limit }).catch(() => []),
|
||||
ResourceService.listResourceTypeNames({ workspace })
|
||||
.then((listed) => new Set(listed))
|
||||
.catch(() => undefined)
|
||||
])
|
||||
|
||||
const normalized = query.trim().toLowerCase()
|
||||
const candidates = new Set([
|
||||
normalized.replace(/[\s-]+/g, '_'),
|
||||
...normalized.split(/[^a-z0-9_]+/)
|
||||
])
|
||||
const exactNames = [...candidates].filter(
|
||||
(name) => names?.has(name) && !similar.some((rt) => rt.name === name)
|
||||
)
|
||||
const exact = await Promise.all(
|
||||
exactNames
|
||||
.slice(0, limit)
|
||||
.map((name) =>
|
||||
ResourceService.getResourceType({ workspace, path: name }).catch(() => undefined)
|
||||
)
|
||||
)
|
||||
const resourceTypes = [
|
||||
...exact.flatMap((rt) => (rt ? [{ name: rt.name, schema: rt.schema }] : [])),
|
||||
...similar
|
||||
].slice(0, limit)
|
||||
|
||||
const hubSyncNote =
|
||||
names && names.size < UNSYNCED_RESOURCE_TYPE_COUNT
|
||||
? `Only ${names.size} resource types exist on this instance, so it has most likely never synced with the Windmill Hub, which has types for most services. ${HUB_SYNC_INSTRUCTIONS}`
|
||||
: undefined
|
||||
|
||||
return { resourceTypes, hubSyncNote }
|
||||
}
|
||||
|
||||
export const SUPPORTED_CHAT_SCRIPT_LANGUAGES = [
|
||||
@@ -149,13 +188,14 @@ export async function getFormattedResourceTypes(
|
||||
case 'bunnative':
|
||||
case 'python3':
|
||||
case 'php': {
|
||||
const resourceTypes = await getResourceTypes(prompt, workspace)
|
||||
const { resourceTypes, hubSyncNote } = await searchResourceTypes(prompt, workspace, 5)
|
||||
|
||||
const intro = `RESOURCE_TYPES:\n`
|
||||
const found =
|
||||
resourceTypes.length > 0
|
||||
? `RESOURCE_TYPES:\n${formatResourceTypes(resourceTypes, lang)}`
|
||||
: `No resource type matches "${prompt}".`
|
||||
|
||||
const resourceTypesText = formatResourceTypes(resourceTypes, lang)
|
||||
|
||||
return intro + resourceTypesText
|
||||
return hubSyncNote ? `${found}\n\n${hubSyncNote}` : found
|
||||
}
|
||||
default:
|
||||
return ''
|
||||
|
||||
@@ -57,7 +57,8 @@ vi.mock('$lib/gen', () => ({
|
||||
EmailTriggerService: { createEmailTrigger: vi.fn() },
|
||||
SettingService: { getGlobal: vi.fn() },
|
||||
ResourceService: {
|
||||
getResourceValue: vi.fn(async ({ path }: { path: string }) => ({ content: `body of ${path}` }))
|
||||
getResourceValue: vi.fn(async ({ path }: { path: string }) => ({ content: `body of ${path}` })),
|
||||
listResourceTypeNames: vi.fn(async () => ['confluence'])
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -2270,6 +2271,29 @@ describe('getHubIntegrationTool', () => {
|
||||
expect(!!parsed.scripts_note).toBe(expected)
|
||||
})
|
||||
|
||||
// Without the note the model writes against a type the instance lacks, and the
|
||||
// script's resource picker stays empty until someone syncs.
|
||||
it.each([
|
||||
[['confluence'], false],
|
||||
[['ai_skill'], true]
|
||||
])('flags hub resource types the instance lacks (%s)', async (present, flagged) => {
|
||||
const { IntegrationService, ResourceService } = await import('$lib/gen')
|
||||
Object.assign(IntegrationService, { getHubIntegrationMeta: vi.fn(async () => doc) })
|
||||
vi.mocked(ResourceService.listResourceTypeNames).mockResolvedValueOnce(present)
|
||||
|
||||
const { getHubIntegrationTool } = await import('./shared')
|
||||
const parsed = JSON.parse(
|
||||
await getHubIntegrationTool.fn({
|
||||
args: { integration: 'confluence' },
|
||||
workspace: 'ws',
|
||||
toolId: 't1',
|
||||
toolCallbacks: { setToolStatus: vi.fn() }
|
||||
} as any)
|
||||
)
|
||||
|
||||
expect(parsed.resource_types_note?.includes('confluence') ?? false).toBe(flagged)
|
||||
})
|
||||
|
||||
// A hub that times out has said nothing about whether the integration exists, and
|
||||
// reporting it as absent would stick for the rest of the conversation.
|
||||
it('does not report a transient hub failure as a missing integration', async () => {
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
FlowService,
|
||||
IntegrationService,
|
||||
JobService,
|
||||
ResourceService,
|
||||
type Job,
|
||||
type CompletedJob,
|
||||
type FlowValue,
|
||||
@@ -1710,12 +1711,31 @@ function parseResourceTypeSchema(schema: unknown): unknown {
|
||||
}
|
||||
}
|
||||
|
||||
export const HUB_SYNC_INSTRUCTIONS =
|
||||
'A superadmin can sync resource types from the hub with "Sync resource types with Hub" in the Add resource dialog of the Resources page, or by running the u/admin/hub_sync script in the admins workspace.'
|
||||
|
||||
async function missingResourceTypesNote(
|
||||
workspace: string,
|
||||
names: string[]
|
||||
): Promise<string | undefined> {
|
||||
if (names.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
const present = await ResourceService.listResourceTypeNames({ workspace })
|
||||
.then((listed) => new Set(listed))
|
||||
.catch(() => undefined)
|
||||
const missing = present ? names.filter((name) => !present.has(name)) : []
|
||||
return missing.length > 0
|
||||
? `This instance does not have the ${missing.join(', ')} resource type${missing.length > 1 ? 's' : ''} yet. ${HUB_SYNC_INSTRUCTIONS}`
|
||||
: undefined
|
||||
}
|
||||
|
||||
export const getHubIntegrationTool = {
|
||||
requires: NONE,
|
||||
def: getHubIntegrationToolDef,
|
||||
// Reads one hub document over a GET and writes nothing, so planning may use it.
|
||||
planModeSafe: true,
|
||||
fn: async ({ args, toolId, toolCallbacks }) => {
|
||||
fn: async ({ args, workspace, toolId, toolCallbacks }) => {
|
||||
const { integration } = getHubIntegrationSchema.parse(args)
|
||||
toolCallbacks.setToolStatus(toolId, { content: `Reading the ${integration} integration...` })
|
||||
|
||||
@@ -1745,6 +1765,10 @@ export const getHubIntegrationTool = {
|
||||
// every section is read as optional: a hub that sends less should return less,
|
||||
// not fail the call.
|
||||
const derived = doc.derived
|
||||
const resourceTypesNote = await missingResourceTypesNote(
|
||||
workspace,
|
||||
(doc.resource_types ?? []).map((rt) => rt.name)
|
||||
)
|
||||
return JSON.stringify({
|
||||
integration: doc.app,
|
||||
display_name: doc.display_name,
|
||||
@@ -1778,6 +1802,7 @@ export const getHubIntegrationTool = {
|
||||
...(rt.description ? { description: rt.description } : {}),
|
||||
schema: parseResourceTypeSchema(rt.schema)
|
||||
})),
|
||||
...(resourceTypesNote ? { resource_types_note: resourceTypesNote } : {}),
|
||||
example_scripts: (derived?.top_scripts ?? []).slice(0, MAX_INTEGRATION_EXAMPLES).map((s) => ({
|
||||
path: s.path,
|
||||
summary: s.summary,
|
||||
|
||||
@@ -5,6 +5,7 @@ export const SCRIPT_BASE = `# Windmill Script Writing Guide
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it \`main\` (\`Main\` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no \`main\`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (\`wmill\`), use it to interact with the platform
|
||||
@@ -827,6 +828,15 @@ The prefix must be on the string itself.
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## When No Resource Type Fits
|
||||
|
||||
The Windmill Hub publishes resource types for most services, and an instance gets them by syncing with the hub. When none fits the service:
|
||||
|
||||
- If looking up resource types reports that the instance is missing the hub's types, tell the user so that a superadmin syncs, and don't create a type for the service meanwhile: the hub most likely has one, and after the sync the workspace would hold two.
|
||||
- Otherwise propose a resource type holding the service's connection fields (base URL, account or region identifiers, credentials), as in "Custom Resource Types" below, and ask the user before creating it: every resource of that type and every script taking one depends on its fields.
|
||||
- You cannot create a resource type yourself: give the user the schema to add with **Add resource type** on the Resources page.
|
||||
- Use a plain variable instead of a resource only when the user prefers it.
|
||||
|
||||
## Custom Resource Types
|
||||
|
||||
Create custom resource types with JSON Schema:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -214,6 +214,14 @@ The prefix must be on the string itself.
|
||||
}
|
||||
```
|
||||
|
||||
## When No Resource Type Fits
|
||||
|
||||
The Windmill Hub publishes resource types for most services, and an instance gets them by syncing with the hub. When none fits the service:
|
||||
|
||||
- If looking up resource types reports that the instance is missing the hub's types, tell the user so that a superadmin syncs, and don't create a type for the service meanwhile: the hub most likely has one, and after the sync the workspace would hold two.
|
||||
- Otherwise propose a resource type holding the service's connection fields (base URL, account or region identifiers, credentials), as in "Custom Resource Types" below, and ask the user before creating it: every resource of that type and every script taking one depends on its fields.
|
||||
- Use a plain variable instead of a resource only when the user prefers it.
|
||||
|
||||
## Custom Resource Types
|
||||
|
||||
Create custom resource types with JSON Schema:
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -53,6 +53,7 @@ Use `wmill resource-type list --schema` to discover available resource types.
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
@@ -213,6 +213,17 @@ The prefix must be on the string itself.
|
||||
}
|
||||
```
|
||||
|
||||
## When No Resource Type Fits
|
||||
|
||||
The Windmill Hub publishes resource types for most services, and an instance gets them by syncing with the hub. When none fits the service:
|
||||
|
||||
- If looking up resource types reports that the instance is missing the hub's types, tell the user so that a superadmin syncs, and don't create a type for the service meanwhile: the hub most likely has one, and after the sync the workspace would hold two.
|
||||
- Otherwise propose a resource type holding the service's connection fields (base URL, account or region identifiers, credentials), as in "Custom Resource Types" below, and ask the user before creating it: every resource of that type and every script taking one depends on its fields.
|
||||
<!-- chat-only -->
|
||||
- You cannot create a resource type yourself: give the user the schema to add with **Add resource type** on the Resources page.
|
||||
<!-- /chat-only -->
|
||||
- Use a plain variable instead of a resource only when the user prefers it.
|
||||
|
||||
## Custom Resource Types
|
||||
|
||||
Create custom resource types with JSON Schema:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
## General Principles
|
||||
|
||||
- A script's inputs are its parameters. Credentials and configuration come in as resource-typed parameters, never hard-coded or read from the environment; the language section below shows how that language declares parameters
|
||||
- When no resource type exists for a service, don't fall back to a plain string parameter or a variable read inside the code. If looking up resource types reports that the instance is missing the Windmill Hub's types, tell the user so that a superadmin syncs: the hub has types for most services. Otherwise propose a resource type holding the service's connection fields and ask before creating it. Use a variable only if the user prefers one: a resource keeps a connection's fields together, lets whoever runs the script pick an existing connection, and keeps the secret out of the arguments a run records
|
||||
- Libraries are installed automatically - do not show installation instructions
|
||||
- In a language with an entrypoint function (TypeScript, Python, Go, Rust, PHP, R, …), name it `main` (`Main` in C#) and do not call it; in TypeScript it must be async. SQL, GraphQL, Bash, PowerShell and Ansible scripts have no `main`: their language section shows how they take arguments
|
||||
- Where the language has a Windmill client (`wmill`), use it to interact with the platform
|
||||
|
||||
Reference in New Issue
Block a user