@jskit-ai/assistant-runtime 0.2.8 → 0.2.10

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.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/fixtures/canonical-conversation/main.js +2 -1
  3. package/fixtures/canonical-conversation/vite.config.mjs +11 -0
  4. package/fixtures/conversation/main.js +2 -1
  5. package/fixtures/conversation/vite.config.mjs +4 -3
  6. package/locales/en.json +1 -0
  7. package/migrations/assistant_config_initial.cjs +1 -5
  8. package/migrations/assistant_transcripts_initial.cjs +3 -9
  9. package/migrations/assistant_transcripts_summary.cjs +28 -0
  10. package/migrations/assistant_turn_requests.cjs +2 -1
  11. package/migrations/constraints/assistant_users_foreign_keys.cjs +22 -0
  12. package/migrations/constraints/assistant_workspaces_foreign_keys.cjs +26 -0
  13. package/package.json +17 -10
  14. package/patterns/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
  15. package/src/client/components/AssistantConversationClientElement.vue +10 -4
  16. package/src/client/components/AssistantSurfaceClientElement.vue +8 -4
  17. package/src/client/composables/conversationGoal.js +266 -0
  18. package/src/client/composables/conversationHistory.js +215 -0
  19. package/src/client/composables/conversationRuntime.js +624 -0
  20. package/src/client/composables/useAssistantConversation.js +208 -840
  21. package/src/client/composables/useAssistantRuntime.js +60 -45
  22. package/src/client/providers/AssistantClientProvider.js +1 -0
  23. package/src/client/support/assistantRuntimeState.js +6 -34
  24. package/src/client/support/conversationFailures.js +30 -0
  25. package/src/client/support/conversationRestoreSupport.js +13 -5
  26. package/src/client/support/subscribeAssistantConversation.js +32 -9
  27. package/src/client/support/workspaceScopeSupport.js +13 -22
  28. package/src/client/types.js +46 -0
  29. package/src/server/AssistantProvider.js +45 -17
  30. package/src/server/actions.js +162 -201
  31. package/src/server/conversationOperations.js +141 -0
  32. package/src/server/createAssistantRuntime.js +83 -44
  33. package/src/server/createAssistantSettingsActions.js +69 -47
  34. package/src/server/hostedAssistant.js +21 -0
  35. package/src/server/index.js +1 -0
  36. package/src/server/registerConversationSubscriptions.js +34 -11
  37. package/src/server/registerFastifyConversations.js +18 -6
  38. package/src/server/registerRoutes.js +5 -2
  39. package/src/server/registerSettingsRoutes.js +1 -1
  40. package/src/server/repositories/assistantConfigRepository.js +10 -20
  41. package/src/server/repositories/conversationsRepository.js +35 -10
  42. package/src/server/repositories/messagesRepository.js +14 -10
  43. package/src/server/repositories/repositoryPersistenceUtils.js +1 -6
  44. package/src/server/repositories/turnRequestsRepository.js +6 -1
  45. package/src/server/services/assistantConfigService.js +25 -23
  46. package/src/server/services/chatService.js +57 -61
  47. package/src/server/services/transcriptService.js +15 -7
  48. package/src/server/sqlConversationStorage.js +90 -18
  49. package/src/server/support/assistantServerConfig.js +1 -1
  50. package/src/server/support/assistantStreamWriter.js +7 -1
  51. package/src/server/support/createSurfaceAwareToolCatalog.js +35 -17
  52. package/src/server/types.js +38 -0
  53. package/src/shared/assistantSurfaces.js +2 -2
  54. package/test/assistantConversationBinding.browser.test.js +115 -1
  55. package/test/assistantConversationOperations.test.js +5 -5
  56. package/test/assistantRuntimeState.test.js +1 -16
  57. package/test/chatServiceLifecycle.test.js +62 -154
  58. package/test/createSurfaceAwareToolCatalog.test.js +5 -0
  59. package/test/featureRuntime.test.js +12 -6
  60. package/test/lazyAppConfig.test.js +3 -5
  61. package/test/packageMetadata.test.js +7 -1
  62. package/test/sqlConversationStorage.mysql.test.js +89 -0
  63. package/test/sqlConversationStorage.test.js +161 -16
  64. package/test/support/memoryAssistantRows.js +6 -1
  65. package/test/support/scriptedModel.js +32 -0
  66. package/test/turnRequests.test.js +4 -2
  67. package/test/usersForeignKeysMigration.test.js +46 -0
  68. package/test/workspacesForeignKeysMigration.test.js +66 -0
  69. package/src/client/support/accessDenied.js +0 -6
package/README.md CHANGED
@@ -19,7 +19,7 @@ Main exports by subpath:
19
19
 
20
20
  | Subpath | Provides |
21
21
  | --- | --- |
22
- | `@jskit-ai/assistant-runtime/server` | `AssistantFeature`, `createAssistantActions`, `registerAssistantRoutes`, `registerConversationSubscriptions`, `registerFastifyConversations` |
22
+ | `@jskit-ai/assistant-runtime/server` | `AssistantFeature`, `createAssistantActions`, `registerAssistantRoutes`, `registerConversationSubscriptions`, `registerFastifyConversations`, `createSurfaceAwareToolCatalog` |
23
23
  | `@jskit-ai/assistant-runtime/server/actionIds` | Assistant action identifiers |
24
24
  | `@jskit-ai/assistant-runtime/client` | `AssistantConversationClientElement`, `AssistantSurfaceClientElement`, `AssistantSettingsClientElement`, `useAssistantConversation`, `configureAssistantConversations` |
25
25
  | `@jskit-ai/assistant-runtime/shared` | Assistant surface configuration helpers |
@@ -10,12 +10,13 @@ import { createWebPlacementRuntime } from "../../../shell-web/src/client/placeme
10
10
  import { createFixtureSocket } from "./socket.js";
11
11
  import { assistantHttpClient, createAssistantApi } from "@jskit-ai/assistant-core/client";
12
12
  import { configureAssistantConversations, useAssistantConversation } from "../../src/client/composables/useAssistantConversation.js";
13
+ import { silentLogger } from "@jskit-ai/kernel/shared/support/silentLogger";
13
14
 
14
15
  globalThis.__JSKIT_CLIENT_APP_CONFIG__ = {
15
16
  surfaceDefinitions: { home: { requiresWorkspace: false } },
16
17
  assistantSurfaces: { home: { settingsSurfaceId: "home", configScope: "global" } }
17
18
  };
18
- const placement = createWebPlacementRuntime({ components: new Map() });
19
+ const placement = createWebPlacementRuntime({ components: new Map(), logger: silentLogger });
19
20
  placement.setContext({ user: { id: "42" }, surfaceConfig: {
20
21
  defaultSurfaceId: "home", surfacesById: { home: { id: "home", routeBase: "/", requiresWorkspace: false } }
21
22
  } });
@@ -110,6 +110,12 @@ export default defineConfig({
110
110
  for (const pending of held.splice(0)) pending.respond(pending.receipt);
111
111
  return json({ ok: true });
112
112
  }
113
+ if (url.pathname === "/fixture/start-queued-goal") {
114
+ const state = states.get(input.id);
115
+ changeGoal(state, state.queuedGoal);
116
+ state.queuedGoal = null;
117
+ return json({ ok: true });
118
+ }
113
119
  if (url.pathname === "/fixture/finish") {
114
120
  const state = states.get(input.id);
115
121
  state.status = "ready";
@@ -145,6 +151,11 @@ export default defineConfig({
145
151
  }
146
152
  const receipt = command.delivery === "message" ? accept(state, { messageId: input.messageId,
147
153
  text: input.objective || (input.action === "resume" ? "Resume the goal." : "Cancel the goal.") }) : null;
154
+ // The command is accepted behind the running turn; its goal changes later.
155
+ if (receipt && mode === "queue-goal") {
156
+ state.queuedGoal = input;
157
+ return json(receipt);
158
+ }
148
159
  changeGoal(state, input);
149
160
  const result = receipt || state.goal || null;
150
161
  return json(result, result === null ? 204 : 200);
@@ -8,6 +8,7 @@ import { aliases, mdi } from "vuetify/iconsets/mdi-svg";
8
8
  import "vuetify/styles";
9
9
  import App from "./App.vue";
10
10
  import { createWebPlacementRuntime } from "../../../shell-web/src/client/placement/runtime.js";
11
+ import { silentLogger } from "@jskit-ai/kernel/shared/support/silentLogger";
11
12
 
12
13
  globalThis.__JSKIT_CLIENT_APP_CONFIG__ = {
13
14
  surfaceDefinitions: { admin: { requiresWorkspace: true }, console: { requiresWorkspace: false } },
@@ -18,7 +19,7 @@ globalThis.__JSKIT_CLIENT_APP_CONFIG__ = {
18
19
  };
19
20
  const router = createRouter({ history: createWebHistory(), routes: [{ path: "/:pathMatch(.*)*", component: App }] });
20
21
  const app = createApp(App);
21
- const placement = createWebPlacementRuntime({ components: new Map() });
22
+ const placement = createWebPlacementRuntime({ components: new Map(), logger: silentLogger });
22
23
  placement.setContext({ user: { id: "1" }, surfaceConfig: {
23
24
  defaultSurfaceId: "admin",
24
25
  surfacesById: { admin: { id: "admin", routeBase: "/", requiresWorkspace: false } }
@@ -3,6 +3,7 @@ import { createChatService } from "../../src/server/services/chatService.js";
3
3
  import { ASSISTANT_STREAM_WRITER_METHODS } from "../../src/server/support/assistantStreamWriter.js";
4
4
  import { createAssistantConversationRuntime } from "../../src/server/createAssistantRuntime.js";
5
5
  import { createMemoryAssistantRows } from "../../test/support/memoryAssistantRows.js";
6
+ import { createScriptedModel } from "../../test/support/scriptedModel.js";
6
7
  import { defineConfig } from "vite";
7
8
  import vue from "@vitejs/plugin-vue";
8
9
  import { fileURLToPath } from "node:url";
@@ -66,14 +67,14 @@ export default defineConfig({
66
67
  turnRequests,
67
68
  aiClientFactory: { async resolveClient(_surface, { integrationId }) {
68
69
  return { enabled: true, provider: "fixture", defaultModel: integrationId, supportsAttachments: true,
69
- async *createChatCompletionStream({ messages }) {
70
+ model: createScriptedModel(async function* ({ messages }) {
70
71
  stream.receivedFiles = messages.at(-1).content;
71
72
  await nextChunk();
72
73
  yield { choices: [{ delta: { content: "Partial answer" } }] };
73
74
  await nextChunk();
74
75
  yield { choices: [{ delta: { content: " completed." } }] };
75
76
  yield { choices: [{ delta: {}, finish_reason: "stop" }] };
76
- }
77
+ }, { model: integrationId })
77
78
  };
78
79
  } },
79
80
  attachments: { async resolve({ attachmentIds }) {
@@ -118,7 +119,7 @@ export default defineConfig({
118
119
  const older = url.searchParams.has("page[cursor]");
119
120
  return json({ data: [{ type: "assistant-conversations", id: older ? "2" : "1", attributes: {
120
121
  title: older ? "Older conversation" : "Saved conversation", status: "completed", startedAt: "2026-09-01T00:00:00Z"
121
- } }], meta: { page: { nextCursor: older ? null : "older" } } });
122
+ } }], meta: { pagination: { cursor: { next: older ? null : "older" } } } });
122
123
  }
123
124
  res.statusCode = 404;
124
125
  json({ error: "Unknown fixture request" });
package/locales/en.json CHANGED
@@ -74,6 +74,7 @@
74
74
  "goal": {
75
75
  "budgetsUnsupported": "This conversation does not support goal token budgets.",
76
76
  "changeFailed": "Could not change the goal.",
77
+ "notStarted": "The goal did not start. Check the chat before starting it again.",
77
78
  "unavailable": "Goal status is unavailable.",
78
79
  "resumeMessage": "Resume the goal.",
79
80
  "cancelMessage": "Cancel the goal."
@@ -1,16 +1,12 @@
1
1
  exports.up = async function up(knex) {
2
2
  const hasTable = await knex.schema.hasTable("assistant_config");
3
3
  if (!hasTable) {
4
- const hasWorkspacesTable = await knex.schema.hasTable("workspaces");
5
-
6
4
  await knex.schema.createTable("assistant_config", (table) => {
7
5
  table.bigIncrements("id").primary();
8
6
  table.string("target_surface_id", 64).notNullable();
9
7
  table.string("scope_key", 160).notNullable();
8
+ // constraints/assistant_workspaces_foreign_keys.cjs adds the workspaces key when that table exists.
10
9
  table.bigInteger("workspace_id").unsigned().nullable();
11
- if (hasWorkspacesTable) {
12
- table.foreign("workspace_id").references("id").inTable("workspaces").onDelete("CASCADE");
13
- }
14
10
  table.text("system_prompt").notNullable().defaultTo("");
15
11
  table.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
16
12
  table.timestamp("updated_at").notNullable().defaultTo(knex.fn.now());
@@ -1,14 +1,11 @@
1
+ // constraints/ adds the users keys, and the workspaces keys when that table exists.
1
2
  exports.up = async function up(knex) {
2
- const hasWorkspacesTable = await knex.schema.hasTable("workspaces");
3
3
  const hasConversationsTable = await knex.schema.hasTable("assistant_conversations");
4
4
  if (!hasConversationsTable) {
5
5
  await knex.schema.createTable("assistant_conversations", (table) => {
6
6
  table.bigIncrements("id").primary();
7
7
  table.bigInteger("workspace_id").unsigned().nullable();
8
- if (hasWorkspacesTable) {
9
- table.foreign("workspace_id").references("id").inTable("workspaces").onDelete("CASCADE");
10
- }
11
- table.bigInteger("created_by_user_id").unsigned().nullable().references("id").inTable("users").onDelete("SET NULL").index();
8
+ table.bigInteger("created_by_user_id").unsigned().nullable().index();
12
9
  table.string("title", 160).notNullable().defaultTo("New conversation");
13
10
  table.string("status", 32).notNullable().defaultTo("active");
14
11
  table.string("provider", 64).notNullable().defaultTo("");
@@ -33,14 +30,11 @@ exports.up = async function up(knex) {
33
30
  table.bigIncrements("id").primary();
34
31
  table.bigInteger("conversation_id").unsigned().notNullable().references("id").inTable("assistant_conversations").onDelete("CASCADE");
35
32
  table.bigInteger("workspace_id").unsigned().nullable();
36
- if (hasWorkspacesTable) {
37
- table.foreign("workspace_id").references("id").inTable("workspaces").onDelete("CASCADE");
38
- }
39
33
  table.integer("seq").unsigned().notNullable();
40
34
  table.string("role", 32).notNullable();
41
35
  table.string("kind", 32).notNullable().defaultTo("chat");
42
36
  table.string("client_message_sid", 128).notNullable().defaultTo("");
43
- table.bigInteger("actor_user_id").unsigned().nullable().references("id").inTable("users").onDelete("SET NULL").index();
37
+ table.bigInteger("actor_user_id").unsigned().nullable().index();
44
38
  table.text("content_text").nullable();
45
39
  table.text("metadata_json").nullable();
46
40
  table.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
@@ -0,0 +1,28 @@
1
+ // A long conversation keeps one compaction summary next to its messages, which are never
2
+ // deleted: the summary text and the last turn it covers. transcript_revision changes on
3
+ // every saved transcript change, so a server can keep reusing the rows it already read.
4
+ const COLUMNS = ["summary_text", "summary_through_turn_id", "transcript_revision"];
5
+
6
+ exports.up = async function up(knex) {
7
+ const missing = [];
8
+ for (const column of COLUMNS) {
9
+ if (!await knex.schema.hasColumn("assistant_conversations", column)) missing.push(column);
10
+ }
11
+ if (!missing.length) return;
12
+ await knex.schema.alterTable("assistant_conversations", table => {
13
+ if (missing.includes("summary_text")) table.text("summary_text", "longtext").nullable();
14
+ if (missing.includes("summary_through_turn_id")) table.string("summary_through_turn_id", 64).nullable();
15
+ if (missing.includes("transcript_revision")) table.string("transcript_revision", 36).nullable();
16
+ });
17
+ };
18
+
19
+ exports.down = async function down(knex) {
20
+ const present = [];
21
+ for (const column of COLUMNS) {
22
+ if (await knex.schema.hasColumn("assistant_conversations", column)) present.push(column);
23
+ }
24
+ if (!present.length) return;
25
+ await knex.schema.alterTable("assistant_conversations", table => {
26
+ table.dropColumns(...present);
27
+ });
28
+ };
@@ -2,7 +2,8 @@ exports.up = async function up(knex) {
2
2
  if (await knex.schema.hasTable("assistant_turn_requests")) return;
3
3
  await knex.schema.createTable("assistant_turn_requests", table => {
4
4
  table.bigIncrements("id").primary();
5
- table.bigInteger("actor_user_id").unsigned().notNullable().references("id").inTable("users").onDelete("CASCADE");
5
+ // constraints/assistant_users_foreign_keys.cjs adds the users key once the users table exists.
6
+ table.bigInteger("actor_user_id").unsigned().notNullable();
6
7
  table.string("scope_key", 128).notNullable();
7
8
  table.string("message_sid", 128).notNullable();
8
9
  table.string("claim_token", 36).notNullable();
@@ -0,0 +1,22 @@
1
+ // The users table can come from the application's own migrations, which run after every
2
+ // package's table migrations, so the assistant tables get their users keys in this later phase.
3
+ // A database migrated before this file already has them from the table migrations.
4
+ const USER_KEYS = [
5
+ { tableName: "assistant_conversations", columnName: "created_by_user_id", parentTable: "users", onDelete: "SET NULL" },
6
+ { tableName: "assistant_messages", columnName: "actor_user_id", parentTable: "users", onDelete: "SET NULL" },
7
+ { tableName: "assistant_turn_requests", columnName: "actor_user_id", parentTable: "users", onDelete: "CASCADE" }
8
+ ];
9
+
10
+ exports.up = async function up(knex) {
11
+ const { addMissingForeignKey } = await import("@jskit-ai/database-runtime/server/foreignKeyMigrations");
12
+ for (const key of USER_KEYS) {
13
+ await addMissingForeignKey(knex, key);
14
+ }
15
+ };
16
+
17
+ exports.down = async function down(knex) {
18
+ const { dropForeignKeyIfPresent } = await import("@jskit-ai/database-runtime/server/foreignKeyMigrations");
19
+ for (const key of USER_KEYS) {
20
+ await dropForeignKeyIfPresent(knex, key);
21
+ }
22
+ };
@@ -0,0 +1,26 @@
1
+ // workspaces-core's migrations run after assistant-runtime's, and an application may create
2
+ // workspaces itself, so the assistant tables get their workspaces keys in this later phase, when
3
+ // that table exists; an application without workspaces gets none.
4
+ // A database migrated before this file may already have them from the table migrations.
5
+ const WORKSPACE_KEYS = [
6
+ { tableName: "assistant_config", columnName: "workspace_id", parentTable: "workspaces", onDelete: "CASCADE" },
7
+ { tableName: "assistant_conversations", columnName: "workspace_id", parentTable: "workspaces", onDelete: "CASCADE" },
8
+ { tableName: "assistant_messages", columnName: "workspace_id", parentTable: "workspaces", onDelete: "CASCADE" }
9
+ ];
10
+
11
+ exports.up = async function up(knex) {
12
+ if (!(await knex.schema.hasTable("workspaces"))) {
13
+ return;
14
+ }
15
+ const { addMissingForeignKey } = await import("@jskit-ai/database-runtime/server/foreignKeyMigrations");
16
+ for (const key of WORKSPACE_KEYS) {
17
+ await addMissingForeignKey(knex, key);
18
+ }
19
+ };
20
+
21
+ exports.down = async function down(knex) {
22
+ const { dropForeignKeyIfPresent } = await import("@jskit-ai/database-runtime/server/foreignKeyMigrations");
23
+ for (const key of WORKSPACE_KEYS) {
24
+ await dropForeignKeyIfPresent(knex, key);
25
+ }
26
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/assistant-runtime",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test --test-concurrency=1"
@@ -10,22 +10,23 @@
10
10
  "./shared": "./src/shared/index.js",
11
11
  "./server/actionIds": "./src/server/actionIds.js",
12
12
  "./server": "./src/server/index.js",
13
+ "./server/types": "./src/server/types.js",
13
14
  "./locales/en.json": "./locales/en.json"
14
15
  },
15
16
  "dependencies": {
16
- "@jskit-ai/assistant-core": "0.2.6",
17
+ "@jskit-ai/assistant-core": "0.2.8",
17
18
  "json-rest-schema": "^1.0.17"
18
19
  },
19
20
  "peerDependencies": {
20
- "@jskit-ai/http-runtime": "0.2.3",
21
- "@jskit-ai/http-web": "0.2.7",
22
- "@jskit-ai/kernel": "0.2.3",
23
- "@jskit-ai/realtime": "0.2.6",
24
- "@jskit-ai/shell-web": "0.2.3",
21
+ "@jskit-ai/http-runtime": "0.2.4",
22
+ "@jskit-ai/http-web": "0.2.8",
23
+ "@jskit-ai/kernel": "0.2.4",
24
+ "@jskit-ai/realtime": "0.2.7",
25
+ "@jskit-ai/shell-web": "0.2.4",
25
26
  "@tanstack/vue-query": "^5.90.5",
26
27
  "vue": "^3.5.13",
27
28
  "vuetify": "^4.0.0",
28
- "@jskit-ai/database-runtime": "0.1.252"
29
+ "@jskit-ai/database-runtime": "0.1.253"
29
30
  },
30
31
  "description": "Capability-based assistant runtime with per-surface chat, transcripts, settings, and action tools.",
31
32
  "jskit": {
@@ -38,8 +39,10 @@
38
39
  "runtime.actions",
39
40
  "runtime.config",
40
41
  "runtime.env",
42
+ "runtime.events",
41
43
  "runtime.http",
42
- "runtime.http-web"
44
+ "runtime.http-web",
45
+ "runtime.logger"
43
46
  ]
44
47
  },
45
48
  "runtime": {
@@ -95,7 +98,11 @@
95
98
  },
96
99
  {
97
100
  "subpath": "./server",
98
- "summary": "Provides conversation routes, authorized shared realtime subscriptions, explicit Fastify hosting shorthand and optional database integration."
101
+ "summary": "Provides conversation routes, authorized shared realtime subscriptions, explicit Fastify hosting shorthand, optional database integration and the per-surface assistant tool catalogue."
102
+ },
103
+ {
104
+ "subpath": "./server/types",
105
+ "summary": "Type of the assistant.runtime capability, and the contracts of the optional capabilities it reads."
99
106
  }
100
107
  ],
101
108
  "capabilities": [
@@ -1,3 +1,4 @@
1
+ import { resolveActorId } from "@jskit-ai/kernel/server/actions/actionContributorHelpers";
1
2
  import { defineFeature } from "@jskit-ai/kernel/server/features";
2
3
  import { createAiConnectionResolver } from "@jskit-ai/connectors-catalog/server/ai";
3
4
  import { createEnvironmentReferenceResolver } from "@jskit-ai/connectors-core/server";
@@ -10,9 +11,10 @@ export const ApplicationAiFeature = defineFeature({
10
11
  return { ai: createAiConnectionResolver({
11
12
  configuration,
12
13
  authorize(context) {
13
- if (!context.actor?.id) return null;
14
+ const actorId = resolveActorId(context);
15
+ if (!actorId) return null;
14
16
  // Apply the app's AI-use policy here; the actor comes from authentication.
15
- return { applicationId: "my-app", subjectId: String(context.actor.id) };
17
+ return { applicationId: "my-app", subjectId: actorId };
16
18
  },
17
19
  resolveReference: createEnvironmentReferenceResolver(env)
18
20
  }) };
@@ -4,6 +4,11 @@ import { AssistantConversationElement } from "@jskit-ai/assistant-core/client/co
4
4
  import { useAssistantConversation } from "../composables/useAssistantConversation.js";
5
5
  import { useJskitText } from "../i18n.js";
6
6
 
7
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantApi} AssistantApi */
8
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantAttachments} AssistantAttachments */
9
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantSuggestions} AssistantSuggestions */
10
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantModelChoices} AssistantModelChoices */
11
+
7
12
  const props = defineProps({
8
13
  conversationId: { type: String, required: true },
9
14
  endpoint: { type: String, default: "" },
@@ -11,7 +16,8 @@ const props = defineProps({
11
16
  hostSurfaceId: { type: String, default: "" },
12
17
  workspaceSlug: { type: String, default: undefined },
13
18
  actorKey: { type: String, default: undefined },
14
- api: { type: Object, default: null },
19
+ // An application's own assistant API; without one the binding uses the surface's standard API.
20
+ api: { type: /** @type {import("vue").PropType<AssistantApi>} */ (Object), default: null },
15
21
  active: { type: Boolean, default: true },
16
22
  clearDraftOn: { type: String, default: undefined, validator: value => ["dispatch", "accepted"].includes(value) },
17
23
  // Unset texts follow the active language; an application's own text is shown as given.
@@ -20,9 +26,9 @@ const props = defineProps({
20
26
  placeholder: { type: String, default: undefined },
21
27
  layout: { type: String, default: "compact", validator: value => ["page", "compact"].includes(value) },
22
28
  data: { type: Object, default: undefined },
23
- attachments: { type: Object, default: null },
24
- suggestions: { type: Object, default: null },
25
- models: { type: Object, default: null },
29
+ attachments: { type: /** @type {import("vue").PropType<AssistantAttachments>} */ (Object), default: null },
30
+ suggestions: { type: /** @type {import("vue").PropType<AssistantSuggestions>} */ (Object), default: null },
31
+ models: { type: /** @type {import("vue").PropType<AssistantModelChoices>} */ (Object), default: null },
26
32
  questions: { type: [Boolean, Object], default: null },
27
33
  goal: { type: [Boolean, Object], default: null },
28
34
  avatarSize: { type: String, default: "compact", validator: (value) => ["hidden", "compact", "standard", "large"].includes(value) }
@@ -6,6 +6,10 @@ import { mapAssistantConversationTurns, toolStatusText } from "../support/assist
6
6
  import { DEFAULT_CONVERSATION_TITLE } from "../../shared/assistantRuntimeConfig.js";
7
7
  import { useJskitText } from "../i18n.js";
8
8
 
9
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantConversationAdapter} AssistantConversationAdapter */
10
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantAttachments} AssistantAttachments */
11
+ /** @typedef {import("@jskit-ai/assistant-core/client/types").AssistantSuggestions} AssistantSuggestions */
12
+
9
13
  const props = defineProps({
10
14
  surfaceId: { type: String, required: true },
11
15
  layout: { type: String, default: "page", validator: (value) => ["page", "compact"].includes(value) },
@@ -15,10 +19,10 @@ const props = defineProps({
15
19
  placeholder: { type: String, default: undefined },
16
20
  showToolActivity: { type: Boolean, default: true },
17
21
  connections: { type: Array, default: () => [] },
18
- attachments: { type: Object, default: null },
19
- suggestions: { type: Object, default: null },
20
- goal: { type: Object, default: null },
21
- activity: { type: Object, default: undefined },
22
+ attachments: { type: /** @type {import("vue").PropType<AssistantAttachments>} */ (Object), default: null },
23
+ suggestions: { type: /** @type {import("vue").PropType<AssistantSuggestions>} */ (Object), default: null },
24
+ goal: { type: /** @type {import("vue").PropType<AssistantConversationAdapter["goal"]>} */ (Object), default: null },
25
+ activity: { type: /** @type {import("vue").PropType<AssistantConversationAdapter["activity"]>} */ (Object), default: undefined },
22
26
  configurationMode: { type: String, default: "editable", validator: value => ["hidden", "readonly", "editable"].includes(value) }
23
27
  });
24
28
  const integrationId = defineModel("integrationId", { type: String, default: "" });