@jskit-ai/assistant 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.descriptor.mjs +284 -0
- package/package.json +31 -0
- package/src/client/components/AssistantClientElement.vue +1316 -0
- package/src/client/components/AssistantConsoleSettingsClientElement.vue +71 -0
- package/src/client/components/AssistantSettingsFormCard.vue +76 -0
- package/src/client/components/AssistantWorkspaceClientElement.vue +15 -0
- package/src/client/components/AssistantWorkspaceSettingsClientElement.vue +73 -0
- package/src/client/composables/useAssistantWorkspaceRuntime.js +789 -0
- package/src/client/index.js +12 -0
- package/src/client/lib/assistantApi.js +137 -0
- package/src/client/lib/assistantHttpClient.js +10 -0
- package/src/client/lib/markdownRenderer.js +31 -0
- package/src/client/providers/AssistantWebClientProvider.js +25 -0
- package/src/server/AssistantServiceProvider.js +179 -0
- package/src/server/actionIds.js +11 -0
- package/src/server/actions.js +191 -0
- package/src/server/diTokens.js +19 -0
- package/src/server/lib/aiClient.js +43 -0
- package/src/server/lib/ndjson.js +47 -0
- package/src/server/lib/providers/anthropicClient.js +375 -0
- package/src/server/lib/providers/common.js +158 -0
- package/src/server/lib/providers/deepSeekClient.js +22 -0
- package/src/server/lib/providers/openAiClient.js +13 -0
- package/src/server/lib/providers/openAiCompatibleClient.js +69 -0
- package/src/server/lib/resolveWorkspaceSlug.js +24 -0
- package/src/server/lib/serviceToolCatalog.js +459 -0
- package/src/server/registerRoutes.js +384 -0
- package/src/server/repositories/assistantSettingsRepository.js +100 -0
- package/src/server/repositories/conversationsRepository.js +244 -0
- package/src/server/repositories/messagesRepository.js +154 -0
- package/src/server/repositories/repositoryPersistenceUtils.js +63 -0
- package/src/server/services/assistantSettingsService.js +153 -0
- package/src/server/services/chatService.js +987 -0
- package/src/server/services/transcriptService.js +334 -0
- package/src/shared/assistantPaths.js +50 -0
- package/src/shared/assistantResource.js +323 -0
- package/src/shared/assistantSettingsResource.js +214 -0
- package/src/shared/index.js +39 -0
- package/src/shared/queryKeys.js +69 -0
- package/src/shared/settingsEvents.js +7 -0
- package/src/shared/streamEvents.js +31 -0
- package/src/shared/support/positiveInteger.js +9 -0
- package/templates/migrations/assistant_settings_initial.cjs +39 -0
- package/templates/migrations/assistant_transcripts_initial.cjs +51 -0
- package/templates/src/pages/admin/workspace/assistant/index.vue +7 -0
- package/test/aiConfigValidation.test.js +15 -0
- package/test/assistantApiSurfaceHeader.test.js +64 -0
- package/test/assistantResource.test.js +53 -0
- package/test/assistantSettingsResource.test.js +48 -0
- package/test/assistantSettingsService.test.js +133 -0
- package/test/chatService.test.js +841 -0
- package/test/descriptorSurfaceOption.test.js +35 -0
- package/test/queryKeys.test.js +41 -0
- package/test/resolveWorkspaceSlug.test.js +83 -0
- package/test/routeInputContracts.test.js +287 -0
- package/test/serviceToolCatalog.test.js +1235 -0
- package/test/transcriptService.test.js +175 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { withStandardErrorResponses } from "@jskit-ai/http-runtime/shared/validators/errorResponses";
|
|
2
|
+
import { KERNEL_TOKENS } from "@jskit-ai/kernel/shared/support/tokens";
|
|
3
|
+
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
4
|
+
import {
|
|
5
|
+
workspaceSlugParamsValidator
|
|
6
|
+
} from "@jskit-ai/users-core/server/validators/routeParamsValidator";
|
|
7
|
+
import {
|
|
8
|
+
resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig,
|
|
9
|
+
resolveWorkspaceSurfaceIdsFromAppConfig
|
|
10
|
+
} from "@jskit-ai/users-core/server/support/workspaceActionSurfaces";
|
|
11
|
+
import { resolveAssistantApiBasePath } from "../shared/assistantPaths.js";
|
|
12
|
+
import { assistantResource } from "../shared/assistantResource.js";
|
|
13
|
+
import {
|
|
14
|
+
assistantConsoleSettingsResource,
|
|
15
|
+
assistantWorkspaceSettingsResource
|
|
16
|
+
} from "../shared/assistantSettingsResource.js";
|
|
17
|
+
import { actionIds } from "./actionIds.js";
|
|
18
|
+
import { endNdjson, mapStreamError, setNdjsonHeaders, writeNdjson } from "./lib/ndjson.js";
|
|
19
|
+
|
|
20
|
+
function resolveAssistantWorkspaceRouteSurfaceConfig(app) {
|
|
21
|
+
const appConfig = typeof app?.has === "function" && app.has("appConfig") ? app.make("appConfig") : {};
|
|
22
|
+
const workspaceSurfaceIds = resolveWorkspaceSurfaceIdsFromAppConfig(appConfig);
|
|
23
|
+
const fallbackSurfaceId = resolveDefaultWorkspaceRouteSurfaceIdFromAppConfig(appConfig);
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
fallbackSurfaceId,
|
|
26
|
+
allowedSurfaceIds: new Set(workspaceSurfaceIds)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveAssistantWorkspaceRequestSurfaceId(request, workspaceRouteSurfaceConfig = {}) {
|
|
31
|
+
const headerValue = request?.headers?.["x-jskit-surface"];
|
|
32
|
+
const headerCandidate = Array.isArray(headerValue) ? headerValue[0] : headerValue;
|
|
33
|
+
const requestedSurfaceId = normalizeText(headerCandidate).toLowerCase();
|
|
34
|
+
const fallbackSurfaceId = normalizeText(workspaceRouteSurfaceConfig?.fallbackSurfaceId).toLowerCase() || "app";
|
|
35
|
+
const allowedSurfaceIds = workspaceRouteSurfaceConfig?.allowedSurfaceIds instanceof Set
|
|
36
|
+
? workspaceRouteSurfaceConfig.allowedSurfaceIds
|
|
37
|
+
: new Set();
|
|
38
|
+
|
|
39
|
+
if (!requestedSurfaceId) {
|
|
40
|
+
return fallbackSurfaceId;
|
|
41
|
+
}
|
|
42
|
+
if (allowedSurfaceIds.size > 0 && !allowedSurfaceIds.has(requestedSurfaceId)) {
|
|
43
|
+
return fallbackSurfaceId;
|
|
44
|
+
}
|
|
45
|
+
return requestedSurfaceId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function registerRoutes(app) {
|
|
49
|
+
if (!app || typeof app.make !== "function") {
|
|
50
|
+
throw new Error("registerRoutes requires application make().");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const router = app.make(KERNEL_TOKENS.HttpRouter);
|
|
54
|
+
const visibility = "workspace";
|
|
55
|
+
const workspaceRouteSurfaceConfig = resolveAssistantWorkspaceRouteSurfaceConfig(app);
|
|
56
|
+
const workspaceRouteSurfaceId = workspaceRouteSurfaceConfig.fallbackSurfaceId;
|
|
57
|
+
const routeBase = resolveAssistantApiBasePath({
|
|
58
|
+
visibility
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
router.register(
|
|
62
|
+
"GET",
|
|
63
|
+
"/api/console/settings/assistant",
|
|
64
|
+
{
|
|
65
|
+
auth: "required",
|
|
66
|
+
surface: "console",
|
|
67
|
+
meta: {
|
|
68
|
+
tags: ["assistant", "settings"],
|
|
69
|
+
summary: "Get assistant console settings."
|
|
70
|
+
},
|
|
71
|
+
responseValidators: withStandardErrorResponses({
|
|
72
|
+
200: assistantConsoleSettingsResource.operations.view.outputValidator
|
|
73
|
+
})
|
|
74
|
+
},
|
|
75
|
+
async function assistantConsoleSettingsReadRoute(request, reply) {
|
|
76
|
+
const response = await request.executeAction({
|
|
77
|
+
actionId: actionIds.consoleSettingsRead
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
reply.code(200).send(response);
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
router.register(
|
|
85
|
+
"PATCH",
|
|
86
|
+
"/api/console/settings/assistant",
|
|
87
|
+
{
|
|
88
|
+
auth: "required",
|
|
89
|
+
surface: "console",
|
|
90
|
+
meta: {
|
|
91
|
+
tags: ["assistant", "settings"],
|
|
92
|
+
summary: "Update assistant console settings."
|
|
93
|
+
},
|
|
94
|
+
bodyValidator: assistantConsoleSettingsResource.operations.patch.bodyValidator,
|
|
95
|
+
responseValidators: withStandardErrorResponses(
|
|
96
|
+
{
|
|
97
|
+
200: assistantConsoleSettingsResource.operations.patch.outputValidator
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
includeValidation400: true
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
},
|
|
104
|
+
async function assistantConsoleSettingsPatchRoute(request, reply) {
|
|
105
|
+
const response = await request.executeAction({
|
|
106
|
+
actionId: actionIds.consoleSettingsUpdate,
|
|
107
|
+
input: {
|
|
108
|
+
payload: request.input.body
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
reply.code(200).send(response);
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
router.register(
|
|
117
|
+
"GET",
|
|
118
|
+
"/api/w/:workspaceSlug/workspace/settings/assistant",
|
|
119
|
+
{
|
|
120
|
+
auth: "required",
|
|
121
|
+
surface: workspaceRouteSurfaceId,
|
|
122
|
+
visibility,
|
|
123
|
+
meta: {
|
|
124
|
+
tags: ["assistant", "settings"],
|
|
125
|
+
summary: "Get assistant workspace settings."
|
|
126
|
+
},
|
|
127
|
+
paramsValidator: workspaceSlugParamsValidator,
|
|
128
|
+
responseValidators: withStandardErrorResponses({
|
|
129
|
+
200: assistantWorkspaceSettingsResource.operations.view.outputValidator
|
|
130
|
+
})
|
|
131
|
+
},
|
|
132
|
+
async function assistantWorkspaceSettingsReadRoute(request, reply) {
|
|
133
|
+
const response = await request.executeAction({
|
|
134
|
+
actionId: actionIds.workspaceSettingsRead,
|
|
135
|
+
context: {
|
|
136
|
+
surface: resolveAssistantWorkspaceRequestSurfaceId(request, workspaceRouteSurfaceConfig)
|
|
137
|
+
},
|
|
138
|
+
input: {
|
|
139
|
+
workspaceSlug: request.input.params.workspaceSlug
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
reply.code(200).send(response);
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
router.register(
|
|
148
|
+
"PATCH",
|
|
149
|
+
"/api/w/:workspaceSlug/workspace/settings/assistant",
|
|
150
|
+
{
|
|
151
|
+
auth: "required",
|
|
152
|
+
surface: workspaceRouteSurfaceId,
|
|
153
|
+
visibility,
|
|
154
|
+
meta: {
|
|
155
|
+
tags: ["assistant", "settings"],
|
|
156
|
+
summary: "Update assistant workspace settings."
|
|
157
|
+
},
|
|
158
|
+
paramsValidator: workspaceSlugParamsValidator,
|
|
159
|
+
bodyValidator: assistantWorkspaceSettingsResource.operations.patch.bodyValidator,
|
|
160
|
+
responseValidators: withStandardErrorResponses(
|
|
161
|
+
{
|
|
162
|
+
200: assistantWorkspaceSettingsResource.operations.patch.outputValidator
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
includeValidation400: true
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
},
|
|
169
|
+
async function assistantWorkspaceSettingsPatchRoute(request, reply) {
|
|
170
|
+
const response = await request.executeAction({
|
|
171
|
+
actionId: actionIds.workspaceSettingsUpdate,
|
|
172
|
+
context: {
|
|
173
|
+
surface: resolveAssistantWorkspaceRequestSurfaceId(request, workspaceRouteSurfaceConfig)
|
|
174
|
+
},
|
|
175
|
+
input: {
|
|
176
|
+
workspaceSlug: request.input.params.workspaceSlug,
|
|
177
|
+
patch: request.input.body
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
reply.code(200).send(response);
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
router.register(
|
|
186
|
+
"POST",
|
|
187
|
+
`${routeBase}/chat/stream`,
|
|
188
|
+
{
|
|
189
|
+
auth: "required",
|
|
190
|
+
surface: workspaceRouteSurfaceId,
|
|
191
|
+
visibility,
|
|
192
|
+
meta: {
|
|
193
|
+
tags: ["assistant"],
|
|
194
|
+
summary: "Stream assistant response for workspace user."
|
|
195
|
+
},
|
|
196
|
+
paramsValidator: workspaceSlugParamsValidator,
|
|
197
|
+
bodyValidator: assistantResource.operations.chatStream.bodyValidator
|
|
198
|
+
},
|
|
199
|
+
async function assistantChatStreamRoute(request, reply) {
|
|
200
|
+
const abortController = new AbortController();
|
|
201
|
+
const closeListener = () => {
|
|
202
|
+
abortController.abort();
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
let streamStarted = false;
|
|
206
|
+
|
|
207
|
+
function ensureStreamStarted() {
|
|
208
|
+
if (streamStarted) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
setNdjsonHeaders(reply);
|
|
213
|
+
reply.code(200);
|
|
214
|
+
reply.hijack();
|
|
215
|
+
if (typeof reply.raw.flushHeaders === "function") {
|
|
216
|
+
reply.raw.flushHeaders();
|
|
217
|
+
}
|
|
218
|
+
streamStarted = true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const streamWriter = Object.freeze({
|
|
222
|
+
sendMeta(payload = {}) {
|
|
223
|
+
ensureStreamStarted();
|
|
224
|
+
writeNdjson(reply, payload);
|
|
225
|
+
},
|
|
226
|
+
sendAssistantDelta(payload = {}) {
|
|
227
|
+
ensureStreamStarted();
|
|
228
|
+
writeNdjson(reply, payload);
|
|
229
|
+
},
|
|
230
|
+
sendAssistantMessage(payload = {}) {
|
|
231
|
+
ensureStreamStarted();
|
|
232
|
+
writeNdjson(reply, payload);
|
|
233
|
+
},
|
|
234
|
+
sendToolCall(payload = {}) {
|
|
235
|
+
ensureStreamStarted();
|
|
236
|
+
writeNdjson(reply, payload);
|
|
237
|
+
},
|
|
238
|
+
sendToolResult(payload = {}) {
|
|
239
|
+
ensureStreamStarted();
|
|
240
|
+
writeNdjson(reply, payload);
|
|
241
|
+
},
|
|
242
|
+
sendError(payload = {}) {
|
|
243
|
+
ensureStreamStarted();
|
|
244
|
+
writeNdjson(reply, payload);
|
|
245
|
+
},
|
|
246
|
+
sendDone(payload = {}) {
|
|
247
|
+
ensureStreamStarted();
|
|
248
|
+
writeNdjson(reply, payload);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
request.raw.on("close", closeListener);
|
|
254
|
+
|
|
255
|
+
await request.executeAction({
|
|
256
|
+
actionId: actionIds.chatStream,
|
|
257
|
+
context: {
|
|
258
|
+
surface: resolveAssistantWorkspaceRequestSurfaceId(request, workspaceRouteSurfaceConfig)
|
|
259
|
+
},
|
|
260
|
+
input: (() => {
|
|
261
|
+
const body = request.input.body;
|
|
262
|
+
const input = {
|
|
263
|
+
workspaceSlug: request.input.params.workspaceSlug,
|
|
264
|
+
messageId: body.messageId,
|
|
265
|
+
input: body.input
|
|
266
|
+
};
|
|
267
|
+
if (Object.hasOwn(body, "conversationId")) {
|
|
268
|
+
input.conversationId = body.conversationId;
|
|
269
|
+
}
|
|
270
|
+
if (Object.hasOwn(body, "history")) {
|
|
271
|
+
input.history = body.history;
|
|
272
|
+
}
|
|
273
|
+
if (Object.hasOwn(body, "clientContext")) {
|
|
274
|
+
input.clientContext = body.clientContext;
|
|
275
|
+
}
|
|
276
|
+
return input;
|
|
277
|
+
})(),
|
|
278
|
+
deps: {
|
|
279
|
+
streamWriter,
|
|
280
|
+
abortSignal: abortController.signal
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (streamStarted) {
|
|
285
|
+
endNdjson(reply);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
reply.code(204).send();
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (!streamStarted) {
|
|
292
|
+
const statusCode = Number(error?.status || error?.statusCode || 500);
|
|
293
|
+
const safeStatusCode = Number.isInteger(statusCode) && statusCode >= 400 && statusCode <= 599 ? statusCode : 500;
|
|
294
|
+
reply.code(safeStatusCode).send({
|
|
295
|
+
error: safeStatusCode >= 500 ? "Internal server error." : String(error?.message || "Request failed.")
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const streamError = mapStreamError(error);
|
|
301
|
+
writeNdjson(reply, {
|
|
302
|
+
type: "error",
|
|
303
|
+
...streamError
|
|
304
|
+
});
|
|
305
|
+
writeNdjson(reply, {
|
|
306
|
+
type: "done",
|
|
307
|
+
status: "failed"
|
|
308
|
+
});
|
|
309
|
+
endNdjson(reply);
|
|
310
|
+
} finally {
|
|
311
|
+
request.raw.off("close", closeListener);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
router.register(
|
|
317
|
+
"GET",
|
|
318
|
+
`${routeBase}/conversations`,
|
|
319
|
+
{
|
|
320
|
+
auth: "required",
|
|
321
|
+
surface: workspaceRouteSurfaceId,
|
|
322
|
+
visibility,
|
|
323
|
+
meta: {
|
|
324
|
+
tags: ["assistant"],
|
|
325
|
+
summary: "List assistant conversations for current workspace user."
|
|
326
|
+
},
|
|
327
|
+
paramsValidator: workspaceSlugParamsValidator,
|
|
328
|
+
queryValidator: assistantResource.operations.conversationsList.queryValidator,
|
|
329
|
+
responseValidators: withStandardErrorResponses({
|
|
330
|
+
200: assistantResource.operations.conversationsList.outputValidator
|
|
331
|
+
})
|
|
332
|
+
},
|
|
333
|
+
async function assistantConversationsRoute(request, reply) {
|
|
334
|
+
const response = await request.executeAction({
|
|
335
|
+
actionId: actionIds.conversationsList,
|
|
336
|
+
context: {
|
|
337
|
+
surface: resolveAssistantWorkspaceRequestSurfaceId(request, workspaceRouteSurfaceConfig)
|
|
338
|
+
},
|
|
339
|
+
input: {
|
|
340
|
+
workspaceSlug: request.input.params.workspaceSlug,
|
|
341
|
+
query: request.input.query
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
reply.code(200).send(response);
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
router.register(
|
|
350
|
+
"GET",
|
|
351
|
+
`${routeBase}/conversations/:conversationId/messages`,
|
|
352
|
+
{
|
|
353
|
+
auth: "required",
|
|
354
|
+
surface: workspaceRouteSurfaceId,
|
|
355
|
+
visibility,
|
|
356
|
+
meta: {
|
|
357
|
+
tags: ["assistant"],
|
|
358
|
+
summary: "List messages for one assistant conversation."
|
|
359
|
+
},
|
|
360
|
+
paramsValidator: [workspaceSlugParamsValidator, assistantResource.operations.conversationMessagesList.paramsValidator],
|
|
361
|
+
queryValidator: assistantResource.operations.conversationMessagesList.queryValidator,
|
|
362
|
+
responseValidators: withStandardErrorResponses({
|
|
363
|
+
200: assistantResource.operations.conversationMessagesList.outputValidator
|
|
364
|
+
})
|
|
365
|
+
},
|
|
366
|
+
async function assistantConversationMessagesRoute(request, reply) {
|
|
367
|
+
const response = await request.executeAction({
|
|
368
|
+
actionId: actionIds.conversationMessagesList,
|
|
369
|
+
context: {
|
|
370
|
+
surface: resolveAssistantWorkspaceRequestSurfaceId(request, workspaceRouteSurfaceConfig)
|
|
371
|
+
},
|
|
372
|
+
input: {
|
|
373
|
+
workspaceSlug: request.input.params.workspaceSlug,
|
|
374
|
+
conversationId: request.input.params.conversationId,
|
|
375
|
+
query: request.input.query
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
reply.code(200).send(response);
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export { registerRoutes };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { parsePositiveInteger } from "@jskit-ai/kernel/server/runtime";
|
|
2
|
+
import { toIso } from "./repositoryPersistenceUtils.js";
|
|
3
|
+
|
|
4
|
+
function mapConsoleRow(row = {}) {
|
|
5
|
+
return {
|
|
6
|
+
workspaceSurfacePrompt: String(row.assistant_workspace_surface_prompt || ""),
|
|
7
|
+
createdAt: toIso(row.created_at),
|
|
8
|
+
updatedAt: toIso(row.updated_at)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function mapWorkspaceRow(row = {}) {
|
|
13
|
+
return {
|
|
14
|
+
workspaceId: Number(row.workspace_id),
|
|
15
|
+
appSurfacePrompt: String(row.assistant_app_surface_prompt || ""),
|
|
16
|
+
createdAt: toIso(row.created_at),
|
|
17
|
+
updatedAt: toIso(row.updated_at)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createRepository(knex) {
|
|
22
|
+
if (typeof knex !== "function") {
|
|
23
|
+
throw new TypeError("assistantSettingsRepository requires knex.");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function ensureConsoleSettings(options = {}) {
|
|
27
|
+
const client = options?.trx || knex;
|
|
28
|
+
const row = await client("console_settings").where({ id: 1 }).first();
|
|
29
|
+
if (!row) {
|
|
30
|
+
throw new Error("console_settings row missing.");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return mapConsoleRow(row);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function updateConsoleSettings(patch = {}, options = {}) {
|
|
37
|
+
const client = options?.trx || knex;
|
|
38
|
+
const nextWorkspaceSurfacePrompt = String(patch.workspaceSurfacePrompt || "");
|
|
39
|
+
|
|
40
|
+
await client("console_settings")
|
|
41
|
+
.where({ id: 1 })
|
|
42
|
+
.update({
|
|
43
|
+
assistant_workspace_surface_prompt: nextWorkspaceSurfacePrompt,
|
|
44
|
+
updated_at: new Date()
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return ensureConsoleSettings({
|
|
48
|
+
trx: client
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function ensureWorkspaceSettings(workspaceId, options = {}) {
|
|
53
|
+
const numericWorkspaceId = parsePositiveInteger(workspaceId);
|
|
54
|
+
if (!numericWorkspaceId) {
|
|
55
|
+
throw new TypeError("assistantSettingsRepository.ensureWorkspaceSettings requires workspace id.");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const client = options?.trx || knex;
|
|
59
|
+
const row = await client("workspace_settings").where({ workspace_id: numericWorkspaceId }).first();
|
|
60
|
+
if (!row) {
|
|
61
|
+
throw new Error("workspace_settings row missing.");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return mapWorkspaceRow(row);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function updateWorkspaceSettings(workspaceId, patch = {}, options = {}) {
|
|
68
|
+
const numericWorkspaceId = parsePositiveInteger(workspaceId);
|
|
69
|
+
if (!numericWorkspaceId) {
|
|
70
|
+
throw new TypeError("assistantSettingsRepository.updateWorkspaceSettings requires workspace id.");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const client = options?.trx || knex;
|
|
74
|
+
const nextAppSurfacePrompt = String(patch.appSurfacePrompt || "");
|
|
75
|
+
|
|
76
|
+
await ensureWorkspaceSettings(numericWorkspaceId, {
|
|
77
|
+
trx: client
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await client("workspace_settings")
|
|
81
|
+
.where({ workspace_id: numericWorkspaceId })
|
|
82
|
+
.update({
|
|
83
|
+
assistant_app_surface_prompt: nextAppSurfacePrompt,
|
|
84
|
+
updated_at: new Date()
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return ensureWorkspaceSettings(numericWorkspaceId, {
|
|
88
|
+
trx: client
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return Object.freeze({
|
|
93
|
+
ensureConsoleSettings,
|
|
94
|
+
updateConsoleSettings,
|
|
95
|
+
ensureWorkspaceSettings,
|
|
96
|
+
updateWorkspaceSettings
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { createRepository };
|