@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
@@ -2,24 +2,27 @@ import { computed, ref, watch } from "vue";
2
2
  import { useQueryClient } from "@tanstack/vue-query";
3
3
  import { getClientAppConfig } from "@jskit-ai/kernel/client";
4
4
  import { normalizeObject, normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
5
- import { useRealtimeEvent } from "@jskit-ai/realtime/client/composables/useRealtimeEvent";
6
- import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
7
- import { useWorkspaceRouteContext } from "@jskit-ai/users-web/client/composables/useWorkspaceRouteContext";
8
- import { usePagedCollection } from "@jskit-ai/users-web/client/composables/usePagedCollection";
5
+ import { buildAssistantApiPath } from "@jskit-ai/assistant-core/shared";
9
6
  import {
10
- MAX_INPUT_CHARS,
11
7
  ASSISTANT_STREAM_EVENT_TYPES,
12
8
  MAX_HISTORY_MESSAGES,
9
+ MAX_INPUT_CHARS,
13
10
  assistantConversationMessagesQueryKey,
14
11
  assistantConversationsListQueryKey,
15
- assistantWorkspaceScopeQueryKey,
12
+ assistantScopeQueryKey,
16
13
  normalizeAssistantStreamEventType,
17
14
  normalizeConversationStatus as normalizeAssistantConversationStatus,
18
15
  parseJsonObject,
19
16
  toPositiveInteger
20
- } from "../../shared/index.js";
21
- import { assistantHttpClient } from "../lib/assistantHttpClient.js";
22
- import { createAssistantWorkspaceApi } from "../lib/assistantApi.js";
17
+ } from "@jskit-ai/assistant-core/shared";
18
+ import {
19
+ assistantHttpClient,
20
+ createAssistantApi
21
+ } from "@jskit-ai/assistant-core/client";
22
+ import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
23
+ import { usePagedCollection } from "@jskit-ai/users-web/client/composables/usePagedCollection";
24
+ import { useWorkspaceRouteContext } from "@jskit-ai/users-web/client/composables/useWorkspaceRouteContext";
25
+ import { assistantRuntimeConfig } from "../../shared/assistantRuntimeConfig.js";
23
26
 
24
27
  const DEFAULT_STREAM_TIMEOUT_MS = 120_000;
25
28
  const DEFAULT_HISTORY_PAGE_SIZE = 20;
@@ -36,43 +39,31 @@ function toNonNegativeInteger(value, fallback = 0) {
36
39
  return parsed;
37
40
  }
38
41
 
39
- function buildActiveConversationStorageKey(workspaceSlug) {
40
- const normalizedWorkspaceSlug = normalizeText(workspaceSlug);
41
- if (!normalizedWorkspaceSlug) {
42
- return "";
43
- }
44
-
45
- return `assistant.activeConversationId:${normalizedWorkspaceSlug}`;
42
+ function buildScopeStorageKey(scope = {}) {
43
+ const runtimeSurfaceId = normalizeText(scope?.targetSurfaceId).toLowerCase() || "assistant";
44
+ const workspaceSlug = normalizeText(scope?.workspaceSlug).toLowerCase() || "global";
45
+ return `assistant.activeConversationId:${runtimeSurfaceId}:${workspaceSlug}`;
46
46
  }
47
47
 
48
- function readStoredActiveConversationId(workspaceSlug) {
48
+ function readStoredActiveConversationId(scope = {}) {
49
49
  if (typeof window === "undefined" || !window.sessionStorage) {
50
50
  return 0;
51
51
  }
52
52
 
53
- const storageKey = buildActiveConversationStorageKey(workspaceSlug);
54
- if (!storageKey) {
55
- return 0;
56
- }
57
-
58
53
  try {
59
- return toPositiveInteger(window.sessionStorage.getItem(storageKey), 0);
54
+ return toPositiveInteger(window.sessionStorage.getItem(buildScopeStorageKey(scope)), 0);
60
55
  } catch {
61
56
  return 0;
62
57
  }
63
58
  }
64
59
 
65
- function writeStoredActiveConversationId(workspaceSlug, conversationId) {
60
+ function writeStoredActiveConversationId(scope = {}, conversationId) {
66
61
  if (typeof window === "undefined" || !window.sessionStorage) {
67
62
  return;
68
63
  }
69
64
 
70
- const storageKey = buildActiveConversationStorageKey(workspaceSlug);
71
- if (!storageKey) {
72
- return;
73
- }
74
-
75
65
  const normalizedConversationId = toPositiveInteger(conversationId, 0);
66
+ const storageKey = buildScopeStorageKey(scope);
76
67
  try {
77
68
  if (normalizedConversationId > 0) {
78
69
  window.sessionStorage.setItem(storageKey, String(normalizedConversationId));
@@ -213,19 +204,6 @@ function mapTranscriptEntriesToAssistantState(entries) {
213
204
  };
214
205
  }
215
206
 
216
- function resolveWorkspaceScope(bootstrapData = {}, workspaceSlug = "") {
217
- const activeWorkspace = bootstrapData?.workspace && typeof bootstrapData.workspace === "object"
218
- ? bootstrapData.workspace
219
- : bootstrapData?.activeWorkspace && typeof bootstrapData.activeWorkspace === "object"
220
- ? bootstrapData.activeWorkspace
221
- : null;
222
-
223
- return {
224
- workspaceSlug: normalizeText(workspaceSlug),
225
- workspaceId: toPositiveInteger(activeWorkspace?.id, 0)
226
- };
227
- }
228
-
229
207
  function resolveRuntimePolicy() {
230
208
  const appConfig = getClientAppConfig();
231
209
  const assistantConfig = normalizeObject(appConfig?.assistant);
@@ -238,27 +216,24 @@ function resolveRuntimePolicy() {
238
216
  });
239
217
  }
240
218
 
241
- function createRuntimeApi({ overrideApi = null, resolveSurfaceId = null } = {}) {
219
+ function createRuntimeApi({ overrideApi = null, resolveBasePath, resolveSurfaceId = null } = {}) {
242
220
  if (overrideApi && typeof overrideApi.streamChat === "function") {
243
221
  return overrideApi;
244
222
  }
245
223
 
246
- return createAssistantWorkspaceApi({
224
+ return createAssistantApi({
247
225
  request: assistantHttpClient.request,
248
226
  requestStream: assistantHttpClient.requestStream,
227
+ resolveBasePath,
249
228
  resolveSurfaceId
250
229
  });
251
230
  }
252
231
 
253
- function useAssistantWorkspaceRuntime({ api = null } = {}) {
232
+ function useAssistantRuntime({ api = null } = {}) {
254
233
  const runtimePolicy = resolveRuntimePolicy();
255
234
  const queryClient = useQueryClient();
256
235
  const errorRuntime = useShellWebErrorRuntime();
257
- const { workspaceSlugFromRoute, currentSurfaceId, placementContext } = useWorkspaceRouteContext();
258
- const runtimeApi = createRuntimeApi({
259
- overrideApi: api,
260
- resolveSurfaceId: () => normalizeText(currentSurfaceId.value).toLowerCase()
261
- });
236
+ const { placementContext, currentSurfaceId, workspaceSlugFromRoute } = useWorkspaceRouteContext();
262
237
 
263
238
  const messages = ref([]);
264
239
  const input = ref("");
@@ -270,12 +245,45 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
270
245
  const abortController = ref(null);
271
246
 
272
247
  const placementSnapshot = computed(() => normalizeObject(placementContext.value));
273
- const workspaceScope = computed(() => resolveWorkspaceScope(placementSnapshot.value, workspaceSlugFromRoute.value));
274
- const hasWorkspaceScope = computed(() => Boolean(workspaceScope.value.workspaceSlug));
248
+ const runtimeScope = computed(() => {
249
+ const workspaceSlug = assistantRuntimeConfig.runtimeSurfaceRequiresWorkspace
250
+ ? normalizeText(workspaceSlugFromRoute.value).toLowerCase()
251
+ : "";
252
+
253
+ return {
254
+ targetSurfaceId: assistantRuntimeConfig.runtimeSurfaceId,
255
+ workspaceSlug,
256
+ workspaceId: assistantRuntimeConfig.runtimeSurfaceRequiresWorkspace
257
+ ? toPositiveInteger(placementSnapshot.value?.workspace?.id, 0)
258
+ : 0
259
+ };
260
+ });
261
+ const hasRuntimeScope = computed(() =>
262
+ assistantRuntimeConfig.runtimeSurfaceRequiresWorkspace ? Boolean(runtimeScope.value.workspaceSlug) : true
263
+ );
264
+
265
+ const runtimeApi = createRuntimeApi({
266
+ overrideApi: api,
267
+ resolveBasePath: () =>
268
+ buildAssistantApiPath({
269
+ requiresWorkspace: assistantRuntimeConfig.runtimeSurfaceRequiresWorkspace,
270
+ workspaceSlug: runtimeScope.value.workspaceSlug,
271
+ suffix: "/"
272
+ }),
273
+ resolveSurfaceId: () => normalizeText(currentSurfaceId.value).toLowerCase()
274
+ });
275
+
275
276
  const activeConversationId = computed(() => normalizeText(conversationId.value));
276
- const isAdminSurface = computed(() => currentSurfaceId.value === "admin");
277
- const canSend = computed(() => !isStreaming.value && !isRestoringConversation.value && Boolean(normalizeText(input.value)));
278
- const canStartNewConversation = computed(() => !isStreaming.value);
277
+ const isAdminSurface = computed(() => normalizeText(currentSurfaceId.value).toLowerCase() === "admin");
278
+ const canSend = computed(() => {
279
+ return Boolean(
280
+ hasRuntimeScope.value &&
281
+ !isStreaming.value &&
282
+ !isRestoringConversation.value &&
283
+ normalizeText(input.value)
284
+ );
285
+ });
286
+ const canStartNewConversation = computed(() => Boolean(hasRuntimeScope.value && !isStreaming.value));
279
287
 
280
288
  function setRuntimeError(message, dedupeKey = "") {
281
289
  const normalizedMessage = normalizeText(message);
@@ -285,23 +293,23 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
285
293
  }
286
294
 
287
295
  errorRuntime.report({
288
- source: "assistant.workspace-runtime",
296
+ source: "assistant.runtime",
289
297
  message: normalizedMessage,
290
298
  severity: "error",
291
299
  channel: "banner",
292
- dedupeKey: dedupeKey || `assistant.workspace-runtime:error:${normalizedMessage}`,
300
+ dedupeKey: dedupeKey || `assistant.runtime:error:${normalizedMessage}`,
293
301
  dedupeWindowMs: 3000
294
302
  });
295
303
  }
296
304
 
297
305
  const conversationHistoryCollection = usePagedCollection({
298
306
  queryKey: computed(() =>
299
- assistantConversationsListQueryKey(workspaceScope.value, {
307
+ assistantConversationsListQueryKey(runtimeScope.value, {
300
308
  limit: runtimePolicy.historyPageSize
301
309
  })
302
310
  ),
303
311
  queryFn: ({ pageParam = null }) =>
304
- runtimeApi.listConversations(workspaceScope.value.workspaceSlug, {
312
+ runtimeApi.listConversations({
305
313
  cursor: pageParam,
306
314
  limit: runtimePolicy.historyPageSize
307
315
  }),
@@ -310,7 +318,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
310
318
  const conversationNumericId = toPositiveInteger(entry?.id, 0);
311
319
  return conversationNumericId > 0 ? String(conversationNumericId) : normalizeText(entry?.id);
312
320
  },
313
- enabled: computed(() => hasWorkspaceScope.value),
321
+ enabled: computed(() => hasRuntimeScope.value),
314
322
  queryOptions: {
315
323
  staleTime: runtimePolicy.historyStaleTimeMs,
316
324
  refetchOnMount: false,
@@ -328,46 +336,45 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
328
336
  const conversationHistoryError = conversationHistoryCollection.loadError;
329
337
 
330
338
  watch(conversationId, (nextConversationId, previousConversationId) => {
331
- const workspaceSlug = workspaceScope.value.workspaceSlug;
332
- if (!workspaceSlug) {
339
+ if (!hasRuntimeScope.value) {
333
340
  return;
334
341
  }
335
342
 
336
343
  const nextConversationNumericId = toPositiveInteger(nextConversationId, 0);
337
344
  if (nextConversationNumericId > 0) {
338
- writeStoredActiveConversationId(workspaceSlug, nextConversationNumericId);
345
+ writeStoredActiveConversationId(runtimeScope.value, nextConversationNumericId);
339
346
  return;
340
347
  }
341
348
 
342
349
  const previousConversationNumericId = toPositiveInteger(previousConversationId, 0);
343
350
  if (previousConversationNumericId > 0) {
344
- writeStoredActiveConversationId(workspaceSlug, 0);
351
+ writeStoredActiveConversationId(runtimeScope.value, 0);
345
352
  }
346
353
  });
347
354
 
348
355
  watch(
349
356
  [
350
- hasWorkspaceScope,
357
+ hasRuntimeScope,
351
358
  conversationHistoryLoading,
352
- workspaceScope,
359
+ runtimeScope,
353
360
  conversationId,
354
361
  conversationHistory,
355
362
  isRestoringConversation
356
363
  ],
357
364
  async ([
358
- nextHasWorkspaceScope,
365
+ nextHasRuntimeScope,
359
366
  nextConversationHistoryLoading,
360
- nextWorkspaceScope,
367
+ nextRuntimeScope,
361
368
  nextConversationId,
362
369
  nextConversationHistory,
363
370
  nextIsRestoringConversation
364
371
  ]) => {
365
- if (!nextHasWorkspaceScope || nextConversationHistoryLoading || nextIsRestoringConversation) {
372
+ if (!nextHasRuntimeScope || nextConversationHistoryLoading || nextIsRestoringConversation) {
366
373
  return;
367
374
  }
368
375
 
369
- const activeConversationId = toPositiveInteger(nextConversationId, 0);
370
- if (activeConversationId > 0) {
376
+ const activeConversationNumericId = toPositiveInteger(nextConversationId, 0);
377
+ if (activeConversationNumericId > 0) {
371
378
  return;
372
379
  }
373
380
 
@@ -376,7 +383,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
376
383
  return;
377
384
  }
378
385
 
379
- const storedConversationId = readStoredActiveConversationId(nextWorkspaceScope?.workspaceSlug);
386
+ const storedConversationId = readStoredActiveConversationId(nextRuntimeScope);
380
387
  if (!storedConversationId) {
381
388
  return;
382
389
  }
@@ -385,7 +392,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
385
392
  (entry) => toPositiveInteger(entry?.id, 0) === storedConversationId
386
393
  );
387
394
  if (!hasStoredConversation) {
388
- writeStoredActiveConversationId(nextWorkspaceScope?.workspaceSlug, 0);
395
+ writeStoredActiveConversationId(nextRuntimeScope, 0);
389
396
  return;
390
397
  }
391
398
 
@@ -419,17 +426,17 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
419
426
  }
420
427
 
421
428
  async function invalidateConversationScope() {
422
- if (!hasWorkspaceScope.value) {
429
+ if (!hasRuntimeScope.value) {
423
430
  return;
424
431
  }
425
432
 
426
433
  await queryClient.invalidateQueries({
427
- queryKey: assistantWorkspaceScopeQueryKey(workspaceScope.value)
434
+ queryKey: assistantScopeQueryKey(runtimeScope.value)
428
435
  });
429
436
  }
430
437
 
431
438
  async function refreshConversationHistory() {
432
- if (!hasWorkspaceScope.value) {
439
+ if (!hasRuntimeScope.value) {
433
440
  return;
434
441
  }
435
442
 
@@ -442,7 +449,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
442
449
 
443
450
  async function selectConversationById(nextConversationId) {
444
451
  const normalizedConversationId = normalizeText(nextConversationId);
445
- if (!normalizedConversationId || isStreaming.value || isRestoringConversation.value || !hasWorkspaceScope.value) {
452
+ if (!normalizedConversationId || isStreaming.value || isRestoringConversation.value || !hasRuntimeScope.value) {
446
453
  return;
447
454
  }
448
455
 
@@ -458,12 +465,12 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
458
465
 
459
466
  try {
460
467
  const response = await queryClient.fetchQuery({
461
- queryKey: assistantConversationMessagesQueryKey(workspaceScope.value, parsedConversationId, {
468
+ queryKey: assistantConversationMessagesQueryKey(runtimeScope.value, parsedConversationId, {
462
469
  page: RESTORE_MESSAGES_PAGE,
463
470
  pageSize: runtimePolicy.restoreMessagesPageSize
464
471
  }),
465
472
  queryFn: () =>
466
- runtimeApi.getConversationMessages(workspaceScope.value.workspaceSlug, parsedConversationId, {
473
+ runtimeApi.getConversationMessages(parsedConversationId, {
467
474
  page: RESTORE_MESSAGES_PAGE,
468
475
  pageSize: runtimePolicy.restoreMessagesPageSize
469
476
  })
@@ -495,7 +502,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
495
502
  input.value = "";
496
503
  setRuntimeError("");
497
504
  conversationId.value = null;
498
- writeStoredActiveConversationId(workspaceScope.value.workspaceSlug, 0);
505
+ writeStoredActiveConversationId(runtimeScope.value, 0);
499
506
  isStreaming.value = false;
500
507
  isRestoringConversation.value = false;
501
508
  abortController.value = null;
@@ -527,7 +534,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
527
534
 
528
535
  async function sendMessage() {
529
536
  const normalizedInput = normalizeText(input.value).slice(0, MAX_INPUT_CHARS);
530
- if (!normalizedInput || isStreaming.value || isRestoringConversation.value || !hasWorkspaceScope.value) {
537
+ if (!normalizedInput || isStreaming.value || isRestoringConversation.value || !hasRuntimeScope.value) {
531
538
  return;
532
539
  }
533
540
 
@@ -567,7 +574,6 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
567
574
 
568
575
  try {
569
576
  await runtimeApi.streamChat(
570
- workspaceScope.value.workspaceSlug,
571
577
  {
572
578
  messageId,
573
579
  ...(parsedConversationId > 0 ? { conversationId: parsedConversationId } : {}),
@@ -645,7 +651,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
645
651
  if (eventType === ASSISTANT_STREAM_EVENT_TYPES.ERROR) {
646
652
  setRuntimeError(
647
653
  normalizeText(event?.message) || "Assistant request failed.",
648
- "assistant.workspace-runtime:stream-event-error"
654
+ "assistant.runtime:stream-event-error"
649
655
  );
650
656
  updateMessage(assistantMessageId, {
651
657
  status: "error"
@@ -664,7 +670,7 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
664
670
  const assistantMessageText = normalizeText(assistantMessage?.text);
665
671
  if (!assistantMessageText && streamDoneStatus !== "aborted") {
666
672
  if (!error.value) {
667
- setRuntimeError("Assistant returned no output.", "assistant.workspace-runtime:empty-output");
673
+ setRuntimeError("Assistant returned no output.", "assistant.runtime:empty-output");
668
674
  }
669
675
  updateMessage(assistantMessageId, {
670
676
  status: "error"
@@ -698,35 +704,6 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
698
704
  }
699
705
  }
700
706
 
701
- useRealtimeEvent({
702
- event: "assistant.transcript.changed",
703
- enabled: computed(() => hasWorkspaceScope.value),
704
- matches({ payload }) {
705
- if (!payload || typeof payload !== "object") {
706
- return true;
707
- }
708
-
709
- const scope = payload.scope && typeof payload.scope === "object" ? payload.scope : {};
710
- const workspaceIdFromEvent = toPositiveInteger(scope.id || scope.workspaceId, 0);
711
- const workspaceId = toPositiveInteger(workspaceScope.value.workspaceId, 0);
712
- if (workspaceIdFromEvent > 0 && workspaceId > 0) {
713
- return workspaceIdFromEvent === workspaceId;
714
- }
715
-
716
- return true;
717
- },
718
- async onEvent({ payload }) {
719
- await invalidateConversationScope();
720
- const incomingConversationId = toPositiveInteger(payload?.conversationId, 0);
721
- const activeId = toPositiveInteger(conversationId.value, 0);
722
- if (!incomingConversationId || incomingConversationId !== activeId || !activeId) {
723
- return;
724
- }
725
-
726
- await selectConversationById(activeId);
727
- }
728
- });
729
-
730
707
  const viewer = computed(() => {
731
708
  const user = normalizeObject(placementSnapshot.value.user);
732
709
 
@@ -774,4 +751,4 @@ function useAssistantWorkspaceRuntime({ api = null } = {}) {
774
751
  });
775
752
  }
776
753
 
777
- export { useAssistantWorkspaceRuntime };
754
+ export { useAssistantRuntime };
@@ -0,0 +1,3 @@
1
+ export { default as AssistantSurfaceClientElement } from "./components/AssistantSurfaceClientElement.vue";
2
+ export { default as AssistantSettingsClientElement } from "./components/AssistantSettingsClientElement.vue";
3
+ export { useAssistantRuntime } from "./composables/useAssistantRuntime.js";
@@ -0,0 +1,16 @@
1
+ import AssistantSettingsClientElement from "../components/AssistantSettingsClientElement.vue";
2
+
3
+ class AssistantClientProvider {
4
+ static id = "assistant.web.client";
5
+ static dependsOn = ["users.web.client"];
6
+
7
+ register(app) {
8
+ if (!app || typeof app.singleton !== "function") {
9
+ throw new Error("AssistantClientProvider requires application singleton().");
10
+ }
11
+
12
+ app.singleton("assistant.web.settings.element", () => AssistantSettingsClientElement);
13
+ }
14
+ }
15
+
16
+ export { AssistantClientProvider };
@@ -0,0 +1,85 @@
1
+ export default Object.freeze({
2
+ packageVersion: 1,
3
+ packageId: "@local/assistant",
4
+ version: "0.1.0",
5
+ kind: "runtime",
6
+ description: "App-local generated assistant runtime.",
7
+ dependsOn: [
8
+ "@jskit-ai/assistant-core",
9
+ "@jskit-ai/database-runtime",
10
+ "@jskit-ai/http-runtime",
11
+ "@jskit-ai/shell-web",
12
+ "@jskit-ai/users-core",
13
+ "@jskit-ai/users-web"
14
+ ],
15
+ capabilities: {
16
+ provides: ["assistant.runtime"],
17
+ requires: [
18
+ "runtime.actions",
19
+ "runtime.database",
20
+ "auth.policy",
21
+ "runtime.http-client",
22
+ "users.core",
23
+ "users.web"
24
+ ]
25
+ },
26
+ runtime: {
27
+ server: {
28
+ providers: [
29
+ {
30
+ entrypoint: "src/server/AssistantProvider.js",
31
+ export: "AssistantProvider"
32
+ }
33
+ ]
34
+ },
35
+ client: {
36
+ providers: [
37
+ {
38
+ entrypoint: "src/client/providers/AssistantClientProvider.js",
39
+ export: "AssistantClientProvider"
40
+ }
41
+ ]
42
+ }
43
+ },
44
+ metadata: {
45
+ apiSummary: {
46
+ surfaces: [
47
+ {
48
+ subpath: "./server/actionIds",
49
+ summary: "Generated assistant action identifiers."
50
+ },
51
+ {
52
+ subpath: "./client",
53
+ summary: "Generated assistant client wrappers."
54
+ },
55
+ {
56
+ subpath: "./shared",
57
+ summary: "Generated assistant runtime configuration."
58
+ }
59
+ ],
60
+ containerTokens: {
61
+ server: [
62
+ "assistant.config.repository",
63
+ "assistant.conversation.repository",
64
+ "assistant.message.repository",
65
+ "assistant.ai.client",
66
+ "assistant.service.tool-catalog"
67
+ ],
68
+ client: [
69
+ "assistant.web.settings.element"
70
+ ]
71
+ }
72
+ }
73
+ },
74
+ mutations: {
75
+ dependencies: {
76
+ runtime: {},
77
+ dev: {}
78
+ },
79
+ packageJson: {
80
+ scripts: {}
81
+ },
82
+ procfile: {},
83
+ files: []
84
+ }
85
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@local/assistant",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ "./client": "./src/client/index.js",
8
+ "./shared": "./src/shared/index.js",
9
+ "./server/actionIds": "./src/server/actionIds.js"
10
+ }
11
+ }