@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,35 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import descriptor from "../package.descriptor.mjs";
4
-
5
- function findFileMutation(id) {
6
- const mutations = Array.isArray(descriptor?.mutations?.files) ? descriptor.mutations.files : [];
7
- return mutations.find((entry) => String(entry?.id || "") === id) || null;
8
- }
9
-
10
- function findTextMutation(id) {
11
- const mutations = Array.isArray(descriptor?.mutations?.text) ? descriptor.mutations.text : [];
12
- return mutations.find((entry) => String(entry?.id || "") === id) || null;
13
- }
14
-
15
- test("assistant descriptor exposes configurable workspace surface option", () => {
16
- const option = descriptor?.options?.surfaces;
17
- assert.equal(option?.required, true);
18
- assert.equal(option?.inputType, "text");
19
- assert.equal(option?.defaultValue, "admin");
20
- });
21
-
22
- test("assistant descriptor routes workspace page + placements through surface option", () => {
23
- const workspacePage = findFileMutation("assistant-page-admin-workspace-assistant-index");
24
- const menuPlacement = findTextMutation("assistant-placement-menu");
25
- const workspaceSettingsPlacement = findTextMutation("assistant-workspace-settings-form-placement");
26
- const consoleSettingsPlacement = findTextMutation("assistant-console-settings-form-placement");
27
-
28
- assert.equal(workspacePage?.toSurface, "${option:surfaces|lower}");
29
- assert.match(String(menuPlacement?.value || ""), /"\$\{option:surfaces\|lower\}"/);
30
- assert.match(String(menuPlacement?.value || ""), /\.split\(","\)/);
31
- assert.match(String(menuPlacement?.value || ""), /surfaces: assistantWorkspaceSurfaceIds\.length > 0 \? assistantWorkspaceSurfaceIds : \["\*"\]/);
32
- assert.doesNotMatch(String(menuPlacement?.value || ""), /surface:\s*"/);
33
- assert.match(String(workspaceSettingsPlacement?.value || ""), /surfaces: \["\*"\]/);
34
- assert.match(String(consoleSettingsPlacement?.value || ""), /surfaces: \["\*"\]/);
35
- });
@@ -1,41 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import {
4
- ASSISTANT_QUERY_KEY_PREFIX,
5
- assistantRootQueryKey,
6
- assistantWorkspaceScopeQueryKey,
7
- assistantConversationsListQueryKey,
8
- assistantConversationMessagesQueryKey
9
- } from "../src/shared/queryKeys.js";
10
-
11
- test("assistant query keys normalize workspace scope and paging", () => {
12
- assert.deepEqual(ASSISTANT_QUERY_KEY_PREFIX, ["assistant"]);
13
- assert.deepEqual(assistantRootQueryKey(), ["assistant"]);
14
-
15
- assert.deepEqual(assistantWorkspaceScopeQueryKey({ workspaceSlug: "acme" }), ["assistant", "slug:acme"]);
16
- assert.deepEqual(assistantWorkspaceScopeQueryKey({ workspaceId: "9" }), ["assistant", "id:9"]);
17
-
18
- assert.deepEqual(assistantConversationsListQueryKey({ workspaceSlug: "acme" }), [
19
- "assistant",
20
- "slug:acme",
21
- "conversations",
22
- "list",
23
- 20,
24
- "all"
25
- ]);
26
-
27
- assert.deepEqual(
28
- assistantConversationsListQueryKey({ workspaceId: 9 }, { limit: 10, status: "ACTIVE" }),
29
- ["assistant", "id:9", "conversations", "list", 10, "active"]
30
- );
31
-
32
- assert.deepEqual(assistantConversationMessagesQueryKey({ workspaceSlug: "acme" }, "22"), [
33
- "assistant",
34
- "slug:acme",
35
- "conversations",
36
- "22",
37
- "messages",
38
- 1,
39
- 200
40
- ]);
41
- });
@@ -1,83 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { resolveWorkspaceSlug } from "../src/server/lib/resolveWorkspaceSlug.js";
4
-
5
- test("resolveWorkspaceSlug follows fallback priority", () => {
6
- const slug = resolveWorkspaceSlug(
7
- {
8
- workspace: {
9
- slug: "workspace-primary"
10
- },
11
- requestMeta: {
12
- resolvedWorkspaceContext: {
13
- workspace: {
14
- slug: "workspace-resolved"
15
- }
16
- },
17
- request: {
18
- input: {
19
- params: {
20
- workspaceSlug: "workspace-request"
21
- }
22
- }
23
- }
24
- }
25
- },
26
- {
27
- workspaceSlug: "workspace-input"
28
- }
29
- );
30
-
31
- assert.equal(slug, "workspace-primary");
32
- });
33
-
34
- test("resolveWorkspaceSlug resolves from requestMeta resolved workspace", () => {
35
- const slug = resolveWorkspaceSlug({
36
- requestMeta: {
37
- resolvedWorkspaceContext: {
38
- workspace: {
39
- slug: "workspace-resolved"
40
- }
41
- }
42
- }
43
- });
44
-
45
- assert.equal(slug, "workspace-resolved");
46
- });
47
-
48
- test("resolveWorkspaceSlug resolves from action input before request params", () => {
49
- const slug = resolveWorkspaceSlug(
50
- {
51
- requestMeta: {
52
- request: {
53
- input: {
54
- params: {
55
- workspaceSlug: "workspace-request"
56
- }
57
- }
58
- }
59
- }
60
- },
61
- {
62
- workspaceSlug: "workspace-input"
63
- }
64
- );
65
-
66
- assert.equal(slug, "workspace-input");
67
- });
68
-
69
- test("resolveWorkspaceSlug resolves from request params when needed", () => {
70
- const slug = resolveWorkspaceSlug({
71
- requestMeta: {
72
- request: {
73
- input: {
74
- params: {
75
- workspaceSlug: "workspace-request"
76
- }
77
- }
78
- }
79
- }
80
- });
81
-
82
- assert.equal(slug, "workspace-request");
83
- });
@@ -1,286 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { registerRoutes } from "../src/server/registerRoutes.js";
4
-
5
- function createReplyDouble() {
6
- return {
7
- statusCode: 200,
8
- payload: null,
9
- code(statusCode) {
10
- this.statusCode = statusCode;
11
- return this;
12
- },
13
- send(payload) {
14
- this.payload = payload;
15
- return this;
16
- }
17
- };
18
- }
19
-
20
- function findRoute(routes, method, path) {
21
- return routes.find((route) => route.method === method && route.path === path) || null;
22
- }
23
-
24
- test("assistant routes build list inputs with explicit query object", async () => {
25
- const registeredRoutes = [];
26
- const router = {
27
- register(method, path, route, handler) {
28
- registeredRoutes.push({
29
- method,
30
- path,
31
- route,
32
- handler
33
- });
34
- }
35
- };
36
- const app = {
37
- make(token) {
38
- if (token !== "jskit.http.router") {
39
- throw new Error(`Unexpected token: ${String(token)}`);
40
- }
41
- return router;
42
- }
43
- };
44
-
45
- registerRoutes(app);
46
-
47
- const conversationsRoute = findRoute(registeredRoutes, "GET", "/api/w/:workspaceSlug/assistant/conversations");
48
- const messagesRoute = findRoute(
49
- registeredRoutes,
50
- "GET",
51
- "/api/w/:workspaceSlug/assistant/conversations/:conversationId/messages"
52
- );
53
- const consoleSettingsReadRoute = findRoute(registeredRoutes, "GET", "/api/console/settings/assistant");
54
- const consoleSettingsPatchRoute = findRoute(registeredRoutes, "PATCH", "/api/console/settings/assistant");
55
- const workspaceSettingsReadRoute = findRoute(
56
- registeredRoutes,
57
- "GET",
58
- "/api/w/:workspaceSlug/settings/assistant"
59
- );
60
- const workspaceSettingsPatchRoute = findRoute(
61
- registeredRoutes,
62
- "PATCH",
63
- "/api/w/:workspaceSlug/settings/assistant"
64
- );
65
- assert.ok(conversationsRoute);
66
- assert.ok(messagesRoute);
67
- assert.ok(consoleSettingsReadRoute);
68
- assert.ok(consoleSettingsPatchRoute);
69
- assert.ok(workspaceSettingsReadRoute);
70
- assert.ok(workspaceSettingsPatchRoute);
71
-
72
- const calls = [];
73
- const executeAction = async (payload) => {
74
- calls.push(payload);
75
- return {};
76
- };
77
-
78
- await conversationsRoute.handler(
79
- {
80
- input: {
81
- params: { workspaceSlug: "acme" },
82
- query: { cursor: 30, limit: 50, status: "active" }
83
- },
84
- executeAction
85
- },
86
- createReplyDouble()
87
- );
88
- await messagesRoute.handler(
89
- {
90
- input: {
91
- params: { workspaceSlug: "acme", conversationId: 10 },
92
- query: { page: 3, pageSize: 100 }
93
- },
94
- executeAction
95
- },
96
- createReplyDouble()
97
- );
98
- await consoleSettingsReadRoute.handler(
99
- {
100
- input: {},
101
- executeAction
102
- },
103
- createReplyDouble()
104
- );
105
- await consoleSettingsPatchRoute.handler(
106
- {
107
- input: {
108
- body: { workspaceSurfacePrompt: "Console prompt" }
109
- },
110
- executeAction
111
- },
112
- createReplyDouble()
113
- );
114
- await workspaceSettingsReadRoute.handler(
115
- {
116
- input: {
117
- params: { workspaceSlug: "acme" }
118
- },
119
- executeAction
120
- },
121
- createReplyDouble()
122
- );
123
- await workspaceSettingsPatchRoute.handler(
124
- {
125
- input: {
126
- params: { workspaceSlug: "acme" },
127
- body: { appSurfacePrompt: "Workspace prompt" }
128
- },
129
- executeAction
130
- },
131
- createReplyDouble()
132
- );
133
-
134
- assert.deepEqual(calls[0].input, {
135
- workspaceSlug: "acme",
136
- query: { cursor: 30, limit: 50, status: "active" }
137
- });
138
- assert.deepEqual(calls[0].context, {
139
- surface: "app"
140
- });
141
- assert.deepEqual(calls[1].input, {
142
- workspaceSlug: "acme",
143
- conversationId: 10,
144
- query: { page: 3, pageSize: 100 }
145
- });
146
- assert.deepEqual(calls[1].context, {
147
- surface: "app"
148
- });
149
- assert.deepEqual(calls[2], {
150
- actionId: "assistant.console.settings.read"
151
- });
152
- assert.deepEqual(calls[3], {
153
- actionId: "assistant.console.settings.update",
154
- input: {
155
- payload: {
156
- workspaceSurfacePrompt: "Console prompt"
157
- }
158
- }
159
- });
160
- assert.deepEqual(calls[4], {
161
- actionId: "assistant.workspace.settings.read",
162
- context: {
163
- surface: "app"
164
- },
165
- input: {
166
- workspaceSlug: "acme"
167
- }
168
- });
169
- assert.deepEqual(calls[5], {
170
- actionId: "assistant.workspace.settings.update",
171
- context: {
172
- surface: "app"
173
- },
174
- input: {
175
- workspaceSlug: "acme",
176
- patch: {
177
- appSurfacePrompt: "Workspace prompt"
178
- }
179
- }
180
- });
181
- });
182
-
183
- test("assistant workspace routes use workspace default surface and honor x-jskit-surface header", async () => {
184
- const registeredRoutes = [];
185
- const router = {
186
- register(method, path, route, handler) {
187
- registeredRoutes.push({
188
- method,
189
- path,
190
- route,
191
- handler
192
- });
193
- }
194
- };
195
- const app = {
196
- has(token) {
197
- return token === "appConfig";
198
- },
199
- make(token) {
200
- if (token === "jskit.http.router") {
201
- return router;
202
- }
203
- if (token === "appConfig") {
204
- return {
205
- surfaceDefaultId: "admin",
206
- surfaceDefinitions: {
207
- app: {
208
- id: "app",
209
- enabled: true,
210
- requiresWorkspace: true
211
- },
212
- admin: {
213
- id: "admin",
214
- enabled: true,
215
- requiresWorkspace: true
216
- },
217
- console: {
218
- id: "console",
219
- enabled: true,
220
- requiresWorkspace: false
221
- }
222
- }
223
- };
224
- }
225
- throw new Error(`Unexpected token: ${String(token)}`);
226
- }
227
- };
228
-
229
- registerRoutes(app);
230
-
231
- const expectedWorkspaceRoutes = [
232
- ["GET", "/api/w/:workspaceSlug/settings/assistant"],
233
- ["PATCH", "/api/w/:workspaceSlug/settings/assistant"],
234
- ["POST", "/api/w/:workspaceSlug/assistant/chat/stream"],
235
- ["GET", "/api/w/:workspaceSlug/assistant/conversations"],
236
- ["GET", "/api/w/:workspaceSlug/assistant/conversations/:conversationId/messages"]
237
- ];
238
-
239
- for (const [method, path] of expectedWorkspaceRoutes) {
240
- const route = findRoute(registeredRoutes, method, path);
241
- assert.ok(route);
242
- assert.equal(route.route.surface, "admin");
243
- }
244
-
245
- const conversationsRoute = findRoute(registeredRoutes, "GET", "/api/w/:workspaceSlug/assistant/conversations");
246
- const actionCalls = [];
247
- const executeAction = async (payload) => {
248
- actionCalls.push(payload);
249
- return {};
250
- };
251
-
252
- await conversationsRoute.handler(
253
- {
254
- headers: {
255
- "x-jskit-surface": "app"
256
- },
257
- input: {
258
- params: { workspaceSlug: "acme" },
259
- query: {}
260
- },
261
- executeAction
262
- },
263
- createReplyDouble()
264
- );
265
- await conversationsRoute.handler(
266
- {
267
- headers: {
268
- "x-jskit-surface": "missing"
269
- },
270
- input: {
271
- params: { workspaceSlug: "acme" },
272
- query: {}
273
- },
274
- executeAction
275
- },
276
- createReplyDouble()
277
- );
278
-
279
- assert.equal(actionCalls.length, 2);
280
- assert.deepEqual(actionCalls[0].context, {
281
- surface: "app"
282
- });
283
- assert.deepEqual(actionCalls[1].context, {
284
- surface: "admin"
285
- });
286
- });