@jskit-ai/agent-docs 0.1.161 → 0.1.163

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 (24) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +277 -0
  2. package/guide/agent/app-extras/assistant.md +4 -0
  3. package/guide/agent/app-extras/realtime.md +12 -0
  4. package/package.json +1 -1
  5. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  6. package/patterns/minimal-foundation/example/package.json +4 -4
  7. package/patterns/shell-foundation/example/package.json +5 -5
  8. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  9. package/reference/autogen/PATTERN_INDEX.md +35 -35
  10. package/reference/autogen/packages/assistant-core.md +308 -0
  11. package/reference/autogen/packages/realtime.md +4 -0
  12. package/skills/jskit/references/pattern-index.md +35 -35
  13. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +4 -4
  14. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +5 -5
  15. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  16. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  17. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  18. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
  19. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  20. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  21. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  22. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
  23. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
  24. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
@@ -0,0 +1,277 @@
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-extras/assistant-conversation.md`. Do not edit manually. -->
2
+
3
+ # Embeddable assistant conversations
4
+
5
+ `@jskit-ai/assistant-core` supplies a Vue/Vuetify conversation element, transcript
6
+ policy, and native provider primitives. It has no dependency on an editor,
7
+ project directory, application database, identity scheme, or avatar.
8
+
9
+ Use this contract when the application already owns its conversation endpoints
10
+ or needs custom storage and provider execution. Applications using the complete
11
+ JSKIT assistant surface can continue to use [Assistant](./assistant.md), which
12
+ owns its routes, database repositories, action-tool loop, and settings.
13
+ Choose one transcript owner for a conversation.
14
+
15
+ ## Ownership
16
+
17
+ | JSKIT owns | The application supplies |
18
+ | --- | --- |
19
+ | Bubbles, rich text, reasoning groups, long-message expansion, scroll following, composer, delivery controls | Conversation selection, labels, loading/errors, current draft and action implementations |
20
+ | Turn grouping, message deduplication, final-answer replacement and history pagination | Storage adapter, authorized scope, transaction/locking implementation, retention, migrations and attachment bytes |
21
+ | Codex JSON-RPC and notification classification, detached-turn completion/recovery, OpenCode HTTP/SSE | Provider process/connection, account credentials, execution environment, permissions, tools, model policy and reconnect ownership |
22
+ | Display of supplied configuration and optional editing controls | Authoritative configuration, permitted changes and server validation |
23
+
24
+ No global store or router is installed by the element. Multiple assistants can
25
+ coexist with separate adapters. The application mounts it in a pane with a
26
+ definite height and `min-height: 0`.
27
+
28
+ ## Client contract
29
+
30
+ ```js
31
+ import { AssistantConversationElement } from "@jskit-ai/assistant-core/client/conversation";
32
+
33
+ const adapter = reactive({
34
+ conversation: {
35
+ turns, visible: true, loading, error, scrollKey: conversationId,
36
+ assistantLabel: "Assistant", hasMoreBefore, loadingMore, loadMoreError
37
+ },
38
+ composer: {
39
+ draft, disabled, canSend, pending, canStop, stopDisabled, stopPending,
40
+ placeholder: "Ask a question…", submitLabel: "Send"
41
+ },
42
+ actions: {
43
+ setDraft, submit, stop, loadMore, reload, resend, cancel, edit, openLink,
44
+ updateConfiguration
45
+ }
46
+ });
47
+ ```
48
+
49
+ Use reactive values or replace the adapter when state changes. Ordinary nested
50
+ objects containing refs must be wrapped in `reactive()` so their fields unwrap.
51
+ Only `conversation` is required; omit `composer` for a transcript-only view.
52
+ Missing optional actions are ignored. Supply `setDraft` and `submit` when a
53
+ composer is present, and `stop` when `canStop` can become true.
54
+
55
+ | Action | Arguments and responsibility |
56
+ | --- | --- |
57
+ | `setDraft(text)` | Update the application draft synchronously. |
58
+ | `submit({ configuration })` | Send or steer through the app's normal admission, attachment and delivery path. Own pending state, accepted-draft clearing and visible failures. The element checks `canSend` before calling. |
59
+ | `stop()` | Stop the owned provider turn. Own pending state and errors; the element checks stop availability. |
60
+ | `loadMore({ complete })` | Prepend older turns, then call `complete({ changed })` after updating reactive state. Call it on failures too; this releases the scroll anchor. |
61
+ | `reload()` | Refresh authoritative history. |
62
+ | `resend(id)`, `cancel(id)`, `edit(id)` | Handle a failed optimistic turn using its stable `optimistic.id`. Retry according to server delivery evidence. |
63
+ | `openLink({ event, href, text })` | Optionally handle app-owned links and call `event.preventDefault()`. Otherwise a validated ordinary link keeps normal browser behavior. |
64
+ | `updateConfiguration(value)` | Accept an edited draft configuration; the server remains authoritative. |
65
+
66
+ `scrollKey` changes when conversation ownership changes, resetting scroll and
67
+ expansion state. `followLatestKey` requests following the newest message.
68
+ `reloadable`, `reloading`, `welcomeMessage`, and `variant: "main" | "task"`
69
+ control the corresponding transcript presentation. `userMessageFormat` is
70
+ `"formatted"` by default; `"plain"` preserves literal user-authored text.
71
+
72
+ ### Turns and messages
73
+
74
+ ```js
75
+ {
76
+ turnId: "stable-app-turn-id",
77
+ user: { messageId: "request-id", role: "user", text: "Hello", at: "2026-01-01T00:00:00Z", attachments: [] },
78
+ assistant: { messageId: "reply-id", role: "assistant", text: "Hello back", at: "2026-01-01T00:00:01Z" },
79
+ messages: [/* ordered user, thinking, commentary and assistant messages */],
80
+ pending: false,
81
+ metadata: { /* application data */ }
82
+ }
83
+ ```
84
+
85
+ `system` is an optional status message. Without `messages`, the transcript uses
86
+ the turn's `thinking`, `commentary`, and `assistant` fields. Keep IDs stable across
87
+ updates and pagination. The UI never uses provider-internal turn IDs to decide
88
+ application ownership. An optimistic turn can carry
89
+ `optimistic: { id, status: "failed", error }`.
90
+
91
+ For an existing flat history, import `conversationTurnsFromMessages` from
92
+ `@jskit-ai/assistant-core/shared/conversation`. It groups ordered messages,
93
+ retains application fields, converts `progressUpdates` into reasoning, and
94
+ recognizes `starting`, `inProgress`, `interrupted`, and `failed` statuses.
95
+ Messages require `text`; applications map names such as `content` explicitly.
96
+
97
+ ### Configuration and slots
98
+
99
+ ```vue
100
+ <AssistantConversationElement
101
+ :adapter="adapter"
102
+ :configuration="configuration"
103
+ configuration-mode="hidden"
104
+ />
105
+ ```
106
+
107
+ `hidden` hides configuration controls while still passing the supplied object to
108
+ `submit`. `readonly` displays disabled controls. `editable` calls
109
+ `updateConfiguration`. `configurationFields` supplies optional select fields:
110
+ `[{ name, label, items }]`. The `configuration` slot can replace those controls;
111
+ it receives `{ configuration, disabled, update }`. Pending sends disable edits.
112
+ Hiding or disabling controls does **not** authorize backend configuration. The
113
+ server must choose or validate model, tool and permission settings itself.
114
+
115
+ Other slots:
116
+
117
+ | Slot | Scope / use |
118
+ | --- | --- |
119
+ | `attachments` | `{ items, message }`; app-owned downloads/previews and access checks |
120
+ | `message-actions` | `{ message, turn }`; integration approvals, SQL actions or other app behavior |
121
+ | `system-message` | `{ message }`; status/repair actions |
122
+ | `hints` | `{ adapter }`; app progress/status/errors above the composer |
123
+ | `composer` | `{ adapter }`; replace the composer while keeping the shared transcript |
124
+ | `input-start`, `composer-tools` | `{ adapter }`; app-owned input adornments and tools |
125
+
126
+ `AssistantTranscript`, `AssistantPromptInput`, `AssistantComposerActions`, and
127
+ `AssistantProgress` are exported separately for compositions with retained
128
+ drafts or app-managed uploads. `AssistantPromptInput` accepts `attachmentState`
129
+ and an `attachments` slot; it never uploads or deletes files. Its exposed methods
130
+ are `focus()`, `preserveHeightForNextModelValue()` and `queueResizeTextarea()`;
131
+ `inputElement` exposes the textarea for app-owned editing operations.
132
+
133
+ ## Backend storage contract
134
+
135
+ ```js
136
+ import {
137
+ createConversationTranscript, createMemoryConversationStorage
138
+ } from "@jskit-ai/assistant-core/server/conversation";
139
+
140
+ const transcript = createConversationTranscript({ storage: createMemoryConversationStorage() });
141
+ await transcript.writeConversationUserMessage(scope, { messageId: requestId, text });
142
+ const { conversationLog, pagination } = await transcript.readConversationLogPage(scope, { limit: 20 });
143
+ ```
144
+
145
+ The memory adapter is explicitly transient. Applications may supply SQL,
146
+ filesystem, document-store, or other storage. JSKIT neither chooses a directory
147
+ nor creates database tables. The storage object implements:
148
+
149
+ ```js
150
+ {
151
+ read(scope, async transaction => result),
152
+ write(scope, async transaction => result)
153
+ }
154
+ ```
155
+
156
+ `scope` is opaque to the transcript service. The **server application** derives
157
+ it from the authenticated actor, workspace and conversation. Never pass a
158
+ client-supplied scope directly into storage. Apply the same authorization to
159
+ history, sends, stops, deletion and attachment reads. The memory reference
160
+ adapter requires a nonempty string; other adapters may use structured scopes.
161
+
162
+ Each callback receives these asynchronous operations:
163
+
164
+ | Transaction operation | Contract |
165
+ | --- | --- |
166
+ | `listTurnIds()` | Stable IDs in oldest-to-newest order; include all stored turns. |
167
+ | `readTurn(id)` | Detached turn snapshot in the client model above, or null if absent. |
168
+ | `nextTurnId()` | Allocate an ID after the current tail under the write lock. |
169
+ | `hasMessage(messageId)` | Check uniqueness across the whole scoped conversation. |
170
+ | `appendMessage(turnId, message)` | Save `{ role, text, messageId, at }`; user messages also carry `attachments` and `turnMetadata`. |
171
+ | `replaceAssistant(turnId, message)` | Idempotently replace the final answer for that exact turn, preserving its existing timestamp/identity. |
172
+
173
+ `write` serializes mutations for the same scope, including duplicate checks and
174
+ ID allocation. A successful return means the write is durable for that adapter.
175
+ Database adapters should use a transaction; filesystem adapters must publish
176
+ the message only after its attachment references and metadata are recoverable.
177
+ Errors reject the operation and must remain visible to the caller. Do not
178
+ acknowledge a failed save. Reads must not expose mutable backing objects.
179
+ Use storage-level locks or transactions when several processes share storage;
180
+ an in-process promise queue alone does not provide that guarantee.
181
+
182
+ The service exposes `readConversationLog`, `readConversationLogPage`,
183
+ `conversationMessageIdExists`, `writeConversationUserMessage`,
184
+ `writeConversationAssistantMessage`, `writeConversationThinkingMessage`,
185
+ `writeConversationCommentaryMessage`, `writeConversationSystemMessage`, and
186
+ `upsertConversationAssistantMessage`. Blank messages and duplicate nonempty
187
+ message IDs return null. A caller must not interpret a duplicate as permission
188
+ to execute a provider turn again. Provider delivery can be uncertain even when
189
+ storage succeeded; the app owns its durable admission/reconciliation policy.
190
+
191
+ User and system messages open turns. Assistant/reasoning/commentary messages
192
+ attach to the last unanswered user turn when one exists. Activity can specify
193
+ `requireOpenTurn: true`. Final-answer replacement targets an explicit `turnId`.
194
+ User metadata and attachment descriptors are supplied to storage unchanged;
195
+ their schema, bytes, access controls, retention, cleanup, export and deletion
196
+ belong to the app. Never put provider credentials in transcript metadata.
197
+
198
+ Pagination takes `{ beforeTurnId, limit }`. `limit` is capped at 100; zero means
199
+ all turns. An unknown cursor reads the newest page. Results contain oldest-first
200
+ `conversationLog` and `pagination`, including `hasMoreBefore`,
201
+ `nextBeforeTurnId`, `oldestTurnId`, `newestTurnId`, and `totalTurnCount`.
202
+
203
+ Run the reusable adapter checks against an isolated fixture:
204
+
205
+ ```js
206
+ import { verifyConversationStorageContract } from "@jskit-ai/assistant-core/testing/conversation-storage";
207
+ await verifyConversationStorageContract(storage);
208
+ ```
209
+
210
+ Those checks cover scoped isolation, concurrent duplicate writes, stable
211
+ ordering, pagination, final replacement, attachments and detached reads. An
212
+ app must additionally test its authentication, crash/reopen behavior,
213
+ multi-process writes, failed commits and attachment cleanup.
214
+
215
+ ## Provider contract
216
+
217
+ API-model apps can use `createAiClient` and the existing tool-catalog helpers
218
+ from `@jskit-ai/assistant-core/server`, or the complete assistant runtime.
219
+ Native-agent hosts can import:
220
+
221
+ - `CodexAppServerJsonRpcClient` from `/server/codex-client`;
222
+ - notification classifiers from `/server/codex-events`;
223
+ - `createCodexAppServerDetachedTurnWatcher` from `/server/codex-turn`;
224
+ - `createOpenCodeServerClient` from `/server/opencode-client`.
225
+
226
+ These are real execution primitives, also consumed by applications with their
227
+ own process and permission owners. They do not spawn an agent, select a user
228
+ account, grant filesystem access or install tools.
229
+
230
+ The Codex client takes `{ endpoint, maxMessageBytes, requestTimeoutMs,
231
+ WebSocketImpl }`. It connects to a WebSocket or `unix://` endpoint, then
232
+ `initialize({ clientInfo, capabilities })` performs the native handshake.
233
+ `request(method, params, { signal })`, `subscribe(callback)`,
234
+ `setRequestHandler(callback)` and `close()` expose the connection. The app must
235
+ authorize server-initiated tool/approval requests. Missing handlers reject them.
236
+ Set transport limits appropriate to the host; the default payload limit is
237
+ unbounded. A request abort retires the local request; interrupt a running native
238
+ turn with `turn/interrupt` when cancellation must stop provider work.
239
+
240
+ The detached watcher takes `(provider, threadId, { includeThreadHistory,
241
+ onEvent, timeoutMs })`. `provider.subscribe` delivers native notifications;
242
+ `provider.readThread` supplies authoritative history when enabled. Call `wait()`
243
+ **before** starting the turn, then `setTurnId()` when startup acknowledges it.
244
+ This preserves completion/failure notifications that arrive before the start
245
+ response. `completeNow`, `failNow`, and `failAfterDetailGrace` handle authoritative
246
+ startup statuses. `onEvent` is a synchronous, nonthrowing observer; enqueue
247
+ asynchronous persistence in the application. The completion result contains
248
+ `{ status, text, threadId, turnId, usage }`. A zero timeout requires provider
249
+ `isAvailable()` and `currentConnectionGeneration()` for connection-loss checks.
250
+ Always await or handle the wait promise and retire it on startup failure.
251
+
252
+ The OpenCode client accepts a loopback HTTP `baseUrl`, `directory`, credentials,
253
+ and optional `fetchImpl`. It exposes native sessions, prompt, interruption,
254
+ messages, status, events, model/agent catalogues and account operations. Response
255
+ and event reads are bounded. `allowAttachmentDirectories` defaults to false;
256
+ enabling it grants the native conversation access to parent directories of
257
+ supplied attachments. Only the host can make that permission decision after
258
+ resolving and authorizing each file descriptor.
259
+
260
+ ## Companions and templates
261
+
262
+ A companion can receive an app-selected layer containing conversation state and
263
+ `submitText`, rather than searching the DOM. `createAssistantTextSubmission`
264
+ from `/client/conversation-submit` builds that action from
265
+ `{ getState, setDraft, submit, afterDraftChange }`. State is
266
+ `{ id, active, draft, canSend, turnActive }`. It preserves existing drafts,
267
+ supports `{ sendImmediately: false }`, waits briefly for send readiness, and
268
+ checks draft/ownership again before using the canonical submit action.
269
+ Pass an `AbortSignal` and abort it when selection, visibility or ownership
270
+ changes, including switching away and back to the same retained conversation.
271
+
272
+ The published package contains `examples/conversation`, a standalone Vue app
273
+ with a Node backend and no editor dependency. Copy it as an application template
274
+ or use the component directly. It runs without credentials using a labelled demo
275
+ provider; optional API credentials enable the existing JSKIT model client.
276
+ Its backend validates configuration independently of the UI and accepts a
277
+ replacement storage module. See its README for commands and scope limits.
@@ -13,6 +13,10 @@ npm run db:migrate
13
13
 
14
14
  Use the `assistant/assistant-surface` pattern. There is no assistant generator.
15
15
 
16
+ For an app-owned backend or custom conversation storage, use the
17
+ [embeddable conversation element and backend contracts](./assistant-conversation.md).
18
+ The package includes a standalone application template.
19
+
16
20
  ## Product decisions
17
21
 
18
22
  Choose:
@@ -69,6 +69,18 @@ A status indicator is optional product UI. When wanted, register it through the
69
69
  normal component and placement APIs. Installing realtime does not append it to
70
70
  the shell.
71
71
 
72
+ The standard status indicator is a button while disconnected. Clicking it starts
73
+ a fresh connection attempt. The client also retries server-initiated disconnects
74
+ and rejected handshakes, backing off from one second to at most thirty seconds.
75
+ Those extra retries pause while the page is hidden or offline and resume when it
76
+ becomes available. Socket.IO continues to own ordinary transport reconnection.
77
+ Explicit client disconnection and `reconnection: false` remain respected.
78
+
79
+ Every attempt goes through normal authentication. Reconnection does not restore
80
+ revoked access; an expired login still requires signing in. Applications should
81
+ preserve unsent input, distinguish disconnected status from running work, and
82
+ refresh authoritative state after reconnecting without resending mutations.
83
+
72
84
  ## Verification
73
85
 
74
86
  Test in-process delivery, audience isolation, authenticated-handshake rejection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.161",
3
+ "version": "0.1.163",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -5,7 +5,7 @@
5
5
  "private": true,
6
6
  "type": "module",
7
7
  "dependencies": {
8
- "@jskit-ai/kernel": "0.1.189",
8
+ "@jskit-ai/kernel": "0.1.191",
9
9
  "json-rest-schema": "^1.0.17"
10
10
  },
11
11
  "exports": {
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.189",
37
+ "@jskit-ai/kernel": "0.1.191",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,12 +42,12 @@
42
42
  "vue": "^3.5.38",
43
43
  "vue-router": "^5.1.0",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.187",
45
+ "@jskit-ai/http-runtime": "0.1.189",
46
46
  "@fastify/fast-json-stringify-compiler": "^5.1.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@jskit-ai/config-eslint": "0.1.186",
50
- "@jskit-ai/jskit-catalog": "0.1.214",
49
+ "@jskit-ai/config-eslint": "0.1.188",
50
+ "@jskit-ai/jskit-catalog": "0.1.216",
51
51
  "@playwright/test": "1.61.1",
52
52
  "@vitejs/plugin-vue": "^6.0.7",
53
53
  "eslint": "^10.8.0",
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.189",
37
+ "@jskit-ai/kernel": "0.1.191",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,14 +42,14 @@
42
42
  "vue": "^3.5.38",
43
43
  "vue-router": "^5.1.0",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.187",
45
+ "@jskit-ai/http-runtime": "0.1.189",
46
46
  "@mdi/js": "^7.4.47",
47
- "@jskit-ai/shell-web": "0.1.193",
47
+ "@jskit-ai/shell-web": "0.1.195",
48
48
  "@fastify/fast-json-stringify-compiler": "^5.1.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@jskit-ai/config-eslint": "0.1.186",
52
- "@jskit-ai/jskit-catalog": "0.1.214",
51
+ "@jskit-ai/config-eslint": "0.1.188",
52
+ "@jskit-ai/jskit-catalog": "0.1.216",
53
53
  "@playwright/test": "1.61.1",
54
54
  "@vitejs/plugin-vue": "^6.0.7",
55
55
  "eslint": "^10.8.0",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "description": "App-local runtime composition and lightweight glue.",
11
11
  "dependencies": {
12
- "@jskit-ai/kernel": "0.1.189"
12
+ "@jskit-ai/kernel": "0.1.191"
13
13
  },
14
14
  "jskit": {
15
15
  "kind": "runtime",