@jskit-ai/assistant-core 0.2.39 → 0.2.41
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- `assistantConversationListItemOutputValidator` (from `@jskit-ai/assistant-core/shared`) is one conversation of `assistantContract`'s `conversationsList`, the record without its `metadata`; the contract's list output is built from it, and `@jskit-ai/assistant-runtime`'s conversations list route serializes its items with it.
|
|
5
6
|
- `createConversationStorage`'s `write` saves nothing when its callback called no write method: the adapter's `writeRecord` does not run, so file storage no longer rewrites and flushes the whole conversation file, or creates an empty one for a missing conversation, when a write only looked (a delivery check, a message already saved), and the saved record stays cached.
|
|
6
7
|
- Checking or recovering one message's delivery (`inspectDelivery`, and a send that finds its message already saved) finds that message's turn by its id instead of reading and cloning every turn of the conversation to find it.
|
|
7
8
|
- With completed envelopes, a streamed turn's saved completed-envelope marker is read once per turn instead of once per delta: the marker is written with the turn's authored message and never changes, and a reply's hundreds of deltas each opened a storage read. A turn not saved yet is read again until it is.
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
"build": "vite build"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@jskit-ai/assistant-core": "0.2.
|
|
12
|
-
"@jskit-ai/http-runtime": "0.2.
|
|
13
|
-
"@jskit-ai/kernel": "0.2.
|
|
11
|
+
"@jskit-ai/assistant-core": "0.2.41",
|
|
12
|
+
"@jskit-ai/http-runtime": "0.2.19",
|
|
13
|
+
"@jskit-ai/kernel": "0.2.19",
|
|
14
14
|
"@jskit-ai/material-web": "0.1.5",
|
|
15
15
|
"vue": "^3.5.13",
|
|
16
16
|
"vuetify": "^4.0.0",
|
|
17
|
-
"@jskit-ai/connectors-core": "0.2.
|
|
18
|
-
"@jskit-ai/connectors-catalog": "0.2.
|
|
17
|
+
"@jskit-ai/connectors-core": "0.2.27",
|
|
18
|
+
"@jskit-ai/connectors-catalog": "0.2.27"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@vitejs/plugin-vue": "^6.0.7",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/assistant-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "jskit test"
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@ai-sdk/togetherai": "^3.0.49",
|
|
53
53
|
"@ai-sdk/xai": "^4.0.58",
|
|
54
54
|
"@jskit-ai/agent": "0.1.3",
|
|
55
|
-
"@jskit-ai/resource-core": "0.1.
|
|
55
|
+
"@jskit-ai/resource-core": "0.1.210",
|
|
56
56
|
"@openrouter/ai-sdk-provider": "^3.0.0",
|
|
57
57
|
"ai": "^7.0.152",
|
|
58
58
|
"json-rest-schema": "^1.0.20",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"ws": "^8.20.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@jskit-ai/http-runtime": "0.2.
|
|
64
|
-
"@jskit-ai/kernel": "0.2.
|
|
63
|
+
"@jskit-ai/http-runtime": "0.2.19",
|
|
64
|
+
"@jskit-ai/kernel": "0.2.19",
|
|
65
65
|
"vue": "^3.5.13",
|
|
66
66
|
"vuetify": "^4.3.0"
|
|
67
67
|
},
|
|
@@ -272,6 +272,8 @@ const conversationMessagesListOutputSchema = createSchema({
|
|
|
272
272
|
});
|
|
273
273
|
|
|
274
274
|
const assistantConversationOutputValidator = createSchemaDefinition(conversationRecordSchema, "replace");
|
|
275
|
+
// One conversation of a list, as the conversations list route answers each item: the record without its metadata.
|
|
276
|
+
const assistantConversationListItemOutputValidator = createSchemaDefinition(conversationListItemSchema, "replace");
|
|
275
277
|
|
|
276
278
|
const assistantContract = defineApiContract({
|
|
277
279
|
namespace: "assistant",
|
|
@@ -283,7 +285,7 @@ const assistantContract = defineApiContract({
|
|
|
283
285
|
conversationsList: {
|
|
284
286
|
method: "GET",
|
|
285
287
|
query: conversationsListQuerySchema,
|
|
286
|
-
output: createCursorListValidator(
|
|
288
|
+
output: createCursorListValidator(assistantConversationListItemOutputValidator)
|
|
287
289
|
},
|
|
288
290
|
conversationMessagesList: {
|
|
289
291
|
method: "GET",
|
|
@@ -299,5 +301,6 @@ export {
|
|
|
299
301
|
MAX_MESSAGE_PAGE_SIZE,
|
|
300
302
|
attachmentIdsField,
|
|
301
303
|
assistantContract,
|
|
304
|
+
assistantConversationListItemOutputValidator,
|
|
302
305
|
assistantConversationOutputValidator
|
|
303
306
|
};
|
package/src/shared/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import test from "node:test";
|
|
|
3
3
|
import { createSchema } from "json-rest-schema";
|
|
4
4
|
|
|
5
5
|
import { createActionCatalogue } from "@jskit-ai/kernel/server/actions";
|
|
6
|
+
import { createValidationError } from "@jskit-ai/kernel/server/runtime/errors";
|
|
6
7
|
import { createServiceToolCatalog } from "../src/server/lib/serviceToolCatalog.js";
|
|
7
8
|
|
|
8
9
|
function schema(fields = {}, mode = "patch") {
|
|
@@ -29,6 +30,7 @@ function action({
|
|
|
29
30
|
input = schema({}),
|
|
30
31
|
output = schema({ ok: { type: "boolean", required: true } }),
|
|
31
32
|
extensions = {},
|
|
33
|
+
checkInput = null,
|
|
32
34
|
execute = async () => ({ ok: true })
|
|
33
35
|
} = {}) {
|
|
34
36
|
return {
|
|
@@ -41,6 +43,7 @@ function action({
|
|
|
41
43
|
input,
|
|
42
44
|
output,
|
|
43
45
|
extensions,
|
|
46
|
+
checkInput,
|
|
44
47
|
execute
|
|
45
48
|
};
|
|
46
49
|
}
|
|
@@ -270,6 +273,48 @@ test("assistant tools expose safe field-level input guidance to the model", asyn
|
|
|
270
273
|
});
|
|
271
274
|
});
|
|
272
275
|
|
|
276
|
+
test("assistant tools give the model the field and the type to use when an action's own input check refuses a key", async () => {
|
|
277
|
+
let executed = false;
|
|
278
|
+
const actions = createActions([action({
|
|
279
|
+
input: schema({ fields: { type: "object", required: false, additionalProperties: true } }),
|
|
280
|
+
// A check of what the schema cannot judge, such as a fieldset key only the application's tables can name.
|
|
281
|
+
checkInput(input) {
|
|
282
|
+
if (input.fields?.pet) {
|
|
283
|
+
throw createValidationError({
|
|
284
|
+
"fields.pet": {
|
|
285
|
+
code: "demo.fieldsKeys",
|
|
286
|
+
params: { type: "pets" },
|
|
287
|
+
message: "fields keys must be resource types. Allowed keys: \"books\", \"pets\"; use \"pets\" instead of \"pet\"."
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
execute: async () => {
|
|
293
|
+
executed = true;
|
|
294
|
+
return { ok: true };
|
|
295
|
+
}
|
|
296
|
+
})]);
|
|
297
|
+
const catalog = createServiceToolCatalog(actions);
|
|
298
|
+
const context = { actor: { id: "7" }, surface: "admin" };
|
|
299
|
+
const toolSet = catalog.resolveToolSet(context);
|
|
300
|
+
|
|
301
|
+
assert.deepEqual(await catalog.executeToolCall({
|
|
302
|
+
toolName: toolSet.tools[0].name,
|
|
303
|
+
argumentsText: JSON.stringify({ fields: { pet: ["name"] } }),
|
|
304
|
+
context,
|
|
305
|
+
toolSet
|
|
306
|
+
}), {
|
|
307
|
+
ok: false,
|
|
308
|
+
error: {
|
|
309
|
+
code: "ACTION_VALIDATION_FAILED",
|
|
310
|
+
message: "Validation failed. fields.pet: fields keys must be resource types. Allowed keys: \"books\", \"pets\"; " +
|
|
311
|
+
"use \"pets\" instead of \"pet\".",
|
|
312
|
+
status: 400
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
assert.equal(executed, false);
|
|
316
|
+
});
|
|
317
|
+
|
|
273
318
|
test("large authorized catalogs use compact paged discovery, exact contracts, and gated execution", async () => {
|
|
274
319
|
const executions = [];
|
|
275
320
|
let clockExecution = null;
|