@jskit-ai/assistant-runtime 0.2.26 → 0.2.28
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 +7 -1
- package/fixtures/conversation/vite.config.mjs +3 -0
- package/fixtures/settings/index.html +12 -0
- package/fixtures/settings/main.js +84 -0
- package/fixtures/settings/vite.config.mjs +9 -0
- package/locales/en.json +4 -1
- package/package.json +16 -11
- package/src/client/components/AssistantSettingsClientElement.vue +23 -0
- package/src/client/support/subscribeAssistantConversation.js +6 -4
- package/src/server/AssistantProvider.js +6 -0
- package/src/server/createAssistantRuntime.js +7 -0
- package/src/server/index.js +1 -0
- package/src/server/services/chatService.js +9 -2
- package/src/server/support/personContext.js +89 -0
- package/src/server/types.js +20 -0
- package/test/assistantConversationBinding.browser.test.js +10 -6
- package/test/assistantConversationSubscriptions.test.js +30 -11
- package/test/assistantRuntimeComposition.test.js +3 -1
- package/test/assistantSettings.browser.test.js +162 -0
- package/test/assistantSettingsPane.test.js +12 -0
- package/test/chatServiceLifecycle.test.js +199 -4
- package/test/conversation.browser.test.js +66 -69
- package/test/lazyAppConfig.test.js +10 -10
- package/test/sqlConversationStorage.test.js +8 -0
- package/test/support/memoryAssistantRows.js +2 -2
- package/test/turnRequests.test.js +3 -0
|
@@ -2,7 +2,8 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import { mkdir } from "node:fs/promises";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import test from "node:test";
|
|
5
|
-
import { chromium
|
|
5
|
+
import { chromium } from "@playwright/test";
|
|
6
|
+
import { expect } from "../../../tooling/testUtils/browserExpect.mjs";
|
|
6
7
|
import { createChromiumLaunchOptions, startViteFixture, stopProcess } from "../../../tooling/testUtils/browserFixture.mjs";
|
|
7
8
|
|
|
8
9
|
const fixtureRoot = fileURLToPath(new URL("../fixtures/conversation/", import.meta.url));
|
|
@@ -10,9 +11,11 @@ const fixtureRoot = fileURLToPath(new URL("../fixtures/conversation/", import.me
|
|
|
10
11
|
test("ready-made assistant preserves streaming, drafts, scope and compact conversation access", {
|
|
11
12
|
skip: process.env.JSKIT_ASSISTANT_RUNTIME_BROWSER_INTEGRATION !== "1",
|
|
12
13
|
timeout: 180_000
|
|
13
|
-
}, async () => {
|
|
14
|
+
}, async (t) => {
|
|
14
15
|
const vite = await startViteFixture({ fixtureRoot });
|
|
16
|
+
t.after(() => stopProcess(vite));
|
|
15
17
|
const browser = await chromium.launch(createChromiumLaunchOptions());
|
|
18
|
+
t.after(() => browser.close());
|
|
16
19
|
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
|
|
17
20
|
const errors = [];
|
|
18
21
|
page.on("pageerror", (error) => errors.push(error.message));
|
|
@@ -138,18 +141,17 @@ test("ready-made assistant preserves streaming, drafts, scope and compact conver
|
|
|
138
141
|
assert.deepEqual(errors, []);
|
|
139
142
|
} catch (error) {
|
|
140
143
|
throw new Error(`${error.message}\nPage errors: ${JSON.stringify(errors)}\n${vite.readOutput()}`, { cause: error });
|
|
141
|
-
} finally {
|
|
142
|
-
await browser.close();
|
|
143
|
-
await stopProcess(vite);
|
|
144
144
|
}
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
test("history restores preserve new typing and reject obsolete pages and failed automatic restores", {
|
|
148
148
|
skip: process.env.JSKIT_ASSISTANT_RUNTIME_BROWSER_INTEGRATION !== "1",
|
|
149
149
|
timeout: 60_000
|
|
150
|
-
}, async () => {
|
|
150
|
+
}, async (t) => {
|
|
151
151
|
const vite = await startViteFixture({ fixtureRoot });
|
|
152
|
+
t.after(() => stopProcess(vite));
|
|
152
153
|
const browser = await chromium.launch(createChromiumLaunchOptions());
|
|
154
|
+
t.after(() => browser.close());
|
|
153
155
|
const page = await browser.newPage();
|
|
154
156
|
const input = page.getByRole("textbox", { name: "Message AI assistant" });
|
|
155
157
|
const send = page.getByRole("button", { name: "Send message", exact: true });
|
|
@@ -220,92 +222,89 @@ test("history restores preserve new typing and reject obsolete pages and failed
|
|
|
220
222
|
assert.equal(failedRequests, 1, "A failed automatic restore must require explicit selection to retry");
|
|
221
223
|
} finally {
|
|
222
224
|
release?.();
|
|
223
|
-
await browser.close();
|
|
224
|
-
await stopProcess(vite);
|
|
225
225
|
}
|
|
226
226
|
});
|
|
227
227
|
|
|
228
228
|
test("page assistant bounds long history in a document layout and preserves drafts when workspace metadata arrives", {
|
|
229
229
|
skip: process.env.JSKIT_ASSISTANT_RUNTIME_BROWSER_INTEGRATION !== "1",
|
|
230
230
|
timeout: 60_000
|
|
231
|
-
}, async () => {
|
|
231
|
+
}, async (t) => {
|
|
232
232
|
const vite = await startViteFixture({ fixtureRoot });
|
|
233
|
+
t.after(() => stopProcess(vite));
|
|
233
234
|
const browser = await chromium.launch(createChromiumLaunchOptions());
|
|
235
|
+
t.after(() => browser.close());
|
|
234
236
|
const page = await browser.newPage();
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
await
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
assert.ok(await page.getByLabel("Conversation messages", { exact: true }).evaluate(element => element.scrollHeight > element.clientHeight));
|
|
248
|
-
}
|
|
249
|
-
await input.fill("Keep this draft while workspace details load.");
|
|
250
|
-
await input.evaluate(element => { element.focus(); element.setSelectionRange(5, 9); });
|
|
251
|
-
await page.getByRole("button", { name: "Load workspace metadata" }).evaluate(element => element.click());
|
|
252
|
-
await expect(input).toHaveValue("Keep this draft while workspace details load.");
|
|
253
|
-
await expect(input).toBeFocused();
|
|
254
|
-
assert.deepEqual(await input.evaluate(element => [element.selectionStart, element.selectionEnd]), [5, 9]);
|
|
255
|
-
await expect(page.getByText("Saved 1 message 70.", { exact: false })).toBeVisible();
|
|
256
|
-
} finally {
|
|
257
|
-
await browser.close();
|
|
258
|
-
await stopProcess(vite);
|
|
237
|
+
await page.goto(`${vite.baseURL}/?page=1`);
|
|
238
|
+
await page.getByRole("button", { name: "Conversations", exact: true }).click();
|
|
239
|
+
await page.getByRole("dialog", { name: "Conversations", exact: true }).getByText("Saved conversation", { exact: true }).click();
|
|
240
|
+
await expect(page.getByText("Saved 1 message 70.", { exact: false })).toBeVisible();
|
|
241
|
+
const input = page.getByRole("textbox", { name: "Message AI assistant" });
|
|
242
|
+
for (const viewport of [{ width: 390, height: 844 }, { width: 800, height: 800 }, { width: 1280, height: 600 }]) {
|
|
243
|
+
await page.setViewportSize(viewport);
|
|
244
|
+
await expect.poll(async () => {
|
|
245
|
+
const bounds = await input.boundingBox();
|
|
246
|
+
return bounds.y + bounds.height;
|
|
247
|
+
}).toBeLessThanOrEqual(viewport.height);
|
|
248
|
+
assert.ok(await page.getByLabel("Conversation messages", { exact: true }).evaluate(element => element.scrollHeight > element.clientHeight));
|
|
259
249
|
}
|
|
250
|
+
await input.fill("Keep this draft while workspace details load.");
|
|
251
|
+
await input.evaluate(element => { element.focus(); element.setSelectionRange(5, 9); });
|
|
252
|
+
await page.getByRole("button", { name: "Load workspace metadata" }).evaluate(element => element.click());
|
|
253
|
+
await expect(input).toHaveValue("Keep this draft while workspace details load.");
|
|
254
|
+
await expect(input).toBeFocused();
|
|
255
|
+
assert.deepEqual(await input.evaluate(element => [element.selectionStart, element.selectionEnd]), [5, 9]);
|
|
256
|
+
await expect(page.getByText("Saved 1 message 70.", { exact: false })).toBeVisible();
|
|
260
257
|
});
|
|
261
258
|
|
|
262
259
|
|
|
263
260
|
test("the ready-made UI streams from the real chat service with selected AI connections and files", {
|
|
264
261
|
skip: process.env.JSKIT_ASSISTANT_RUNTIME_BROWSER_INTEGRATION !== "1", timeout: 90_000
|
|
265
|
-
}, async () => {
|
|
262
|
+
}, async (t) => {
|
|
266
263
|
const vite = await startViteFixture({ fixtureRoot });
|
|
264
|
+
t.after(() => stopProcess(vite));
|
|
267
265
|
const browser = await chromium.launch(createChromiumLaunchOptions());
|
|
266
|
+
t.after(() => browser.close());
|
|
268
267
|
const page = await browser.newPage({ viewport: { width: 1100, height: 800 } });
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
assert.equal(state.transcript.filter(message => message.role === "assistant").length, 1);
|
|
300
|
-
} finally { await browser.close(); await stopProcess(vite); }
|
|
268
|
+
await page.request.get(`${vite.baseURL}/fixture/service`);
|
|
269
|
+
await page.goto(`${vite.baseURL}/?files=1`);
|
|
270
|
+
const input = page.getByRole("textbox", { name: "Message AI assistant" });
|
|
271
|
+
await expect(input).toBeEnabled();
|
|
272
|
+
await page.getByRole("button", { name: "Choose AI", exact: true }).click();
|
|
273
|
+
await page.getByRole("button", { name: "Deep model", exact: true }).click();
|
|
274
|
+
await page.getByRole("button", { name: "Apply", exact: true }).click();
|
|
275
|
+
await page.locator('input[type="file"]').setInputFiles({ name: "notes.txt", mimeType: "text/plain", buffer: Buffer.from("notes") });
|
|
276
|
+
await expect(page.getByText("notes.txt", { exact: true })).toBeVisible();
|
|
277
|
+
await input.fill("Read the notes");
|
|
278
|
+
await input.press("Enter");
|
|
279
|
+
await expect(page.getByText("Assistant is working…", { exact: true }).last()).toBeVisible();
|
|
280
|
+
await expect(page.getByLabel("Message attachments")).toHaveCount(0);
|
|
281
|
+
await expect(page.getByLabel("Attached files")).toBeVisible();
|
|
282
|
+
await input.fill("My next draft");
|
|
283
|
+
await input.evaluate(element => element.setSelectionRange(3, 7));
|
|
284
|
+
await page.request.get(`${vite.baseURL}/fixture/next`);
|
|
285
|
+
await expect(page.getByText("Partial answer", { exact: true })).toBeVisible();
|
|
286
|
+
await expect(input).toHaveValue("My next draft");
|
|
287
|
+
assert.deepEqual(await input.evaluate(element => [element.selectionStart, element.selectionEnd]), [3, 7]);
|
|
288
|
+
let state = await (await page.request.get(`${vite.baseURL}/fixture/state`)).json();
|
|
289
|
+
assert.equal(state.requests[0].integrationId, "deep");
|
|
290
|
+
assert.deepEqual(state.requests[0].attachmentIds, ["fixture-file"]);
|
|
291
|
+
assert.equal(state.transcript.filter(message => message.role === "assistant").length, 0);
|
|
292
|
+
await page.request.get(`${vite.baseURL}/fixture/next?finish=1`);
|
|
293
|
+
await expect(page.getByText("Partial answer completed.", { exact: true })).toHaveCount(1);
|
|
294
|
+
await expect(page.getByText("Assistant is working…", { exact: true })).toHaveCount(0);
|
|
295
|
+
state = await (await page.request.get(`${vite.baseURL}/fixture/state`)).json();
|
|
296
|
+
assert.deepEqual(state.transcript[0].metadata.attachments, [{ attachmentId: "fixture-file", fileName: "notes.txt", size: 5 }]);
|
|
297
|
+
assert.equal(state.transcript.filter(message => message.role === "assistant").length, 1);
|
|
301
298
|
});
|
|
302
299
|
|
|
303
300
|
test("pending delivery appears immediately and retries the original request without replacing a newer draft", {
|
|
304
301
|
skip: process.env.JSKIT_ASSISTANT_RUNTIME_BROWSER_INTEGRATION !== "1",
|
|
305
302
|
timeout: 60_000
|
|
306
|
-
}, async () => {
|
|
303
|
+
}, async (t) => {
|
|
307
304
|
const vite = await startViteFixture({ fixtureRoot });
|
|
305
|
+
t.after(() => stopProcess(vite));
|
|
308
306
|
const browser = await chromium.launch(createChromiumLaunchOptions());
|
|
307
|
+
t.after(() => browser.close());
|
|
309
308
|
const page = await browser.newPage({ viewport: { width: 390, height: 844 } });
|
|
310
309
|
const held = Promise.withResolvers();
|
|
311
310
|
const requests = [];
|
|
@@ -345,7 +344,5 @@ test("pending delivery appears immediately and retries the original request with
|
|
|
345
344
|
assert.deepEqual(errors, []);
|
|
346
345
|
} finally {
|
|
347
346
|
held.resolve();
|
|
348
|
-
await browser.close();
|
|
349
|
-
await stopProcess(vite);
|
|
350
347
|
}
|
|
351
348
|
});
|
|
@@ -178,7 +178,7 @@ test("registerRoutes forwards the resolved host surface through every direct act
|
|
|
178
178
|
params: {
|
|
179
179
|
conversationId: "conversation_1",
|
|
180
180
|
surfaceId: "admin",
|
|
181
|
-
workspaceSlug: "
|
|
181
|
+
workspaceSlug: "acme"
|
|
182
182
|
},
|
|
183
183
|
query: {
|
|
184
184
|
limit: 20
|
|
@@ -233,7 +233,7 @@ test("registerRoutes builds workspace action input from explicit config and scop
|
|
|
233
233
|
},
|
|
234
234
|
input: {
|
|
235
235
|
params: {
|
|
236
|
-
workspaceSlug: "
|
|
236
|
+
workspaceSlug: "acme",
|
|
237
237
|
surfaceId: "admin"
|
|
238
238
|
},
|
|
239
239
|
query: {
|
|
@@ -259,7 +259,7 @@ test("registerRoutes builds workspace action input from explicit config and scop
|
|
|
259
259
|
assert.equal(reply.statusCode, 200);
|
|
260
260
|
assert.equal(capturedAction?.surface, "admin");
|
|
261
261
|
assert.equal(capturedAction?.input?.targetSurfaceId, "admin");
|
|
262
|
-
assert.equal(capturedAction?.input?.workspaceSlug, "
|
|
262
|
+
assert.equal(capturedAction?.input?.workspaceSlug, "acme");
|
|
263
263
|
});
|
|
264
264
|
|
|
265
265
|
test("registerRoutes returns clear AppError payload for pre-stream assistant failures", async () => {
|
|
@@ -306,7 +306,7 @@ test("registerRoutes returns clear AppError payload for pre-stream assistant fai
|
|
|
306
306
|
},
|
|
307
307
|
input: {
|
|
308
308
|
params: {
|
|
309
|
-
workspaceSlug: "
|
|
309
|
+
workspaceSlug: "acme",
|
|
310
310
|
surfaceId: "admin"
|
|
311
311
|
},
|
|
312
312
|
body: {
|
|
@@ -330,7 +330,7 @@ test("registerRoutes returns clear AppError payload for pre-stream assistant fai
|
|
|
330
330
|
});
|
|
331
331
|
assert.deepEqual(capturedInput, {
|
|
332
332
|
targetSurfaceId: "admin",
|
|
333
|
-
workspaceSlug: "
|
|
333
|
+
workspaceSlug: "acme",
|
|
334
334
|
messageId: "msg_1",
|
|
335
335
|
input: "hello"
|
|
336
336
|
});
|
|
@@ -349,7 +349,7 @@ test("registerRoutes returns clear AppError payload for pre-stream assistant fai
|
|
|
349
349
|
await route.handler({
|
|
350
350
|
raw: { on() {}, off() {} },
|
|
351
351
|
headers: { "x-jskit-surface": "admin" },
|
|
352
|
-
input: { params: { workspaceSlug: "
|
|
352
|
+
input: { params: { workspaceSlug: "acme", surfaceId: "admin" }, body: { messageId: "msg_2", input: "hello" } },
|
|
353
353
|
executeAction: async () => { throw failure; }
|
|
354
354
|
}, reply);
|
|
355
355
|
assert.equal(reply.statusCode, status);
|
|
@@ -389,7 +389,7 @@ test("chat service uses explicit app config when conversations are listed", asyn
|
|
|
389
389
|
{
|
|
390
390
|
input: {
|
|
391
391
|
targetSurfaceId: "admin",
|
|
392
|
-
workspaceSlug: "
|
|
392
|
+
workspaceSlug: "acme"
|
|
393
393
|
},
|
|
394
394
|
context: {
|
|
395
395
|
actor: {
|
|
@@ -398,14 +398,14 @@ test("chat service uses explicit app config when conversations are listed", asyn
|
|
|
398
398
|
},
|
|
399
399
|
workspace: {
|
|
400
400
|
id: 7,
|
|
401
|
-
slug: "
|
|
401
|
+
slug: "acme"
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
405
|
);
|
|
406
406
|
|
|
407
407
|
assert.equal(response.assistantSurface.targetSurfaceId, "admin");
|
|
408
|
-
assert.equal(response.workspace.slug, "
|
|
408
|
+
assert.equal(response.workspace.slug, "acme");
|
|
409
409
|
});
|
|
410
410
|
|
|
411
411
|
test("chat service rejects workspace-scoped assistant surfaces when workspace support is unavailable", async () => {
|
|
@@ -435,7 +435,7 @@ test("chat service rejects workspace-scoped assistant surfaces when workspace su
|
|
|
435
435
|
{
|
|
436
436
|
input: {
|
|
437
437
|
targetSurfaceId: "admin",
|
|
438
|
-
workspaceSlug: "
|
|
438
|
+
workspaceSlug: "acme"
|
|
439
439
|
},
|
|
440
440
|
context: {
|
|
441
441
|
actor: {
|
|
@@ -5,6 +5,7 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import knex from "knex";
|
|
7
7
|
import { AppError } from "@jskit-ai/kernel/server/runtime";
|
|
8
|
+
import { silentLogger } from "@jskit-ai/kernel/server/runtime/logger";
|
|
8
9
|
import { createConversationTranscript } from "@jskit-ai/assistant-core/server/conversation";
|
|
9
10
|
import { verifyConversationStorageContract } from "@jskit-ai/assistant-core/testing/conversation-storage";
|
|
10
11
|
import transcriptsMigration from "../migrations/assistant_transcripts_initial.cjs";
|
|
@@ -17,8 +18,12 @@ import { createSqlConversationStorage } from "../src/server/sqlConversationStora
|
|
|
17
18
|
import { createAssistantConversationRuntime } from "../src/server/createAssistantRuntime.js";
|
|
18
19
|
import { createTranscriptService } from "../src/server/services/transcriptService.js";
|
|
19
20
|
import { createChatService } from "../src/server/services/chatService.js";
|
|
21
|
+
import { NO_PERSON_CONTEXT, createPersonContextPrompt } from "../src/server/support/personContext.js";
|
|
20
22
|
import { createScriptedModel } from "./support/scriptedModel.js";
|
|
21
23
|
|
|
24
|
+
// The chat service of an application that supplies no facts about the person.
|
|
25
|
+
const NO_FACTS = createPersonContextPrompt({ personContext: NO_PERSON_CONTEXT, logger: silentLogger });
|
|
26
|
+
|
|
22
27
|
async function fixture(t) {
|
|
23
28
|
const directory = await mkdtemp(path.join(tmpdir(), "assistant-sql-runtime-"));
|
|
24
29
|
const clients = [];
|
|
@@ -178,6 +183,7 @@ test("the SQL facade uses common inference and durable tool rows, and the model'
|
|
|
178
183
|
const dependencies = { conversationRuntime: runtime, aiClientFactory, serviceToolCatalog: catalog,
|
|
179
184
|
transcriptService: createTranscriptService(f), turnRequests: createTurnRequestsRepository(f.db),
|
|
180
185
|
assistantConfigService: { resolveSystemPrompt: async () => "Retained SQL instructions" },
|
|
186
|
+
personContextPrompt: NO_FACTS,
|
|
181
187
|
appConfig: { surfaceDefinitions: { assistant: { enabled: true, requiresWorkspace: false } },
|
|
182
188
|
assistantSurfaces: { assistant: { settingsSurfaceId: "assistant", configScope: "global" } } } };
|
|
183
189
|
const service = createChatService(dependencies);
|
|
@@ -234,6 +240,7 @@ test("the SQL facade replays historical inspection failures with their exact pub
|
|
|
234
240
|
const dependencies = { conversationRuntime: runtime, aiClientFactory, serviceToolCatalog: catalog,
|
|
235
241
|
transcriptService: createTranscriptService(f), turnRequests,
|
|
236
242
|
assistantConfigService: { resolveSystemPrompt: async () => "Read the supplied context" },
|
|
243
|
+
personContextPrompt: NO_FACTS,
|
|
237
244
|
appConfig: { surfaceDefinitions: { assistant: { enabled: true, requiresWorkspace: false } },
|
|
238
245
|
assistantSurfaces: { assistant: { settingsSurfaceId: "assistant", configScope: "global" } } } };
|
|
239
246
|
const input = { targetSurfaceId: "assistant", conversationId: conversation.id,
|
|
@@ -344,6 +351,7 @@ for (const shape of ["orphan-output", "orphan-tool-result", "unconfirmed-tool"])
|
|
|
344
351
|
const dependencies = { conversationRuntime: runtime, aiClientFactory, serviceToolCatalog: catalog,
|
|
345
352
|
transcriptService: createTranscriptService(f), turnRequests,
|
|
346
353
|
assistantConfigService: { resolveSystemPrompt: async () => "Read only the admitted request" },
|
|
354
|
+
personContextPrompt: NO_FACTS,
|
|
347
355
|
workspaceScopeSupport: { resolveWorkspace: context => context.requestMeta.resolvedWorkspaceContext.workspace },
|
|
348
356
|
appConfig: { surfaceDefinitions: {
|
|
349
357
|
assistant: { enabled: true, requiresWorkspace: true }, other: { enabled: true, requiresWorkspace: true }
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** Repository fixture for the original chat-service unit cases. The production
|
|
2
2
|
* SQL adapter and common runtime run unchanged over these transactional rows.
|
|
3
3
|
*/
|
|
4
|
-
export function createMemoryAssistantRows({ id = "conversation_1", surfaceId = "assistant", messages = [] } = {}) {
|
|
5
|
-
let state = { conversation: { id, workspaceId
|
|
4
|
+
export function createMemoryAssistantRows({ id = "conversation_1", surfaceId = "assistant", workspaceId = null, messages = [] } = {}) {
|
|
5
|
+
let state = { conversation: { id, workspaceId, createdByUserId: "1", surfaceId,
|
|
6
6
|
title: "New conversation", status: "active", messageCount: 0, metadata: {} }, transcript: { revision: "", summary: null }, messages: [] };
|
|
7
7
|
let pending = Promise.resolve();
|
|
8
8
|
const read = options => options?.trx || state;
|
|
@@ -6,7 +6,9 @@ import path from "node:path";
|
|
|
6
6
|
import knex from "knex";
|
|
7
7
|
import migration from "../migrations/assistant_turn_requests.cjs";
|
|
8
8
|
import { createRepository } from "../src/server/repositories/turnRequestsRepository.js";
|
|
9
|
+
import { silentLogger } from "@jskit-ai/kernel/server/runtime/logger";
|
|
9
10
|
import { createChatService } from "../src/server/services/chatService.js";
|
|
11
|
+
import { NO_PERSON_CONTEXT, createPersonContextPrompt } from "../src/server/support/personContext.js";
|
|
10
12
|
import { createAssistantConversationRuntime } from "../src/server/createAssistantRuntime.js";
|
|
11
13
|
import { createMemoryAssistantRows } from "./support/memoryAssistantRows.js";
|
|
12
14
|
import { createScriptedModel } from "./support/scriptedModel.js";
|
|
@@ -59,6 +61,7 @@ function service(repository, { provider, transcript = [] } = {}) {
|
|
|
59
61
|
serviceToolCatalog: { limits: { maxToolArgumentBytes: 64 * 1024 }, resolveToolSet: () => ({ tools: [] }),
|
|
60
62
|
toOpenAiToolSchema: tool => ({ type: "function", function: tool }) },
|
|
61
63
|
assistantConfigService: { resolveSystemPrompt: async () => "Answer." },
|
|
64
|
+
personContextPrompt: createPersonContextPrompt({ personContext: NO_PERSON_CONTEXT, logger: silentLogger }),
|
|
62
65
|
appConfig: {
|
|
63
66
|
surfaceDefinitions: { assistant: { id: "assistant", enabled: true, requiresWorkspace: false, accessPolicyId: "public" } },
|
|
64
67
|
assistantSurfaces: { assistant: { settingsSurfaceId: "assistant", configScope: "global" } }
|