@jskit-ai/assistant 0.1.32 → 0.1.35

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