Files
goodbuddy/src/shared/application-settings-contracts.ts
T
mesalogo 48d7526b7e feat: configure supervisor model and story graph use per conversation
Add a supervisor text-model selector using existing connections and a per-conversation story graph switch above knowledge settings. Hide the switch when Supervisor is disabled and enforce conversation preferences at local and remote tool execution boundaries.

Release note: Choose a dedicated supervisor model and control whether each conversation can query existing stories and experiences. Enabling graph access does not start a review or automatically insert context.
2026-10-03 19:16:35 +08:00

136 lines
5.4 KiB
TypeScript

import { z } from 'zod'
import { supervisionReviewSettingsSchema } from './supervision-review-contracts'
import { magicNoteCommentFormatSchema } from './magic-notes-contracts'
import { localToolEnvironmentSettingsSchema } from './local-tool-environment-contracts'
import { modelDownloadSourceSchema } from './model-download-contracts'
import { settingsWarningsSchema } from './settings-warning-contracts'
export {
artifactDownloadSourceSchema,
defaultLocalToolEnvironmentSettings,
localToolEnvironmentSettingsSchema,
localToolExecutablePathSchema,
localToolRuntimeSelectionSchema,
type ArtifactDownloadSource,
type LocalToolEnvironmentSettings,
type LocalToolRuntimeSelection
} from './local-tool-environment-contracts'
export {
modelDownloadSourceSchema,
type ModelDownloadSource
} from './model-download-contracts'
export const magicNoteCommentModeSchema = z.enum([
'immediate',
'after-save-auto',
'after-save-manual'
])
export type MagicNoteCommentMode = z.infer<typeof magicNoteCommentModeSchema>
export const magicNoteCanvasPageCountSchema = z.number().int().min(1).max(8)
export const updateSourceSchema = z.enum(['github', 'mirror'])
export type UpdateSource = z.infer<typeof updateSourceSchema>
export const defaultSupervisionTimeoutSeconds = 240
export const defaultSupervisorModelConcurrency = 1
export const supervisorModelConcurrencySchema = z.number().int().min(1).max(4)
export const supervisionTimeoutSecondsSchema = z.number().int().min(30).max(600)
export const builtInApplicationIds = ['magic-notes', 'knowledge', 'heartbeat', 'local-inference', 'device-sharing'] as const
export type BuiltInApplicationId = typeof builtInApplicationIds[number]
export const editableApplicationIds = ['magic-notes', 'heartbeat', 'local-inference', 'device-sharing'] as const
export type EditableApplicationId = typeof editableApplicationIds[number]
export const defaultApplicationNavigation = {
order: ['knowledge', 'heartbeat', 'magic-notes', 'local-inference', 'device-sharing'] as BuiltInApplicationId[],
pinned: { 'magic-notes': true, heartbeat: true, 'local-inference': false }
}
export const applicationNavigationSchema = z.object({
order: z.array(z.enum(builtInApplicationIds)).length(builtInApplicationIds.length)
.refine(ids => new Set(ids).size === builtInApplicationIds.length, 'Each application must occur exactly once'),
pinned: z.object({
'magic-notes': z.boolean(),
heartbeat: z.boolean().default(true),
'local-inference': z.boolean()
}).strict()
}).strict()
const applicationPreferencesSchema = z
.object({
checkUpdatesOnStartup: z.boolean(),
desktopNotificationsEnabled: z.boolean().default(true),
transparentFrostedEffectEnabled: z.boolean().default(true),
updateSource: updateSourceSchema,
modelDownloadSource: modelDownloadSourceSchema,
localToolEnvironment: localToolEnvironmentSettingsSchema,
conversationHtmlRenderingEnabled: z.boolean(),
remoteProjectsEnabled: z.boolean(),
applicationNavigation: applicationNavigationSchema.default(defaultApplicationNavigation),
localInferenceEnabled: z.boolean().default(true),
deviceSharingEnabled: z.boolean().default(false),
magicNotesEnabled: z.boolean().default(true),
heartbeatEnabled: z.boolean().optional(),
heartbeatReportTimeoutSeconds: supervisionTimeoutSecondsSchema.optional(),
supervisorOrganizeTimeoutSeconds: supervisionTimeoutSecondsSchema.optional(),
supervisorModelConcurrency: supervisorModelConcurrencySchema.optional(),
supervisorModelProfileId: z.string().uuid().nullable().optional(),
supervisionReview: supervisionReviewSettingsSchema.optional(),
magicNotesShowIncompleteTodoCount: z.boolean().default(true),
magicNoteCommentMode: magicNoteCommentModeSchema.default('immediate'),
magicNoteCommentFormat: magicNoteCommentFormatSchema.default('combined'),
magicNoteCanvasPageCount: magicNoteCanvasPageCountSchema.default(1)
})
.strict()
export const applicationSettingsSchema = applicationPreferencesSchema
.extend({
warnings: settingsWarningsSchema.optional()
})
.strict()
export const applicationSettingsUpdateSchema = applicationPreferencesSchema
.partial()
.extend({
applicationNavigation: applicationNavigationSchema.optional(),
desktopNotificationsEnabled: z.boolean().optional(),
transparentFrostedEffectEnabled: z.boolean().optional(),
localInferenceEnabled: z.boolean().optional(),
deviceSharingEnabled: z.boolean().optional(),
magicNotesEnabled: z.boolean().optional(),
heartbeatEnabled: z.boolean().optional(),
magicNotesShowIncompleteTodoCount: z.boolean().optional(),
magicNoteCommentMode: magicNoteCommentModeSchema.optional(),
magicNoteCommentFormat: magicNoteCommentFormatSchema.optional(),
magicNoteCanvasPageCount: magicNoteCanvasPageCountSchema.optional()
})
.refine((input) => Object.keys(input).length > 0, {
message: 'At least one application setting is required'
})
export type ApplicationSettings = z.infer<typeof applicationSettingsSchema>
export type ApplicationSettingsUpdate = z.infer<
typeof applicationSettingsUpdateSchema
>
export type VersionCheckFile = {
name: string
size: number
sha256: string
}
export type VersionCheckTarget = {
platform: 'windows' | 'macos' | 'linux'
arch: 'x64' | 'arm64'
formats: string[]
files: VersionCheckFile[]
}
export type VersionCheckResult = {
updateAvailable: boolean
currentVersion: string
latestVersion: string
releaseUrl: string
target: VersionCheckTarget
}