mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
* feat(ai-chat): make reusable skills ai_skill resources you select per workspace * chore: pin the ee ref to the skill telemetry counters * fix: address review findings on skill authoring, import and migration * fix: enforce skill selection in read_skill and stop imports clobbering resources * feat: carry format_extension from the hub into synced resource types * fix: let an edit set or clear a resource type's format_extension * fix: regenerate the sqlx cache and close the review round findings * fix: close the round-2 findings on folder ACLs, cached sync and truncation * refactor: make the skills migration non-destructive and use design-system inputs * fix: close the round-4 findings on folder owners, startup sync and truncation * fix: clear obsolete extensions, guard folder owners, and report skipped skills * fix: honor explicit-null extensions and report same-type migration conflicts * fix: scope skill actions to the committed workspace and paginate the listing * fix: keep the drawer scoped to the live workspace and surface truncation * fix: discard a skills refresh for a workspace the chat has left * chore: update ee-repo-ref to 6efe7a73c745c2e1377a34498523c00d89010a3d This commit updates the EE repository reference after PR #764 was merged in windmill-ee-private. Previous ee-repo-ref: 55998c142bc72edd08532748af1974b16035658d New ee-repo-ref: 6efe7a73c745c2e1377a34498523c00d89010a3d Automated by sync-ee-ref workflow. --------- Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import { get } from 'svelte/store'
|
|
import { userStore } from '$lib/stores'
|
|
|
|
/**
|
|
* A set of workspace-object paths the chat may act through, remembered per
|
|
* workspace and per account.
|
|
*
|
|
* Being able to read a resource is not the same as wanting the chat to use it: a
|
|
* resource in a shared folder is readable by a whole team, and each enabled entry
|
|
* costs something on every turn — an MCP server puts its tool descriptions in the
|
|
* model's context and reaches an external system, a skill puts its description
|
|
* there. So an entry is off until it is turned on.
|
|
*
|
|
* Stored per browser, like the chat's other per-user preferences, but keyed by
|
|
* email as well as workspace: browser storage outlives a logout, and inheriting
|
|
* the previous account's selection would hand the next person capabilities they
|
|
* never turned on. Workspace ids cannot contain `:`, so the composite key is
|
|
* unambiguous.
|
|
*/
|
|
export type EnabledPathsPreference = {
|
|
enabledPaths: (workspace: string) => string[]
|
|
isEnabled: (workspace: string, path: string) => boolean
|
|
/** Returns false when there is no account to record the preference against, so
|
|
* a caller that just created the object can say it did not stay on. */
|
|
setEnabled: (workspace: string, path: string, enabled: boolean) => boolean
|
|
}
|
|
|
|
export function createEnabledPathsPreference(storageKey: string): EnabledPathsPreference {
|
|
function scope(workspace: string): string | undefined {
|
|
const email = get(userStore)?.email
|
|
return email ? `${workspace}:${email}` : undefined
|
|
}
|
|
|
|
function read(): Record<string, string[]> {
|
|
if (typeof localStorage === 'undefined') return {}
|
|
try {
|
|
return JSON.parse(localStorage.getItem(storageKey) ?? '{}')
|
|
} catch {
|
|
return {}
|
|
}
|
|
}
|
|
|
|
function write(all: Record<string, string[]>) {
|
|
try {
|
|
localStorage.setItem(storageKey, JSON.stringify(all))
|
|
} catch (e) {
|
|
console.error(`Failed to persist ${storageKey}`, e)
|
|
}
|
|
}
|
|
|
|
function enabledPaths(workspace: string): string[] {
|
|
const key = scope(workspace)
|
|
return key ? (read()[key] ?? []) : []
|
|
}
|
|
|
|
return {
|
|
enabledPaths,
|
|
isEnabled: (workspace, path) => enabledPaths(workspace).includes(path),
|
|
setEnabled: (workspace, path, enabled) => {
|
|
const key = scope(workspace)
|
|
if (!key) return false
|
|
const all = read()
|
|
const current = new Set(all[key] ?? [])
|
|
if (enabled) {
|
|
current.add(path)
|
|
} else {
|
|
current.delete(path)
|
|
}
|
|
all[key] = [...current]
|
|
write(all)
|
|
return true
|
|
}
|
|
}
|
|
}
|