File size: 4,899 Bytes
1f21206 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | /**
* Settings REST API
*
* GET /api/settings โ ่ทๅๅๅนถๅ็่ฎพ็ฝฎ
* GET /api/settings/user โ ่ทๅ็จๆท่ฎพ็ฝฎ
* GET /api/settings/project โ ่ทๅ้กน็ฎ่ฎพ็ฝฎ
* PUT /api/settings/user โ ๆดๆฐ็จๆท่ฎพ็ฝฎ
* PUT /api/settings/project โ ๆดๆฐ้กน็ฎ่ฎพ็ฝฎ
* GET /api/permissions/mode โ ่ทๅๆ้ๆจกๅผ
* PUT /api/permissions/mode โ ่ฎพ็ฝฎๆ้ๆจกๅผ
*/
import { SettingsService } from '../services/settingsService.js'
import { ApiError, errorResponse } from '../middleware/errorHandler.js'
import { ensureDesktopCliLauncherInstalled } from '../services/desktopCliLauncherService.js'
import { conversationService } from '../services/conversationService.js'
const settingsService = new SettingsService()
export async function handleSettingsApi(
req: Request,
url: URL,
segments: string[],
): Promise<Response> {
try {
const resource = segments[1] // 'settings' | 'permissions'
const sub = segments[2] // 'user' | 'project' | 'mode' | undefined
// โโ /api/permissions/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if (resource === 'permissions') {
if (sub === 'mode') {
return await handlePermissionMode(req)
}
throw ApiError.notFound(`Unknown permissions endpoint: ${sub}`)
}
// โโ /api/settings/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const method = req.method
switch (sub) {
case undefined:
// GET /api/settings
if (method !== 'GET') throw methodNotAllowed(method)
return Response.json(await settingsService.getSettings())
case 'user':
return await handleUserSettings(req)
case 'project':
return await handleProjectSettings(req, url)
case 'cli-launcher':
if (method !== 'GET') throw methodNotAllowed(method)
return Response.json(await ensureDesktopCliLauncherInstalled())
default:
throw ApiError.notFound(`Unknown settings endpoint: ${sub}`)
}
} catch (error) {
return errorResponse(error)
}
}
// โโโ Handlers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
async function handleUserSettings(req: Request): Promise<Response> {
if (req.method === 'GET') {
return Response.json(await settingsService.getUserSettings())
}
if (req.method === 'PUT') {
const body = await parseJsonBody(req)
await settingsService.updateUserSettings(body)
syncThinkingSettingToActiveSessions(body)
return Response.json({ ok: true })
}
throw methodNotAllowed(req.method)
}
async function handleProjectSettings(req: Request, url: URL): Promise<Response> {
const projectRoot = url.searchParams.get('projectRoot') || undefined
if (req.method === 'GET') {
return Response.json(await settingsService.getProjectSettings(projectRoot))
}
if (req.method === 'PUT') {
const body = await parseJsonBody(req)
await settingsService.updateProjectSettings(body, projectRoot)
return Response.json({ ok: true })
}
throw methodNotAllowed(req.method)
}
async function handlePermissionMode(req: Request): Promise<Response> {
if (req.method === 'GET') {
const mode = await settingsService.getPermissionMode()
return Response.json({ mode })
}
if (req.method === 'PUT') {
const body = await parseJsonBody(req)
const mode = body.mode
if (typeof mode !== 'string') {
throw ApiError.badRequest('Missing or invalid "mode" in request body')
}
await settingsService.setPermissionMode(mode)
return Response.json({ ok: true, mode })
}
throw methodNotAllowed(req.method)
}
// โโโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
async function parseJsonBody(req: Request): Promise<Record<string, unknown>> {
try {
return (await req.json()) as Record<string, unknown>
} catch {
throw ApiError.badRequest('Invalid JSON body')
}
}
function methodNotAllowed(method: string): ApiError {
return new ApiError(405, `Method ${method} not allowed`, 'METHOD_NOT_ALLOWED')
}
function syncThinkingSettingToActiveSessions(settings: Record<string, unknown>): void {
if (
!Object.prototype.hasOwnProperty.call(settings, 'alwaysThinkingEnabled') ||
typeof settings.alwaysThinkingEnabled !== 'boolean'
) {
return
}
conversationService.setMaxThinkingTokensForActiveSessions(
settings.alwaysThinkingEnabled ? null : 0,
)
}
|