@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,29 +0,0 @@
1
- const ASSISTANT_STREAM_EVENT_TYPES = Object.freeze({
2
- META: "meta",
3
- ASSISTANT_DELTA: "assistant_delta",
4
- ASSISTANT_MESSAGE: "assistant_message",
5
- TOOL_CALL: "tool_call",
6
- TOOL_RESULT: "tool_result",
7
- ERROR: "error",
8
- DONE: "done"
9
- });
10
-
11
- const STREAM_EVENT_TYPE_SET = new Set(Object.values(ASSISTANT_STREAM_EVENT_TYPES));
12
-
13
- function normalizeAssistantStreamEventType(value, fallback = "") {
14
- const normalized = String(value || "").trim().toLowerCase();
15
- if (!normalized) {
16
- return fallback;
17
- }
18
-
19
- if (!STREAM_EVENT_TYPE_SET.has(normalized)) {
20
- return fallback;
21
- }
22
-
23
- return normalized;
24
- }
25
-
26
- export {
27
- ASSISTANT_STREAM_EVENT_TYPES,
28
- normalizeAssistantStreamEventType
29
- };
@@ -1,18 +0,0 @@
1
- import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
2
-
3
- const ASSISTANT_CONVERSATION_STATUSES = Object.freeze(["active", "completed", "failed", "aborted"]);
4
- const ASSISTANT_CONVERSATION_STATUS_SET = new Set(ASSISTANT_CONVERSATION_STATUSES);
5
-
6
- function normalizeConversationStatus(value, { fallback = "" } = {}) {
7
- const normalized = normalizeText(value).toLowerCase();
8
- if (ASSISTANT_CONVERSATION_STATUS_SET.has(normalized)) {
9
- return normalized;
10
- }
11
-
12
- return normalizeText(fallback).toLowerCase();
13
- }
14
-
15
- export {
16
- ASSISTANT_CONVERSATION_STATUSES,
17
- normalizeConversationStatus
18
- };
@@ -1,18 +0,0 @@
1
- function parseJsonObject(value) {
2
- if (value == null) {
3
- return {};
4
- }
5
-
6
- try {
7
- const parsed = typeof value === "string" ? JSON.parse(value) : value;
8
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
9
- return {};
10
- }
11
-
12
- return parsed;
13
- } catch {
14
- return {};
15
- }
16
- }
17
-
18
- export { parseJsonObject };
@@ -1,9 +0,0 @@
1
- import { normalizePositiveInteger } from "@jskit-ai/kernel/shared/support/normalize";
2
-
3
- function toPositiveInteger(value, fallback = 0) {
4
- return normalizePositiveInteger(value, {
5
- fallback
6
- });
7
- }
8
-
9
- export { toPositiveInteger };
@@ -1,37 +0,0 @@
1
- /**
2
- * @param {import('knex').Knex} knex
3
- */
4
- exports.up = async function up(knex) {
5
- const hasConsolePromptColumn = await knex.schema.hasColumn("console_settings", "assistant_workspace_surface_prompt");
6
- if (!hasConsolePromptColumn) {
7
- await knex.schema.alterTable("console_settings", (table) => {
8
- table.text("assistant_workspace_surface_prompt").notNullable().defaultTo("");
9
- });
10
- }
11
-
12
- const hasWorkspacePromptColumn = await knex.schema.hasColumn("workspace_settings", "assistant_app_surface_prompt");
13
- if (!hasWorkspacePromptColumn) {
14
- await knex.schema.alterTable("workspace_settings", (table) => {
15
- table.text("assistant_app_surface_prompt").notNullable().defaultTo("");
16
- });
17
- }
18
- };
19
-
20
- /**
21
- * @param {import('knex').Knex} knex
22
- */
23
- exports.down = async function down(knex) {
24
- const hasWorkspacePromptColumn = await knex.schema.hasColumn("workspace_settings", "assistant_app_surface_prompt");
25
- if (hasWorkspacePromptColumn) {
26
- await knex.schema.alterTable("workspace_settings", (table) => {
27
- table.dropColumn("assistant_app_surface_prompt");
28
- });
29
- }
30
-
31
- const hasConsolePromptColumn = await knex.schema.hasColumn("console_settings", "assistant_workspace_surface_prompt");
32
- if (hasConsolePromptColumn) {
33
- await knex.schema.alterTable("console_settings", (table) => {
34
- table.dropColumn("assistant_workspace_surface_prompt");
35
- });
36
- }
37
- };
@@ -1,7 +0,0 @@
1
- <template>
2
- <AssistantWorkspaceClientElement />
3
- </template>
4
-
5
- <script setup>
6
- import { AssistantWorkspaceClientElement } from "@jskit-ai/assistant/client";
7
- </script>
@@ -1,15 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { normalizeOptionalHttpUrl } from "../src/server/lib/providers/common.js";
4
-
5
- test("normalizeOptionalHttpUrl accepts empty values", () => {
6
- assert.equal(normalizeOptionalHttpUrl(""), "");
7
- assert.equal(normalizeOptionalHttpUrl(" "), "");
8
- });
9
-
10
- test("normalizeOptionalHttpUrl rejects non-http absolute values", () => {
11
- assert.throws(
12
- () => normalizeOptionalHttpUrl("cd ../89", { context: "assistant AI_BASE_URL" }),
13
- /assistant AI_BASE_URL must be an absolute http\(s\) URL\./
14
- );
15
- });
@@ -1,64 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { createAssistantWorkspaceApi } from "../src/client/lib/assistantApi.js";
4
-
5
- test("assistant workspace api forwards normalized surface header on requests", async () => {
6
- const observed = {
7
- stream: null,
8
- list: null,
9
- messages: null
10
- };
11
-
12
- const api = createAssistantWorkspaceApi({
13
- resolveSurfaceId: () => "AdMiN",
14
- async request(url, options = {}) {
15
- if (url.includes("/messages")) {
16
- observed.messages = { url, options };
17
- } else {
18
- observed.list = { url, options };
19
- }
20
- return {};
21
- },
22
- async requestStream(url, options = {}) {
23
- observed.stream = { url, options };
24
- return null;
25
- }
26
- });
27
-
28
- await api.streamChat("acme", {
29
- messageId: "msg_1",
30
- input: "Hello"
31
- });
32
- await api.listConversations("acme", {
33
- limit: 5
34
- });
35
- await api.getConversationMessages("acme", 99, {
36
- page: 1,
37
- pageSize: 5
38
- });
39
-
40
- assert.equal(observed.stream?.options?.headers?.["x-jskit-surface"], "admin");
41
- assert.equal(observed.list?.options?.headers?.["x-jskit-surface"], "admin");
42
- assert.equal(observed.messages?.options?.headers?.["x-jskit-surface"], "admin");
43
- });
44
-
45
- test("assistant workspace api omits surface header when surface id is empty", async () => {
46
- const observed = [];
47
- const api = createAssistantWorkspaceApi({
48
- resolveSurfaceId: () => "",
49
- async request(url, options = {}) {
50
- observed.push({
51
- url,
52
- options
53
- });
54
- return {};
55
- },
56
- async requestStream(_url, _options = {}) {
57
- return null;
58
- }
59
- });
60
-
61
- await api.listConversations("acme");
62
- assert.equal(observed.length, 1);
63
- assert.equal(Object.hasOwn(observed[0].options || {}, "headers"), false);
64
- });
@@ -1,53 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { Check } from "typebox/value";
4
- import { assistantResource } from "../src/shared/assistantResource.js";
5
-
6
- test("assistant output schemas accept normalized paginated payloads", () => {
7
- const conversationsListSchema = assistantResource.operations.conversationsList.outputValidator.schema;
8
- const conversationMessagesSchema = assistantResource.operations.conversationMessagesList.outputValidator.schema;
9
-
10
- const conversationsPayload = {
11
- items: [],
12
- nextCursor: null
13
- };
14
-
15
- const messagesPayload = {
16
- conversation: {
17
- id: 1,
18
- workspaceId: 10,
19
- workspaceSlug: "acme",
20
- workspaceName: "Acme",
21
- title: "Conversation",
22
- createdByUserId: 7,
23
- createdByUserDisplayName: "Merc",
24
- createdByUserEmail: "merc@example.com",
25
- status: "active",
26
- provider: "openai",
27
- model: "gpt-4.1",
28
- surfaceSid: "admin",
29
- startedAt: "2026-03-16T10:00:00.000Z",
30
- endedAt: null,
31
- messageCount: 2,
32
- metadata: {},
33
- createdAt: "2026-03-16T10:00:00.000Z",
34
- updatedAt: "2026-03-16T10:01:00.000Z"
35
- },
36
- entries: [],
37
- page: 1,
38
- pageSize: 200,
39
- total: 0,
40
- totalPages: 1
41
- };
42
-
43
- assert.equal(Check(conversationsListSchema, conversationsPayload), true);
44
- assert.equal(Check(conversationMessagesSchema, messagesPayload), true);
45
- });
46
-
47
- test("assistant conversation message params accept numeric path strings and normalize to integer", () => {
48
- const paramsValidator = assistantResource.operations.conversationMessagesList.paramsValidator;
49
- assert.equal(Check(paramsValidator.schema, { conversationId: "2" }), true);
50
- assert.deepEqual(paramsValidator.normalize({ conversationId: "2" }), {
51
- conversationId: 2
52
- });
53
- });
@@ -1,48 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { Check } from "typebox/value";
4
- import { validateOperationSection } from "@jskit-ai/http-runtime/shared/validators/operationValidation";
5
- import {
6
- assistantConsoleSettingsResource,
7
- assistantWorkspaceSettingsResource
8
- } from "../src/shared/assistantSettingsResource.js";
9
-
10
- test("assistant settings resources expose valid output schemas", () => {
11
- const consoleSchema = assistantConsoleSettingsResource.operations.view.outputValidator.schema;
12
- const workspaceSchema = assistantWorkspaceSettingsResource.operations.view.outputValidator.schema;
13
-
14
- assert.equal(
15
- Check(consoleSchema, {
16
- settings: {
17
- workspaceSurfacePrompt: ""
18
- }
19
- }),
20
- true
21
- );
22
- assert.equal(
23
- Check(workspaceSchema, {
24
- settings: {
25
- appSurfacePrompt: ""
26
- }
27
- }),
28
- true
29
- );
30
- });
31
-
32
- test("assistant settings patch normalizer preserves omitted fields", () => {
33
- const consolePatch = validateOperationSection({
34
- operation: assistantConsoleSettingsResource.operations.patch,
35
- section: "bodyValidator",
36
- value: {}
37
- });
38
- const workspacePatch = validateOperationSection({
39
- operation: assistantWorkspaceSettingsResource.operations.patch,
40
- section: "bodyValidator",
41
- value: {}
42
- });
43
-
44
- assert.equal(consolePatch.ok, true);
45
- assert.equal(workspacePatch.ok, true);
46
- assert.deepEqual(consolePatch.value, {});
47
- assert.deepEqual(workspacePatch.value, {});
48
- });
@@ -1,133 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { createService } from "../src/server/services/assistantSettingsService.js";
4
-
5
- function createFixture() {
6
- const calls = {
7
- requireConsoleOwner: 0,
8
- ensureConsoleSettings: 0,
9
- updateConsoleSettings: [],
10
- ensureWorkspaceSettings: [],
11
- updateWorkspaceSettings: []
12
- };
13
-
14
- const service = createService({
15
- consoleService: {
16
- async requireConsoleOwner() {
17
- calls.requireConsoleOwner += 1;
18
- }
19
- },
20
- assistantSettingsRepository: {
21
- async ensureConsoleSettings() {
22
- calls.ensureConsoleSettings += 1;
23
- return {
24
- workspaceSurfacePrompt: "Workspace prompt"
25
- };
26
- },
27
- async updateConsoleSettings(patch = {}) {
28
- calls.updateConsoleSettings.push({
29
- ...patch
30
- });
31
- return {
32
- workspaceSurfacePrompt: String(patch.workspaceSurfacePrompt || "")
33
- };
34
- },
35
- async ensureWorkspaceSettings(workspaceId) {
36
- calls.ensureWorkspaceSettings.push(workspaceId);
37
- return {
38
- workspaceId: 7,
39
- appSurfacePrompt: "App prompt"
40
- };
41
- },
42
- async updateWorkspaceSettings(workspaceId, patch = {}) {
43
- calls.updateWorkspaceSettings.push({
44
- workspaceId,
45
- patch: {
46
- ...patch
47
- }
48
- });
49
- return {
50
- workspaceId: 7,
51
- appSurfacePrompt: String(patch.appSurfacePrompt || "")
52
- };
53
- }
54
- }
55
- });
56
-
57
- return {
58
- service,
59
- calls
60
- };
61
- }
62
-
63
- test("assistantSettingsService enforces console owner on console settings reads", async () => {
64
- const { service, calls } = createFixture();
65
-
66
- const result = await service.getConsoleSettings({
67
- context: {
68
- actor: {
69
- id: 9
70
- }
71
- }
72
- });
73
-
74
- assert.equal(calls.requireConsoleOwner, 1);
75
- assert.equal(calls.ensureConsoleSettings, 1);
76
- assert.deepEqual(result, {
77
- settings: {
78
- workspaceSurfacePrompt: "Workspace prompt"
79
- }
80
- });
81
- });
82
-
83
- test("assistantSettingsService resolves prompts by surface", async () => {
84
- const { service, calls } = createFixture();
85
- const workspace = {
86
- id: 7
87
- };
88
-
89
- const appPrompt = await service.resolveSystemPrompt(workspace, {
90
- surface: "app"
91
- });
92
- const adminPrompt = await service.resolveSystemPrompt(workspace, {
93
- surface: "admin"
94
- });
95
-
96
- assert.equal(appPrompt, "App prompt");
97
- assert.equal(adminPrompt, "Workspace prompt");
98
- assert.deepEqual(calls.ensureWorkspaceSettings, [7]);
99
- assert.equal(calls.ensureConsoleSettings, 1);
100
- });
101
-
102
- test("assistantSettingsService patch updates are no-ops when prompt keys are omitted", async () => {
103
- const { service, calls } = createFixture();
104
- const workspace = {
105
- id: 7
106
- };
107
-
108
- const consoleResult = await service.updateConsoleSettings(
109
- {},
110
- {
111
- context: {
112
- actor: {
113
- id: 9
114
- }
115
- }
116
- }
117
- );
118
- const workspaceResult = await service.updateWorkspaceSettings(workspace, {});
119
-
120
- assert.equal(calls.requireConsoleOwner, 1);
121
- assert.deepEqual(calls.updateConsoleSettings, []);
122
- assert.deepEqual(calls.updateWorkspaceSettings, []);
123
- assert.deepEqual(consoleResult, {
124
- settings: {
125
- workspaceSurfacePrompt: "Workspace prompt"
126
- }
127
- });
128
- assert.deepEqual(workspaceResult, {
129
- settings: {
130
- appSurfacePrompt: "App prompt"
131
- }
132
- });
133
- });