@jskit-ai/assistant-core 0.1.143 → 0.1.145

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/assistant-core",
3
- "version": "0.1.143",
3
+ "version": "0.1.145",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -11,16 +11,16 @@
11
11
  "./shared": "./src/shared/index.js"
12
12
  },
13
13
  "dependencies": {
14
- "@jskit-ai/http-runtime": "0.1.165",
15
- "@jskit-ai/kernel": "0.1.167",
16
- "@jskit-ai/resource-core": "0.1.109",
17
- "@jskit-ai/resource-crud-core": "0.1.109",
14
+ "@jskit-ai/resource-core": "0.1.111",
15
+ "@jskit-ai/resource-crud-core": "0.1.111",
18
16
  "dompurify": "^3.4.13",
19
17
  "json-rest-schema": "^1.0.17",
20
18
  "marked": "^17.0.4",
21
19
  "openai": "^6.22.0"
22
20
  },
23
21
  "peerDependencies": {
22
+ "@jskit-ai/http-runtime": "0.1.167",
23
+ "@jskit-ai/kernel": "0.1.169",
24
24
  "vue": "^3.5.13",
25
25
  "vuetify": "^4.0.0"
26
26
  },
@@ -384,6 +384,26 @@ function truncateDescription(value, maxLength = 240) {
384
384
  return `${description.slice(0, Math.max(1, maxLength - 1))}…`;
385
385
  }
386
386
 
387
+ function resolveValidationFailureMessage(error) {
388
+ const baseMessage = normalizeText(error?.message, { fallback: "Validation failed." });
389
+ if (normalizeText(error?.code).toUpperCase() !== "ACTION_VALIDATION_FAILED") {
390
+ return baseMessage;
391
+ }
392
+
393
+ const fieldErrors = error?.details?.fieldErrors;
394
+ if (!fieldErrors || typeof fieldErrors !== "object" || Array.isArray(fieldErrors)) {
395
+ return baseMessage;
396
+ }
397
+
398
+ const details = Object.entries(fieldErrors)
399
+ .map(([field, message]) => [normalizeText(field), truncateDescription(message, 300)])
400
+ .filter(([field, message]) => field && message)
401
+ .sort(([left], [right]) => left.localeCompare(right))
402
+ .slice(0, 8)
403
+ .map(([field, message]) => `${field}: ${message}`);
404
+ return details.length > 0 ? `${baseMessage} ${details.join(" ")}` : baseMessage;
405
+ }
406
+
387
407
  function canInvokeMethod(permission, context) {
388
408
  const permissionSpec = normalizePermissionSpec(permission);
389
409
 
@@ -832,7 +852,7 @@ function createServiceToolCatalog(
832
852
  ok: false,
833
853
  error: {
834
854
  code: String(error?.code || "assistant_tool_failed").trim() || "assistant_tool_failed",
835
- message: status >= 500 ? "Tool call failed." : String(error?.message || "Tool call failed."),
855
+ message: status >= 500 ? "Tool call failed." : resolveValidationFailureMessage(error),
836
856
  status: Number.isInteger(status) ? status : 500
837
857
  }
838
858
  };
@@ -216,6 +216,37 @@ test("assistant tools hide workspaceSlug and overwrite model values with trusted
216
216
  assert.equal(executed.context.channel, "automation");
217
217
  });
218
218
 
219
+ test("assistant tools expose safe field-level input guidance to the model", async () => {
220
+ const actions = createActions([action({
221
+ input: schema({
222
+ include: {
223
+ type: "string",
224
+ required: false,
225
+ messages: {
226
+ default: "include expects a comma-separated string such as \"pet,service\"."
227
+ }
228
+ }
229
+ })
230
+ })]);
231
+ const catalog = createServiceToolCatalog(actions);
232
+ const context = { actor: { id: "7" }, surface: "admin" };
233
+ const toolSet = catalog.resolveToolSet(context);
234
+
235
+ assert.deepEqual(await catalog.executeToolCall({
236
+ toolName: toolSet.tools[0].name,
237
+ argumentsText: JSON.stringify({ include: ["pet"] }),
238
+ context,
239
+ toolSet
240
+ }), {
241
+ ok: false,
242
+ error: {
243
+ code: "ACTION_VALIDATION_FAILED",
244
+ message: "Validation failed. include: include expects a comma-separated string such as \"pet,service\".",
245
+ status: 400
246
+ }
247
+ });
248
+ });
249
+
219
250
  test("large authorized catalogs use compact paged discovery, exact contracts, and gated execution", async () => {
220
251
  const executions = [];
221
252
  const workspaceInput = schema({