@jskit-ai/assistant-runtime 0.1.29 → 0.1.31

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.
@@ -1,7 +1,7 @@
1
1
  export default Object.freeze({
2
2
  packageVersion: 1,
3
3
  packageId: "@jskit-ai/assistant-runtime",
4
- version: "0.1.29",
4
+ version: "0.1.31",
5
5
  kind: "runtime",
6
6
  description: "Shared assistant runtime with per-surface assistant registration.",
7
7
  dependsOn: [
@@ -74,13 +74,13 @@ export default Object.freeze({
74
74
  mutations: {
75
75
  dependencies: {
76
76
  runtime: {
77
- "@jskit-ai/assistant-core": "0.1.34",
78
- "@jskit-ai/database-runtime": "0.1.58",
79
- "@jskit-ai/http-runtime": "0.1.57",
80
- "@jskit-ai/kernel": "0.1.58",
81
- "@jskit-ai/shell-web": "0.1.57",
82
- "@jskit-ai/users-core": "0.1.68",
83
- "@jskit-ai/users-web": "0.1.73",
77
+ "@jskit-ai/assistant-core": "0.1.36",
78
+ "@jskit-ai/database-runtime": "0.1.60",
79
+ "@jskit-ai/http-runtime": "0.1.59",
80
+ "@jskit-ai/kernel": "0.1.60",
81
+ "@jskit-ai/shell-web": "0.1.59",
82
+ "@jskit-ai/users-core": "0.1.70",
83
+ "@jskit-ai/users-web": "0.1.75",
84
84
  "@tanstack/vue-query": "^5.90.5",
85
85
  "vuetify": "^4.0.0"
86
86
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/assistant-runtime",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./client": "./src/client/index.js",
@@ -8,13 +8,13 @@
8
8
  "./server/actionIds": "./src/server/actionIds.js"
9
9
  },
10
10
  "dependencies": {
11
- "@jskit-ai/assistant-core": "0.1.34",
12
- "@jskit-ai/database-runtime": "0.1.58",
13
- "@jskit-ai/http-runtime": "0.1.57",
14
- "@jskit-ai/kernel": "0.1.58",
15
- "@jskit-ai/shell-web": "0.1.57",
16
- "@jskit-ai/users-core": "0.1.68",
17
- "@jskit-ai/users-web": "0.1.73",
11
+ "@jskit-ai/assistant-core": "0.1.36",
12
+ "@jskit-ai/database-runtime": "0.1.60",
13
+ "@jskit-ai/http-runtime": "0.1.59",
14
+ "@jskit-ai/kernel": "0.1.60",
15
+ "@jskit-ai/shell-web": "0.1.59",
16
+ "@jskit-ai/users-core": "0.1.70",
17
+ "@jskit-ai/users-web": "0.1.75",
18
18
  "json-rest-schema": "1.x.x",
19
19
  "@tanstack/vue-query": "^5.90.5",
20
20
  "vuetify": "^4.0.0"
@@ -5,6 +5,7 @@ import {
5
5
  import {
6
6
  deepFreeze
7
7
  } from "@jskit-ai/kernel/shared/support/deepFreeze";
8
+ import { returnJsonApiData } from "@jskit-ai/http-runtime/shared";
8
9
  import {
9
10
  assistantConfigResource,
10
11
  assistantResource
@@ -120,17 +121,17 @@ const assistantActions = Object.freeze([
120
121
  require: "authenticated"
121
122
  },
122
123
  input: runtimeConversationsListInputValidator,
123
- output: assistantResource.operations.conversationsList.output,
124
+ output: null,
124
125
  idempotency: "none",
125
126
  audit: {
126
127
  actionName: actionIds.conversationsList
127
128
  },
128
129
  observability: {},
129
130
  async execute(input, context, deps) {
130
- return deps.chatService.listConversations(input.query, {
131
+ return returnJsonApiData(await deps.chatService.listConversations(input.query, {
131
132
  context,
132
133
  input
133
- });
134
+ }));
134
135
  }
135
136
  },
136
137
  {
@@ -143,17 +144,17 @@ const assistantActions = Object.freeze([
143
144
  require: "authenticated"
144
145
  },
145
146
  input: runtimeConversationMessagesListInputValidator,
146
- output: assistantResource.operations.conversationMessagesList.output,
147
+ output: null,
147
148
  idempotency: "none",
148
149
  audit: {
149
150
  actionName: actionIds.conversationMessagesList
150
151
  },
151
152
  observability: {},
152
153
  async execute(input, context, deps) {
153
- return deps.chatService.getConversationMessages(input.conversationId, input.query, {
154
+ return returnJsonApiData(await deps.chatService.getConversationMessages(input.conversationId, input.query, {
154
155
  context,
155
156
  input
156
- });
157
+ }));
157
158
  }
158
159
  },
159
160
  {
@@ -166,16 +167,16 @@ const assistantActions = Object.freeze([
166
167
  require: "authenticated"
167
168
  },
168
169
  input: settingsReadInputValidator,
169
- output: assistantConfigResource.operations.view.output,
170
+ output: null,
170
171
  idempotency: "none",
171
172
  audit: {
172
173
  actionName: actionIds.settingsRead
173
174
  },
174
175
  observability: {},
175
176
  async execute(input, context, deps) {
176
- return deps.assistantConfigService.getSettings(input, {
177
+ return returnJsonApiData(await deps.assistantConfigService.getSettings(input, {
177
178
  context
178
- });
179
+ }));
179
180
  }
180
181
  },
181
182
  {
@@ -188,16 +189,16 @@ const assistantActions = Object.freeze([
188
189
  require: "authenticated"
189
190
  },
190
191
  input: settingsUpdateInputValidator,
191
- output: assistantConfigResource.operations.patch.output,
192
+ output: null,
192
193
  idempotency: "optional",
193
194
  audit: {
194
195
  actionName: actionIds.settingsUpdate
195
196
  },
196
197
  observability: {},
197
198
  async execute(input, context, deps) {
198
- return deps.assistantConfigService.updateSettings(input, input.patch, {
199
+ return returnJsonApiData(await deps.assistantConfigService.updateSettings(input, input.patch, {
199
200
  context
200
- });
201
+ }));
201
202
  }
202
203
  }
203
204
  ]);
@@ -2,8 +2,13 @@ import { AppError } from "@jskit-ai/kernel/server/runtime";
2
2
  import { resolveAppConfig } from "@jskit-ai/kernel/server/support";
3
3
  import { composeSchemaDefinitions } from "@jskit-ai/kernel/shared/validators";
4
4
  import { normalizeSurfaceId } from "@jskit-ai/kernel/shared/surface/registry";
5
- import { withStandardErrorResponses } from "@jskit-ai/http-runtime/shared/validators/errorResponses";
5
+ import { createJsonApiResourceRouteContract } from "@jskit-ai/http-runtime/shared/validators/jsonApiRouteTransport";
6
6
  import {
7
+ ASSISTANT_CONVERSATIONS_TRANSPORT,
8
+ ASSISTANT_CONVERSATION_MESSAGES_TRANSPORT,
9
+ ASSISTANT_SETTINGS_UPDATE_TRANSPORT,
10
+ ASSISTANT_SETTINGS_TRANSPORT,
11
+ assistantConversationOutputValidator,
7
12
  assistantConfigResource,
8
13
  assistantResource,
9
14
  resolveAssistantApiBasePath
@@ -156,6 +161,24 @@ function buildChatStreamActionInput(routeInput = {}, requestBody = {}) {
156
161
  return actionInput;
157
162
  }
158
163
 
164
+ function resolveAssistantSettingsRecordId(record = {}) {
165
+ const scopeKey = String(record?.scopeKey || "").trim();
166
+ if (!scopeKey) {
167
+ throw new Error("Assistant settings JSON:API response requires scopeKey.");
168
+ }
169
+
170
+ return scopeKey;
171
+ }
172
+
173
+ function resolveAssistantConversationMessagesRecordId(record = {}) {
174
+ const conversationId = String(record?.conversation?.id || "").trim();
175
+ if (!conversationId) {
176
+ throw new Error("Assistant conversation messages JSON:API response requires conversation.id.");
177
+ }
178
+
179
+ return conversationId;
180
+ }
181
+
159
182
  function registerSettingsRoutes(
160
183
  router,
161
184
  resolveCurrentAppConfig,
@@ -181,8 +204,11 @@ function registerSettingsRoutes(
181
204
  tags: ["assistant", "settings"],
182
205
  summary: "Get assistant settings."
183
206
  },
184
- responses: withStandardErrorResponses({
185
- 200: assistantConfigResource.operations.view.output
207
+ ...createJsonApiResourceRouteContract({
208
+ ...ASSISTANT_SETTINGS_TRANSPORT,
209
+ output: assistantConfigResource.operations.view.output,
210
+ outputKind: "record",
211
+ getRecordId: resolveAssistantSettingsRecordId
186
212
  })
187
213
  },
188
214
  async function assistantSettingsReadRoute(request, reply) {
@@ -216,15 +242,14 @@ function registerSettingsRoutes(
216
242
  tags: ["assistant", "settings"],
217
243
  summary: "Update assistant settings."
218
244
  },
219
- body: assistantConfigResource.operations.patch.body,
220
- responses: withStandardErrorResponses(
221
- {
222
- 200: assistantConfigResource.operations.patch.output
223
- },
224
- {
225
- includeValidation400: true
226
- }
227
- )
245
+ ...createJsonApiResourceRouteContract({
246
+ ...ASSISTANT_SETTINGS_UPDATE_TRANSPORT,
247
+ body: assistantConfigResource.operations.patch.body,
248
+ output: assistantConfigResource.operations.patch.output,
249
+ outputKind: "record",
250
+ getRecordId: resolveAssistantSettingsRecordId,
251
+ includeValidation400: true
252
+ })
228
253
  },
229
254
  async function assistantSettingsPatchRoute(request, reply) {
230
255
  const routeState = resolveRouteRequestState(request, {
@@ -400,9 +425,11 @@ function registerRuntimeRoutes(
400
425
  tags: ["assistant"],
401
426
  summary: "List assistant conversations."
402
427
  },
403
- query: assistantResource.operations.conversationsList.query,
404
- responses: withStandardErrorResponses({
405
- 200: assistantResource.operations.conversationsList.output
428
+ ...createJsonApiResourceRouteContract({
429
+ ...ASSISTANT_CONVERSATIONS_TRANSPORT,
430
+ query: assistantResource.operations.conversationsList.query,
431
+ output: assistantConversationOutputValidator,
432
+ outputKind: "collection"
406
433
  })
407
434
  },
408
435
  async function assistantConversationsRoute(request, reply) {
@@ -439,9 +466,12 @@ function registerRuntimeRoutes(
439
466
  tags: ["assistant"],
440
467
  summary: "List assistant conversation messages."
441
468
  },
442
- query: assistantResource.operations.conversationMessagesList.query,
443
- responses: withStandardErrorResponses({
444
- 200: assistantResource.operations.conversationMessagesList.output
469
+ ...createJsonApiResourceRouteContract({
470
+ ...ASSISTANT_CONVERSATION_MESSAGES_TRANSPORT,
471
+ query: assistantResource.operations.conversationMessagesList.query,
472
+ output: assistantResource.operations.conversationMessagesList.output,
473
+ outputKind: "record",
474
+ getRecordId: resolveAssistantConversationMessagesRecordId
445
475
  })
446
476
  },
447
477
  async function assistantConversationMessagesRoute(request, reply) {
@@ -85,6 +85,46 @@ function createAssistantTestApp({
85
85
  };
86
86
  }
87
87
 
88
+ function findRoute(routes, { method, path }) {
89
+ return routes.find((entry) => entry.method === method && entry.path === path) || null;
90
+ }
91
+
92
+ test("registerRoutes exposes JSON:API contracts for assistant settings and transcript endpoints", () => {
93
+ const testApp = createAssistantTestApp({
94
+ workspaceScopeSupport: createWorkspaceServerScopeSupport(),
95
+ resolveCurrentAppConfig: () => createAssistantAppConfig()
96
+ });
97
+
98
+ registerRoutes(testApp.app);
99
+ const routes = testApp.router.list();
100
+ const publicSettingsReadRoute = findRoute(routes, {
101
+ method: "GET",
102
+ path: "/api/assistant/:surfaceId/settings"
103
+ });
104
+ const publicSettingsUpdateRoute = findRoute(routes, {
105
+ method: "PATCH",
106
+ path: "/api/assistant/:surfaceId/settings"
107
+ });
108
+ const publicConversationsRoute = findRoute(routes, {
109
+ method: "GET",
110
+ path: "/api/assistant/:surfaceId/conversations"
111
+ });
112
+ const publicConversationMessagesRoute = findRoute(routes, {
113
+ method: "GET",
114
+ path: "/api/assistant/:surfaceId/conversations/:conversationId/messages"
115
+ });
116
+
117
+ assert.equal(publicSettingsReadRoute?.transport?.kind, "jsonapi-resource");
118
+ assert.equal(publicSettingsUpdateRoute?.transport?.kind, "jsonapi-resource");
119
+ assert.equal(publicConversationsRoute?.transport?.kind, "jsonapi-resource");
120
+ assert.equal(publicConversationMessagesRoute?.transport?.kind, "jsonapi-resource");
121
+ assert.equal(publicSettingsReadRoute?.schema?.response?.[200]?.required?.[0], "data");
122
+ assert.equal(publicSettingsUpdateRoute?.schema?.body?.required?.[0], "data");
123
+ assert.equal(publicSettingsUpdateRoute?.schema?.response?.[200]?.required?.[0], "data");
124
+ assert.equal(publicConversationsRoute?.schema?.response?.[200]?.required?.[0], "data");
125
+ assert.equal(publicConversationMessagesRoute?.schema?.response?.[200]?.required?.[0], "data");
126
+ });
127
+
88
128
  test("registerRoutes resolves appConfig lazily when handlers run", async () => {
89
129
  let currentAppConfig = null;
90
130
  const workspaceScopeSupport = createWorkspaceServerScopeSupport();
@@ -97,11 +137,10 @@ test("registerRoutes resolves appConfig lazily when handlers run", async () => {
97
137
  currentAppConfig = createAssistantAppConfig();
98
138
  const routes = testApp.router.list();
99
139
 
100
- const route = routes.find(
101
- (entry) =>
102
- entry.method === "GET" &&
103
- entry.path === "/api/w/:workspaceSlug/assistant/:surfaceId/conversations"
104
- );
140
+ const route = findRoute(routes, {
141
+ method: "GET",
142
+ path: "/api/w/:workspaceSlug/assistant/:surfaceId/conversations"
143
+ });
105
144
 
106
145
  assert.ok(route, "Expected workspace assistant conversations route to be registered.");
107
146
 
@@ -167,11 +206,10 @@ test("registerRoutes returns clear AppError payload for pre-stream assistant fai
167
206
  currentAppConfig = createAssistantAppConfig();
168
207
  const routes = testApp.router.list();
169
208
 
170
- const route = routes.find(
171
- (entry) =>
172
- entry.method === "POST" &&
173
- entry.path === "/api/w/:workspaceSlug/assistant/:surfaceId/chat/stream"
174
- );
209
+ const route = findRoute(routes, {
210
+ method: "POST",
211
+ path: "/api/w/:workspaceSlug/assistant/:surfaceId/chat/stream"
212
+ });
175
213
 
176
214
  assert.ok(route, "Expected workspace assistant chat stream route to be registered.");
177
215