@jskit-ai/assistant-runtime 0.1.152 → 0.1.153

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-runtime",
3
- "version": "0.1.152",
3
+ "version": "0.1.153",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -11,15 +11,15 @@
11
11
  "./server/actionIds": "./src/server/actionIds.js"
12
12
  },
13
13
  "dependencies": {
14
- "@jskit-ai/assistant-core": "0.1.157",
15
- "@jskit-ai/database-runtime": "0.1.181",
14
+ "@jskit-ai/assistant-core": "0.1.158",
15
+ "@jskit-ai/database-runtime": "0.1.182",
16
16
  "json-rest-schema": "^1.0.17"
17
17
  },
18
18
  "peerDependencies": {
19
- "@jskit-ai/http-runtime": "0.1.179",
20
- "@jskit-ai/http-web": "0.1.26",
21
- "@jskit-ai/kernel": "0.1.181",
22
- "@jskit-ai/shell-web": "0.1.185",
19
+ "@jskit-ai/http-runtime": "0.1.180",
20
+ "@jskit-ai/http-web": "0.1.27",
21
+ "@jskit-ai/kernel": "0.1.182",
22
+ "@jskit-ai/shell-web": "0.1.186",
23
23
  "@tanstack/vue-query": "^5.90.5",
24
24
  "vue": "^3.5.13",
25
25
  "vuetify": "^4.0.0"
@@ -193,6 +193,20 @@ function buildSystemPrompt({ targetSurfaceId = "", toolDescriptors = [], workspa
193
193
  toolSummary,
194
194
  toolContracts
195
195
  ];
196
+ if (toolDescriptors.length > 0) {
197
+ promptSegments.push(
198
+ "For counts or summaries, first look for a suitable count, aggregate, or report action before reading individual records. Use collection reads when no such action can answer the request. For requests to read several records, compare records, or examine all records, look for a collection action such as list, search, or query.",
199
+ "Match the user's current scope. When the user broadens a request, find the underlying collection and remove earlier date or other filters that no longer apply; a previous result subset is not the full collection.",
200
+ "Inspect the action's input and output contracts, use supported filters and field selection, and follow returned pagination until the requested number or scope is covered. For all records or a comparison across the whole collection, cover every relevant page unless a suitable aggregate action answers the request. Never present a partial page or sample as complete; state any incomplete coverage."
201
+ );
202
+ }
203
+ if (toolDescriptors.some((tool) => tool.name === "assistant_action_search")) {
204
+ promptSegments.push(
205
+ "The directly exposed tools are entry points into a larger authorized action catalog. Additional application capabilities are available through assistant_action_search, assistant_action_contract, and assistant_action_execute.",
206
+ "Before claiming an operation or dataset is unavailable or asking the user for access, discover relevant actions with assistant_action_search. Search for the resource and the requested operation: list/search/query for reading records, count/aggregate/report for totals or summaries. Search matches literal words, not meanings: use short resource or operation terms, try broader terms such as list or query when wording differs, or omit query to browse. Continue through catalog nextCursor pages when needed to find a relevant action; one empty search or unrelated page does not establish that a capability is absent.",
207
+ "Choose an action by its returned description and exact contract, then load assistant_action_contract before assistant_action_execute. Use discovered action IDs and contract fields; do not invent them. Catalog pagination discovers actions; a collection action's pagination retrieves records."
208
+ );
209
+ }
196
210
  if (normalizedCustomSystemPrompt) {
197
211
  promptSegments.push(`Additional instructions for this surface: ${normalizedCustomSystemPrompt}`);
198
212
  }
@@ -207,6 +207,54 @@ function assistantMessages(events) {
207
207
  .map((event) => event.payload.text);
208
208
  }
209
209
 
210
+ test("the provider receives collection guidance in direct and discovery modes", async (t) => {
211
+ for (const discovery of [false, true]) {
212
+ await t.test(discovery ? "discovery" : "direct", async () => {
213
+ const toolNames = discovery
214
+ ? ["assistant_action_search", "assistant_action_contract", "assistant_action_execute"]
215
+ : ["inventory_assets_list"];
216
+ const harness = createHarness([textCompletion("The requested comparison is complete.")], {
217
+ tools: toolNames.map((name) => ({
218
+ name,
219
+ parameters: { type: "object" },
220
+ outputSchema: { type: "object" }
221
+ }))
222
+ });
223
+
224
+ await harness.run("Compare all records, including those outside last week's results.");
225
+
226
+ const prompt = harness.completionRequests[0].messages[0].content;
227
+ assert.match(prompt, /collection action such as list, search, or query/u);
228
+ assert.match(prompt, /first look for a suitable count, aggregate, or report action before reading individual records/u);
229
+ assert.match(prompt, /remove earlier date or other filters that no longer apply/u);
230
+ assert.match(prompt, /follow returned pagination until the requested number or scope is covered/u);
231
+ assert.match(prompt, /Never present a partial page or sample as complete/u);
232
+ if (discovery) {
233
+ assert.match(prompt, /Before claiming an operation or dataset is unavailable.*assistant_action_search/u);
234
+ assert.match(prompt, /count\/aggregate\/report for totals or summaries/u);
235
+ assert.match(prompt, /broader terms such as list or query.*omit query to browse/u);
236
+ assert.match(prompt, /one empty search or unrelated page does not establish that a capability is absent/u);
237
+ assert.match(prompt, /load assistant_action_contract before assistant_action_execute/u);
238
+ } else {
239
+ assert.doesNotMatch(prompt, /assistant_action_search|assistant_action_contract|assistant_action_execute/u);
240
+ }
241
+ });
242
+ }
243
+ });
244
+
245
+ test("an empty authorized tool set does not advertise discovery or collection actions", async () => {
246
+ const harness = createHarness([textCompletion("No application actions are available in this session.")], {
247
+ tools: []
248
+ });
249
+
250
+ await harness.run("List the available records.");
251
+
252
+ const request = harness.completionRequests[0];
253
+ assert.deepEqual(request.tools, []);
254
+ assert.match(request.messages[0].content, /No tools are currently available for this user\/session/u);
255
+ assert.doesNotMatch(request.messages[0].content, /assistant_action_search|collection action/u);
256
+ });
257
+
210
258
  test("progress-only output is retried silently and current-time prompts require a workspace clock", async () => {
211
259
  const harness = createHarness(
212
260
  [