@things-factory/ai-assistant 10.1.47 → 10.1.50
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/client/components/assistant-chat.ts +97 -19
- package/client/components/assistant-dock.ts +617 -0
- package/client/components/assistant-mode.ts +2 -0
- package/client/components/assistant-session-manager.ts +607 -0
- package/client/components/chat-echo-dedup.ts +4 -0
- package/client/components/chat-input-builder.ts +4 -1
- package/client/components/panel-aria.test.ts +13 -8
- package/client/index.ts +8 -0
- package/client/setup-assistant-dock.ts +109 -0
- package/client/utils/assistant-activity.ts +122 -0
- package/client/utils/assistant-ask.ts +44 -0
- package/client/utils/assistant-proposals.ts +50 -0
- package/client/utils/assistant-session-actions.ts +18 -0
- package/client/utils/assistant-session-admin.ts +167 -0
- package/client/utils/assistant-session-controller.ts +2 -0
- package/client/utils/assistant-session-transport.ts +6 -2
- package/client/utils/assistant-surface.ts +157 -0
- package/client/utils/attachment-policy.ts +71 -0
- package/dist-client/components/assistant-chat.d.ts +6 -0
- package/dist-client/components/assistant-chat.js +98 -20
- package/dist-client/components/assistant-chat.js.map +1 -1
- package/dist-client/components/assistant-dock.d.ts +74 -0
- package/dist-client/components/assistant-dock.js +641 -0
- package/dist-client/components/assistant-dock.js.map +1 -0
- package/dist-client/components/assistant-mode.d.ts +6 -0
- package/dist-client/components/assistant-mode.js.map +1 -1
- package/dist-client/components/assistant-session-manager.d.ts +77 -0
- package/dist-client/components/assistant-session-manager.js +652 -0
- package/dist-client/components/assistant-session-manager.js.map +1 -0
- package/dist-client/components/chat-echo-dedup.js +4 -0
- package/dist-client/components/chat-echo-dedup.js.map +1 -1
- package/dist-client/components/chat-input-builder.d.ts +2 -0
- package/dist-client/components/chat-input-builder.js +2 -1
- package/dist-client/components/chat-input-builder.js.map +1 -1
- package/dist-client/components/panel-aria.test.js +12 -8
- package/dist-client/components/panel-aria.test.js.map +1 -1
- package/dist-client/index.d.ts +8 -0
- package/dist-client/index.js +8 -0
- package/dist-client/index.js.map +1 -1
- package/dist-client/setup-assistant-dock.d.ts +15 -0
- package/dist-client/setup-assistant-dock.js +110 -0
- package/dist-client/setup-assistant-dock.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/assistant-activity.d.ts +22 -0
- package/dist-client/utils/assistant-activity.js +104 -0
- package/dist-client/utils/assistant-activity.js.map +1 -0
- package/dist-client/utils/assistant-ask.d.ts +23 -0
- package/dist-client/utils/assistant-ask.js +18 -0
- package/dist-client/utils/assistant-ask.js.map +1 -0
- package/dist-client/utils/assistant-proposals.d.ts +29 -0
- package/dist-client/utils/assistant-proposals.js +22 -0
- package/dist-client/utils/assistant-proposals.js.map +1 -0
- package/dist-client/utils/assistant-session-actions.d.ts +12 -0
- package/dist-client/utils/assistant-session-actions.js +19 -0
- package/dist-client/utils/assistant-session-actions.js.map +1 -0
- package/dist-client/utils/assistant-session-admin.d.ts +72 -0
- package/dist-client/utils/assistant-session-admin.js +81 -0
- package/dist-client/utils/assistant-session-admin.js.map +1 -0
- package/dist-client/utils/assistant-session-controller.d.ts +2 -0
- package/dist-client/utils/assistant-session-controller.js.map +1 -1
- package/dist-client/utils/assistant-session-transport.js +6 -2
- package/dist-client/utils/assistant-session-transport.js.map +1 -1
- package/dist-client/utils/assistant-surface.d.ts +72 -0
- package/dist-client/utils/assistant-surface.js +99 -0
- package/dist-client/utils/assistant-surface.js.map +1 -0
- package/dist-client/utils/attachment-policy.d.ts +35 -0
- package/dist-client/utils/attachment-policy.js +56 -0
- package/dist-client/utils/attachment-policy.js.map +1 -0
- package/dist-server/service/assistant-chat-resolver.d.ts +1 -0
- package/dist-server/service/assistant-chat-resolver.js +71 -3
- package/dist-server/service/assistant-chat-resolver.js.map +1 -1
- package/dist-server/service/assistant-mode/assistant-mode-resolver.d.ts +1 -0
- package/dist-server/service/assistant-mode/assistant-mode-resolver.js +7 -0
- package/dist-server/service/assistant-mode/assistant-mode-resolver.js.map +1 -1
- package/dist-server/service/assistant-mode/resolve.d.ts +3 -0
- package/dist-server/service/assistant-mode/resolve.js +6 -2
- package/dist-server/service/assistant-mode/resolve.js.map +1 -1
- package/dist-server/service/assistant-mode/types.d.ts +6 -0
- package/dist-server/service/assistant-mode/types.js +0 -9
- package/dist-server/service/assistant-mode/types.js.map +1 -1
- package/dist-server/service/chat-message/chat-message.d.ts +6 -0
- package/dist-server/service/chat-message/chat-message.js +19 -0
- package/dist-server/service/chat-message/chat-message.js.map +1 -1
- package/dist-server/service/chat-session/attachment-policy.d.ts +44 -0
- package/dist-server/service/chat-session/attachment-policy.js +56 -0
- package/dist-server/service/chat-session/attachment-policy.js.map +1 -0
- package/dist-server/service/chat-session/attachment-route.d.ts +3 -0
- package/dist-server/service/chat-session/attachment-route.js +44 -0
- package/dist-server/service/chat-session/attachment-route.js.map +1 -0
- package/dist-server/service/chat-session/attachment-tools.d.ts +3 -0
- package/dist-server/service/chat-session/attachment-tools.js +59 -0
- package/dist-server/service/chat-session/attachment-tools.js.map +1 -0
- package/dist-server/service/chat-session/session-attachments.d.ts +36 -0
- package/dist-server/service/chat-session/session-attachments.js +84 -0
- package/dist-server/service/chat-session/session-attachments.js.map +1 -0
- package/dist-server/service/chat-session/session-inbox.d.ts +29 -0
- package/dist-server/service/chat-session/session-inbox.js +32 -8
- package/dist-server/service/chat-session/session-inbox.js.map +1 -1
- package/dist-server/service/chat-session/session-purge.d.ts +14 -0
- package/dist-server/service/chat-session/session-purge.js +77 -0
- package/dist-server/service/chat-session/session-purge.js.map +1 -0
- package/dist-server/service/chat-session/session-retention.d.ts +6 -0
- package/dist-server/service/chat-session/session-retention.js +20 -0
- package/dist-server/service/chat-session/session-retention.js.map +1 -0
- package/dist-server/service/chat-session/session-visibility.d.ts +8 -0
- package/dist-server/service/chat-session/session-visibility.js +11 -0
- package/dist-server/service/chat-session/session-visibility.js.map +1 -1
- package/dist-server/service/chat-session/session-write-gate.d.ts +11 -0
- package/dist-server/service/chat-session/session-write-gate.js +24 -0
- package/dist-server/service/chat-session/session-write-gate.js.map +1 -0
- package/dist-server/service/chat-session-participant/invite-notification.d.ts +1 -1
- package/dist-server/service/chat-session-participant/invite-notification.js +21 -6
- package/dist-server/service/chat-session-participant/invite-notification.js.map +1 -1
- package/dist-server/service/chat-session-participant/participant-lookup-roles.d.ts +3 -0
- package/dist-server/service/chat-session-participant/participant-lookup-roles.js +10 -0
- package/dist-server/service/chat-session-participant/participant-lookup-roles.js.map +1 -0
- package/dist-server/service/chat-session-participant/participant-lookup.d.ts +2 -0
- package/dist-server/service/chat-session-participant/participant-lookup.js +26 -0
- package/dist-server/service/chat-session-participant/participant-lookup.js.map +1 -0
- package/dist-server/service/chat-session-resolver.d.ts +17 -2
- package/dist-server/service/chat-session-resolver.js +135 -15
- package/dist-server/service/chat-session-resolver.js.map +1 -1
- package/dist-server/service/index.d.ts +5 -0
- package/dist-server/service/index.js +5 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -2
- package/server/service/assistant-chat-resolver.ts +71 -4
- package/server/service/assistant-mode/assistant-mode-resolver.ts +6 -0
- package/server/service/assistant-mode/resolve.ts +9 -2
- package/server/service/assistant-mode/types.ts +6 -0
- package/server/service/chat-message/chat-message.ts +17 -0
- package/server/service/chat-session/attachment-policy.test.ts +42 -0
- package/server/service/chat-session/attachment-policy.ts +68 -0
- package/server/service/chat-session/attachment-route.ts +45 -0
- package/server/service/chat-session/attachment-tools.ts +63 -0
- package/server/service/chat-session/session-attachments.ts +89 -0
- package/server/service/chat-session/session-inbox.test.ts +71 -1
- package/server/service/chat-session/session-inbox.ts +61 -11
- package/server/service/chat-session/session-purge.test.ts +24 -0
- package/server/service/chat-session/session-purge.ts +81 -0
- package/server/service/chat-session/session-retention.ts +17 -0
- package/server/service/chat-session/session-visibility.ts +11 -0
- package/server/service/chat-session/session-write-gate.test.ts +53 -0
- package/server/service/chat-session/session-write-gate.ts +31 -0
- package/server/service/chat-session-participant/invite-notification.test.ts +15 -0
- package/server/service/chat-session-participant/invite-notification.ts +24 -6
- package/server/service/chat-session-participant/participant-lookup-roles.ts +6 -0
- package/server/service/chat-session-participant/participant-lookup.ts +22 -0
- package/server/service/chat-session-resolver.ts +130 -13
- package/server/service/index.ts +5 -0
- package/test/assistant-dock.test.ts +118 -0
- package/test/assistant-session-manager.test.ts +126 -0
- package/test/attachment-policy-agree.test.ts +32 -0
- package/test/open-doors.test.ts +5 -2
- package/translations/en.json +61 -1
- package/translations/ja.json +61 -1
- package/translations/ko.json +61 -1
- package/translations/ms.json +61 -1
- package/translations/zh.json +61 -1
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
injectMentionUserIds,
|
|
33
33
|
stripMentionRefids
|
|
34
34
|
} from './markdown.js'
|
|
35
|
+
import { acceptOf, chatAttachmentUrl, refuseAttachments } from '../utils/attachment-policy.js'
|
|
35
36
|
import { buildAssistantChatInput, buildChatMutationInput } from './chat-input-builder.js'
|
|
36
37
|
import { receiveRemoteMessage, reconcileSentLine, remoteMessageToLine } from './chat-echo-dedup.js'
|
|
37
38
|
import './mention-popup.js'
|
|
@@ -116,6 +117,8 @@ interface ChatLine {
|
|
|
116
117
|
*/
|
|
117
118
|
groundingWarnings?: string[]
|
|
118
119
|
attachments?: Array<{
|
|
120
|
+
/** A stored file of the conversation (shared dock §9) - opened by its route, not carried inline. */
|
|
121
|
+
id?: string
|
|
119
122
|
name: string
|
|
120
123
|
size: number
|
|
121
124
|
type: string
|
|
@@ -168,6 +171,18 @@ const BOARD_AI_CHAT_MUTATION = gql`
|
|
|
168
171
|
* front of the model this turn, so a surface that granted a category and sees it missing knows
|
|
169
172
|
* the registration never happened, instead of reading a vague answer as a refusal.
|
|
170
173
|
*/
|
|
174
|
+
/* Files go to the conversation first; the turn then names them (design/ai/shared-dock.md §9). */
|
|
175
|
+
const ATTACH_TO_CONVERSATION_MUTATION = gql`
|
|
176
|
+
mutation AttachToConversation($sessionId: String!, $files: [Upload!]!, $kind: String) {
|
|
177
|
+
attachToConversation(sessionId: $sessionId, files: $files, kind: $kind) {
|
|
178
|
+
id
|
|
179
|
+
name
|
|
180
|
+
mimetype
|
|
181
|
+
size
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
`
|
|
185
|
+
|
|
171
186
|
const ASSISTANT_CHAT_MUTATION = gql`
|
|
172
187
|
mutation AssistantChat($input: AssistantChatInput!) {
|
|
173
188
|
assistantChat(input: $input) {
|
|
@@ -223,6 +238,7 @@ const ASSISTANT_MODE_QUERY = gql`
|
|
|
223
238
|
examples
|
|
224
239
|
footerNotice
|
|
225
240
|
stagedNotice
|
|
241
|
+
attachments
|
|
226
242
|
}
|
|
227
243
|
}
|
|
228
244
|
`
|
|
@@ -265,6 +281,7 @@ const CHAT_MESSAGES_QUERY = gql`
|
|
|
265
281
|
relatedPatchId
|
|
266
282
|
toolUsagesJson
|
|
267
283
|
groundingWarningsJson
|
|
284
|
+
attachmentsJson
|
|
268
285
|
createdAt
|
|
269
286
|
redacted
|
|
270
287
|
creator {
|
|
@@ -286,6 +303,7 @@ const CHAT_MESSAGE_SUBSCRIPTION = gql`
|
|
|
286
303
|
relatedPatchId
|
|
287
304
|
toolUsagesJson
|
|
288
305
|
groundingWarningsJson
|
|
306
|
+
attachmentsJson
|
|
289
307
|
createdAt
|
|
290
308
|
redacted
|
|
291
309
|
creator {
|
|
@@ -595,9 +613,36 @@ export class OxAssistantChat extends LitElement {
|
|
|
595
613
|
* `attachments` 짐 자체는 그대로 둔다: figure 의 도구가 거기서 이미지를 찾는다
|
|
596
614
|
* (`figure-tools.ts` — `ctx.host.image` 가 없을 때의 갈래).
|
|
597
615
|
*/
|
|
616
|
+
/** This conversation talks to the neutral door - its attachments follow the mode's policy (§9). */
|
|
617
|
+
private get usesAttachmentPolicy(): boolean {
|
|
618
|
+
return this.conversation.chatEndpoint === 'assistantChat'
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/** Whether the attach button stands: a mode that declares nothing takes nothing (the board door keeps its images). */
|
|
622
|
+
private get acceptsAttachments(): boolean {
|
|
623
|
+
return !this.usesAttachmentPolicy || !!this.modeView?.attachments?.kinds?.length
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/** A refusal in the reader's words - the same keys the door uses. */
|
|
627
|
+
private attachmentRefusalText(refusal: NonNullable<ReturnType<typeof refuseAttachments>>): string {
|
|
628
|
+
const params: any = { ...refusal }
|
|
629
|
+
if (refusal.code === 'attachment-too-large') params.max = Math.round(refusal.maxBytes / 1024 / 1024)
|
|
630
|
+
if (refusal.code === 'too-many-attachments') params.max = refusal.maxFiles
|
|
631
|
+
if (refusal.code === 'attachment-kind-not-accepted') params.kinds = refusal.kinds.join(', ')
|
|
632
|
+
return String(i18next.t(`ai-assistant.text.${refusal.code}`, { ...params, defaultValue: refusal.code }))
|
|
633
|
+
}
|
|
634
|
+
|
|
598
635
|
private async onAttachFiles(files: FileList | File[] | null | undefined) {
|
|
599
636
|
if (!files || files.length === 0) return
|
|
600
637
|
const list = Array.from(files)
|
|
638
|
+
if (this.usesAttachmentPolicy) {
|
|
639
|
+
/* Said before anything is sent - never cut silently (§9-1). */
|
|
640
|
+
const refusal = refuseAttachments(this.modeView?.attachments, [...this.attachments, ...list].map(f => ({ name: f.name, type: f.type, size: f.size })))
|
|
641
|
+
if (refusal) {
|
|
642
|
+
this.errorMessage = this.attachmentRefusalText(refusal)
|
|
643
|
+
return
|
|
644
|
+
}
|
|
645
|
+
}
|
|
601
646
|
const newAttachments: ChatAttachment[] = []
|
|
602
647
|
|
|
603
648
|
for (const file of list) {
|
|
@@ -2889,21 +2934,24 @@ export class OxAssistantChat extends LitElement {
|
|
|
2889
2934
|
${line.attachments && line.attachments.length > 0
|
|
2890
2935
|
? html`
|
|
2891
2936
|
<div class="msg-attachments">
|
|
2892
|
-
${line.attachments.map(att =>
|
|
2893
|
-
|
|
2937
|
+
${line.attachments.map(att => {
|
|
2938
|
+
/* A stored file opens through the conversation's own route (§9-3); a fresh one shows its local copy. */
|
|
2939
|
+
const href = att.url || att.base64 || (att.id && this.sessionId ? chatAttachmentUrl(this.sessionId, att.id) : '')
|
|
2940
|
+
/* By type - a text file carries base64 too, and drew as a broken image (found on :3700). */
|
|
2941
|
+
return att.type?.startsWith('image/') || att.url?.startsWith('data:image/') || att.base64?.startsWith('data:image/')
|
|
2894
2942
|
? html`
|
|
2895
|
-
<
|
|
2896
|
-
<img src=${
|
|
2943
|
+
<a class="msg-attachment-img-wrap" title=${att.name} href=${href} target="_blank" rel="noopener">
|
|
2944
|
+
<img src=${href} alt=${att.name} />
|
|
2897
2945
|
<span class="msg-attachment-label">${att.name}</span>
|
|
2898
|
-
</
|
|
2946
|
+
</a>
|
|
2899
2947
|
`
|
|
2900
2948
|
: html`
|
|
2901
|
-
<
|
|
2949
|
+
<a class="msg-attachment-file-chip" title=${att.name} href=${href || nothing} target="_blank" rel="noopener">
|
|
2902
2950
|
<md-icon>description</md-icon>
|
|
2903
2951
|
<span>${att.name}</span>
|
|
2904
|
-
</
|
|
2952
|
+
</a>
|
|
2905
2953
|
`
|
|
2906
|
-
)}
|
|
2954
|
+
})}
|
|
2907
2955
|
</div>
|
|
2908
2956
|
`
|
|
2909
2957
|
: nothing}
|
|
@@ -2976,7 +3024,7 @@ export class OxAssistantChat extends LitElement {
|
|
|
2976
3024
|
id="chat-file-input"
|
|
2977
3025
|
type="file"
|
|
2978
3026
|
multiple
|
|
2979
|
-
accept
|
|
3027
|
+
accept=${this.usesAttachmentPolicy ? acceptOf(this.modeView?.attachments) : 'image/*'}
|
|
2980
3028
|
style="display: none"
|
|
2981
3029
|
@change=${(e: Event) => {
|
|
2982
3030
|
const input = e.target as HTMLInputElement
|
|
@@ -2986,14 +3034,16 @@ export class OxAssistantChat extends LitElement {
|
|
|
2986
3034
|
}
|
|
2987
3035
|
}}
|
|
2988
3036
|
/>
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
3037
|
+
${this.acceptsAttachments
|
|
3038
|
+
? html`<button
|
|
3039
|
+
type="button"
|
|
3040
|
+
class="action"
|
|
3041
|
+
@click=${() => this.renderRoot.querySelector<HTMLInputElement>('#chat-file-input')?.click()}
|
|
3042
|
+
title=${i18next.t('ai-assistant.tooltip.attach-file', { defaultValue: 'attach an image (drag & drop or paste supported)' })}>
|
|
3043
|
+
<md-icon>attach_file</md-icon>
|
|
3044
|
+
${i18next.t('ai-assistant.button.attach', { defaultValue: 'Attach' })}
|
|
3045
|
+
</button>`
|
|
3046
|
+
: nothing}
|
|
2997
3047
|
${hasMessages
|
|
2998
3048
|
? html`
|
|
2999
3049
|
<button
|
|
@@ -4420,6 +4470,33 @@ export class OxAssistantChat extends LitElement {
|
|
|
4420
4470
|
this.busy = false
|
|
4421
4471
|
}
|
|
4422
4472
|
|
|
4473
|
+
/* The neutral door takes stored files by id: upload them to the conversation first (§9-2). */
|
|
4474
|
+
let attachmentIds: string[] | undefined
|
|
4475
|
+
if (attachmentsToSend.length > 0 && this.usesAttachmentPolicy) {
|
|
4476
|
+
if (!this.sessionId) {
|
|
4477
|
+
this.errorMessage = i18next.t('ai-assistant.text.attachments-need-session', { defaultValue: 'attachments need a saved conversation.' })
|
|
4478
|
+
this.attachments = attachmentsToSend
|
|
4479
|
+
return
|
|
4480
|
+
}
|
|
4481
|
+
this.busy = true
|
|
4482
|
+
try {
|
|
4483
|
+
const uploaded = await client.mutate({
|
|
4484
|
+
mutation: ATTACH_TO_CONVERSATION_MUTATION,
|
|
4485
|
+
variables: { sessionId: this.sessionId, files: attachmentsToSend.map(a => a.file), kind: this.conversation.kind },
|
|
4486
|
+
/* The shell's client sends multipart only when asked - without it a File travels as {} and is refused. */
|
|
4487
|
+
context: { hasUpload: true }
|
|
4488
|
+
})
|
|
4489
|
+
if (uploaded.errors?.length) throw new Error(uploaded.errors.map(error => error.message).join('\n'))
|
|
4490
|
+
attachmentIds = (uploaded.data?.attachToConversation ?? []).map((file: any) => file.id)
|
|
4491
|
+
} catch (error) {
|
|
4492
|
+
this.errorMessage = error instanceof Error ? error.message : String(error)
|
|
4493
|
+
this.attachments = attachmentsToSend
|
|
4494
|
+
this.busy = false
|
|
4495
|
+
return
|
|
4496
|
+
}
|
|
4497
|
+
this.busy = false
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4423
4500
|
let requestContext: AssistantRequestContext
|
|
4424
4501
|
let liveBoard: any
|
|
4425
4502
|
let requestBase: any
|
|
@@ -4475,7 +4552,7 @@ export class OxAssistantChat extends LitElement {
|
|
|
4475
4552
|
this.lines = [...this.lines, { role: 'assistant', content: '', pending: true, _localId: asstLocalId }]
|
|
4476
4553
|
|
|
4477
4554
|
try {
|
|
4478
|
-
if (attachmentsToSend.length > 0) {
|
|
4555
|
+
if (attachmentsToSend.length > 0 && !attachmentIds) {
|
|
4479
4556
|
requestContext.hostContext = {
|
|
4480
4557
|
...requestContext.hostContext,
|
|
4481
4558
|
attachments: attachmentsToSend.map(a => ({
|
|
@@ -4512,7 +4589,8 @@ export class OxAssistantChat extends LitElement {
|
|
|
4512
4589
|
history,
|
|
4513
4590
|
mode: { kind: this.conversation.kind!, target: this.conversation.target },
|
|
4514
4591
|
truncateAfterMessageId: this._truncateAfterId,
|
|
4515
|
-
hostContext: requestContext.hostContext
|
|
4592
|
+
hostContext: requestContext.hostContext,
|
|
4593
|
+
attachmentIds
|
|
4516
4594
|
})
|
|
4517
4595
|
: buildChatMutationInput({
|
|
4518
4596
|
sessionId: this.sessionId,
|