Files
windmill/frontend/src/lib/components/copilot/loadCopilot.ts
T
Ruben FiszelandClaude Opus 5 8c65511e81 fix: raw app new-app modal ignores instance-level AI settings (#10619)
* fix: stop the new raw app modal claiming AI is unconfigured before it knows

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: require a resolved workspace before trusting the loaded AI config

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: drop the unreachable token guard and point superadmins at instance settings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: show the instance settings link to superadmins who are not workspace admins

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 20:39:38 +02:00

49 lines
1.9 KiB
TypeScript

import { WorkspaceService } from '$lib/gen'
import { copilotWorkspace, setCopilotInfo } from '$lib/aiStore'
import { workspaceAIClients } from './lib'
// Lives here, not in $lib/aiStore, purely so that module needs no import of the AI
// client — it is the one thing that wanted both. Moving it back recreates the
// aiStore -> copilot/lib -> copilot/chat/shared -> aiStore cycle.
// copilotInfo/copilotSessionModel are global, so concurrent loads (e.g. a fast
// session switch between workspaces) race: an earlier call resolving last would
// clobber the active workspace's config. Apply only the most recent call's
// result via a monotonic token — last invocation wins regardless of resolution
// order. init() is synchronous so its ordering already matches.
let loadCopilotToken = 0
// Consumers load the config for the workspace they operate on rather than trusting an
// ancestor to have done it, and they mount together — so share the in-flight request
// instead of firing one GET each. Only ever hold the newest request here: an older one
// has lost the token, so handing it back would leave its workspace never applied.
let inFlight: { workspace: string; promise: Promise<void> } | undefined
export function loadCopilot(workspace: string): Promise<void> {
if (inFlight?.workspace === workspace) {
return inFlight.promise
}
const promise = fetchAndApply(workspace, ++loadCopilotToken).finally(() => {
if (inFlight?.promise === promise) {
inFlight = undefined
}
})
inFlight = { workspace, promise }
return promise
}
async function fetchAndApply(workspace: string, token: number) {
workspaceAIClients.init(workspace)
try {
const info = await WorkspaceService.getCopilotInfo({ workspace })
if (token !== loadCopilotToken) return
setCopilotInfo(info)
copilotWorkspace.set(workspace)
} catch (err) {
if (token !== loadCopilotToken) return
setCopilotInfo({})
copilotWorkspace.set(workspace)
console.error('Could not get copilot info', err)
}
}