@things-factory/ai-assistant 10.1.79 → 10.1.87
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 +102 -13
- package/client/components/assistant-dock.ts +206 -18
- package/client/components/assistant-mode.test.ts +16 -2
- package/client/components/assistant-session-manager.ts +58 -26
- package/client/components/assistant-session-toolbar.ts +4 -2
- package/client/components/chat-echo-dedup.ts +4 -0
- package/client/components/proposal-outcome-line.ts +36 -0
- package/client/components/proposal-request.test.ts +52 -0
- package/client/utils/assistant-navigation.test.ts +38 -0
- package/client/utils/assistant-navigation.ts +6 -0
- package/client/utils/assistant-session-controller.ts +2 -0
- package/client/utils/assistant-session-transport.ts +2 -2
- package/client/utils/assistant-surface.ts +21 -0
- package/dist-client/components/assistant-chat.d.ts +15 -0
- package/dist-client/components/assistant-chat.js +106 -13
- package/dist-client/components/assistant-chat.js.map +1 -1
- package/dist-client/components/assistant-dock.d.ts +16 -0
- package/dist-client/components/assistant-dock.js +221 -20
- package/dist-client/components/assistant-dock.js.map +1 -1
- package/dist-client/components/assistant-mode.test.js +14 -2
- package/dist-client/components/assistant-mode.test.js.map +1 -1
- package/dist-client/components/assistant-session-manager.d.ts +4 -0
- package/dist-client/components/assistant-session-manager.js +74 -27
- package/dist-client/components/assistant-session-manager.js.map +1 -1
- package/dist-client/components/assistant-session-toolbar.d.ts +1 -0
- package/dist-client/components/assistant-session-toolbar.js +8 -2
- package/dist-client/components/assistant-session-toolbar.js.map +1 -1
- package/dist-client/components/chat-echo-dedup.d.ts +2 -0
- package/dist-client/components/chat-echo-dedup.js +2 -0
- package/dist-client/components/chat-echo-dedup.js.map +1 -1
- package/dist-client/components/proposal-outcome-line.d.ts +29 -0
- package/dist-client/components/proposal-outcome-line.js +15 -0
- package/dist-client/components/proposal-outcome-line.js.map +1 -1
- package/dist-client/components/proposal-request.test.d.ts +1 -0
- package/dist-client/components/proposal-request.test.js +45 -0
- package/dist-client/components/proposal-request.test.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/assistant-navigation.d.ts +6 -0
- package/dist-client/utils/assistant-navigation.js +9 -0
- package/dist-client/utils/assistant-navigation.js.map +1 -0
- package/dist-client/utils/assistant-navigation.test.d.ts +1 -0
- package/dist-client/utils/assistant-navigation.test.js +37 -0
- package/dist-client/utils/assistant-navigation.test.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 +2 -2
- package/dist-client/utils/assistant-session-transport.js.map +1 -1
- package/dist-client/utils/assistant-surface.d.ts +19 -0
- package/dist-client/utils/assistant-surface.js.map +1 -1
- package/dist-server/service/assistant-chat-resolver.js +1 -0
- package/dist-server/service/assistant-chat-resolver.js.map +1 -1
- package/dist-server/service/chat-message/chat-message.d.ts +10 -0
- package/dist-server/service/chat-message/chat-message.js +29 -0
- package/dist-server/service/chat-message/chat-message.js.map +1 -1
- package/dist-server/service/chat-message/proposal-outcome.d.ts +8 -0
- package/dist-server/service/chat-message/proposal-outcome.js +35 -1
- package/dist-server/service/chat-message/proposal-outcome.js.map +1 -1
- package/dist-server/service/chat-session/chat-session.d.ts +5 -5
- package/dist-server/service/chat-session/chat-session.js.map +1 -1
- package/dist-server/service/chat-session/session-inbox.d.ts +7 -0
- package/dist-server/service/chat-session/session-inbox.js +7 -0
- package/dist-server/service/chat-session/session-inbox.js.map +1 -1
- package/dist-server/service/chat-session/session-visibility.d.ts +8 -5
- package/dist-server/service/chat-session/session-visibility.js +9 -15
- package/dist-server/service/chat-session/session-visibility.js.map +1 -1
- package/dist-server/service/chat-session-resolver.d.ts +1 -0
- package/dist-server/service/chat-session-resolver.js +64 -10
- package/dist-server/service/chat-session-resolver.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/server/service/assistant-chat-resolver.ts +1 -0
- package/server/service/chat-message/chat-message.ts +32 -0
- package/server/service/chat-message/proposal-outcome.test.ts +53 -2
- package/server/service/chat-message/proposal-outcome.ts +33 -0
- package/server/service/chat-session/chat-session.ts +5 -5
- package/server/service/chat-session/session-inbox.ts +7 -0
- package/server/service/chat-session/session-visibility.test.ts +6 -6
- package/server/service/chat-session/session-visibility.ts +9 -15
- package/server/service/chat-session-resolver.ts +72 -13
- package/server/service/session-anchor.test.ts +2 -2
- package/test/assistant-dock.test.ts +8 -3
- package/test/assistant-session-toolbar.test.ts +7 -1
- package/test/open-doors.test.ts +2 -1
- package/test/session-discovery.test.ts +42 -0
- package/translations/en.json +28 -2
- package/translations/ja.json +28 -2
- package/translations/ko.json +28 -2
- package/translations/ms.json +28 -2
- package/translations/zh.json +28 -2
|
@@ -35,6 +35,9 @@ export declare class AssistantDock extends AssistantDock_base {
|
|
|
35
35
|
private showingHistory;
|
|
36
36
|
private conversationView;
|
|
37
37
|
private asking?;
|
|
38
|
+
private screenChanged;
|
|
39
|
+
private navigationNotice;
|
|
40
|
+
private openedIdentity;
|
|
38
41
|
private app;
|
|
39
42
|
/** The kind the person picked; kept while the surface stays the same. */
|
|
40
43
|
private chosenKind;
|
|
@@ -44,9 +47,16 @@ export declare class AssistantDock extends AssistantDock_base {
|
|
|
44
47
|
private unsubscribers;
|
|
45
48
|
private controller;
|
|
46
49
|
private onStartNewSession;
|
|
50
|
+
/** Who reads the open conversation - absent until the list or the create answer says. */
|
|
51
|
+
private get audience();
|
|
52
|
+
protected updated(changed: Map<PropertyKey, unknown>): void;
|
|
47
53
|
connectedCallback(): void;
|
|
48
54
|
disconnectedCallback(): void;
|
|
49
55
|
private scopeKey;
|
|
56
|
+
private identityKey;
|
|
57
|
+
private get navigationState();
|
|
58
|
+
private mayLeaveConversation;
|
|
59
|
+
private requestSurface;
|
|
50
60
|
/** The screen changed - a different surface or domain is a different conversation. */
|
|
51
61
|
private follow;
|
|
52
62
|
private open;
|
|
@@ -62,8 +72,14 @@ export declare class AssistantDock extends AssistantDock_base {
|
|
|
62
72
|
private report;
|
|
63
73
|
/** Every proposal ends in exactly one reported outcome - a kind nobody handles is `unavailable`. */
|
|
64
74
|
private onProposal;
|
|
75
|
+
/**
|
|
76
|
+
* "Check result" - asks the surface what became of a requested proposal and reports only what it learns.
|
|
77
|
+
* Nothing is run: a lost answer never turns into a second application (ADR-0097 Q-D4 ④).
|
|
78
|
+
*/
|
|
79
|
+
private onProposalCheck;
|
|
65
80
|
private appendNote;
|
|
66
81
|
private onScenePatch;
|
|
82
|
+
private mayApplyOnScreen;
|
|
67
83
|
private onBoardRevert;
|
|
68
84
|
private onSceneAction;
|
|
69
85
|
private stuckLine;
|
|
@@ -21,6 +21,7 @@ import { setOpenSession, subscribeSessionActivity } from '../utils/assistant-act
|
|
|
21
21
|
import { assistantHomeSurface, currentAssistantSurface, isAnchor, subscribeAssistantSurface } from '../utils/assistant-surface.js';
|
|
22
22
|
import { runProposal } from '../utils/assistant-proposals.js';
|
|
23
23
|
import { holdAssistantAsk, subscribeAssistantAsk, takeAssistantAsk } from '../utils/assistant-ask.js';
|
|
24
|
+
import { surfaceTransition } from '../utils/assistant-navigation.js';
|
|
24
25
|
export const ASSISTANT_DOCK_VIEWPART = 'assistant-dock';
|
|
25
26
|
const t = (key, defaultValue, options = {}) => i18next.t(`ai-assistant.dock.${key}`, { defaultValue, ...options });
|
|
26
27
|
const MODES_QUERY = gql `
|
|
@@ -66,6 +67,9 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
66
67
|
this.failure = '';
|
|
67
68
|
this.showingHistory = false;
|
|
68
69
|
this.conversationView = 0;
|
|
70
|
+
this.screenChanged = false;
|
|
71
|
+
this.navigationNotice = '';
|
|
72
|
+
this.openedIdentity = '';
|
|
69
73
|
this.app = new AppController(this);
|
|
70
74
|
/** The kind the person picked; kept while the surface stays the same. */
|
|
71
75
|
this.chosenKind = '';
|
|
@@ -84,17 +88,21 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
84
88
|
this.failure = next.error;
|
|
85
89
|
}, { getItem: key => sessionStorage.getItem(key), setItem: (key, value) => sessionStorage.setItem(key, value) }, { lazy: true });
|
|
86
90
|
this.onStartNewSession = () => void this.newConversation();
|
|
87
|
-
this.onModeChange = (event) => {
|
|
91
|
+
this.onModeChange = async (event) => {
|
|
88
92
|
const kind = event.detail?.kind;
|
|
89
93
|
if (!kind || kind === this.kind)
|
|
90
94
|
return;
|
|
95
|
+
if (!(await this.mayLeaveConversation()))
|
|
96
|
+
return;
|
|
91
97
|
this.chosenKind = kind;
|
|
92
98
|
void this.open();
|
|
93
99
|
};
|
|
94
100
|
/** Every proposal ends in exactly one reported outcome - a kind nobody handles is `unavailable`. */
|
|
95
101
|
this.onProposal = async (event) => {
|
|
96
102
|
const { proposal, sessionId, proposalKey } = event.detail ?? {};
|
|
97
|
-
const outcome =
|
|
103
|
+
const outcome = this.openedFor !== this.scopeKey(currentAssistantSurface()) || this.openedIdentity !== this.identityKey()
|
|
104
|
+
? { verdict: 'unavailable', errorCode: 'conversation-screen-changed', note: t('return-to-subject', 'Return to the conversation subject before applying this proposal.') }
|
|
105
|
+
: await runProposal(proposal, this.proposalContext(sessionId));
|
|
98
106
|
if (outcome.verdict === 'unavailable' && outcome.errorCode === 'unknown-proposal-kind') {
|
|
99
107
|
notify({ level: 'error', message: t('proposal-not-runnable', 'this proposal cannot be run on this screen.') });
|
|
100
108
|
}
|
|
@@ -103,8 +111,36 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
103
111
|
if (outcome.note && sessionId)
|
|
104
112
|
await this.appendNote(sessionId, outcome.note);
|
|
105
113
|
};
|
|
114
|
+
/**
|
|
115
|
+
* "Check result" - asks the surface what became of a requested proposal and reports only what it learns.
|
|
116
|
+
* Nothing is run: a lost answer never turns into a second application (ADR-0097 Q-D4 ④).
|
|
117
|
+
*/
|
|
118
|
+
this.onProposalCheck = async (event) => {
|
|
119
|
+
const { proposal, sessionId, proposalKey } = event.detail ?? {};
|
|
120
|
+
const ask = this.surface?.proposalOutcome;
|
|
121
|
+
if (!ask) {
|
|
122
|
+
notify({ level: 'info', message: t('proposal-result-uncheckable', 'this screen cannot check that result. open the screen where it was applied.') });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let outcome;
|
|
126
|
+
try {
|
|
127
|
+
outcome = await ask.call(this.surface, proposalKey, proposal);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
outcome = undefined;
|
|
131
|
+
}
|
|
132
|
+
if (!outcome?.verdict) {
|
|
133
|
+
notify({ level: 'info', message: t('proposal-result-unknown', 'the result is still unknown. it was not applied again.') });
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
await this.report(sessionId, proposalKey, outcome);
|
|
137
|
+
if (outcome.note && sessionId)
|
|
138
|
+
await this.appendNote(sessionId, outcome.note);
|
|
139
|
+
};
|
|
106
140
|
/* ── board surfaces: the chat's scene edits land on the open board ───────────────── */
|
|
107
141
|
this.onScenePatch = async (event) => {
|
|
142
|
+
if (!this.mayApplyOnScreen())
|
|
143
|
+
return;
|
|
108
144
|
const board = this.surface?.board;
|
|
109
145
|
if (!board)
|
|
110
146
|
return;
|
|
@@ -112,8 +148,10 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
112
148
|
if (result?.missed)
|
|
113
149
|
notify({ level: 'info', message: t('patch-missed', '{missed} of the changes could not be applied.', { missed: result.missed }) });
|
|
114
150
|
};
|
|
115
|
-
this.onBoardRevert = (event) =>
|
|
116
|
-
|
|
151
|
+
this.onBoardRevert = (event) => { if (this.mayApplyOnScreen())
|
|
152
|
+
void this.surface?.board?.revertPatch?.(event.detail?.patchId); };
|
|
153
|
+
this.onSceneAction = (event) => { if (this.mayApplyOnScreen())
|
|
154
|
+
void this.surface?.board?.applyAction?.(event.detail); };
|
|
117
155
|
}
|
|
118
156
|
static { this.styles = [
|
|
119
157
|
ScrollbarStyles,
|
|
@@ -207,6 +245,34 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
207
245
|
--md-icon-size: 18px;
|
|
208
246
|
}
|
|
209
247
|
|
|
248
|
+
/*
|
|
249
|
+
* An open conversation is read by everyone in the domain - the dock says so on every screen of it, not
|
|
250
|
+
* only in the list (2026-09-30: open and private were one grey word apart, and an owner's question about
|
|
251
|
+
* the books sat in every employee's list). A private one draws nothing extra: it is the default.
|
|
252
|
+
*/
|
|
253
|
+
:host([audience='open']) {
|
|
254
|
+
border-left: 3px solid var(--md-sys-color-tertiary);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.audience {
|
|
258
|
+
display: flex;
|
|
259
|
+
align-items: center;
|
|
260
|
+
gap: 6px;
|
|
261
|
+
flex: none;
|
|
262
|
+
padding: 6px 10px;
|
|
263
|
+
background: var(--md-sys-color-tertiary-container);
|
|
264
|
+
color: var(--md-sys-color-on-tertiary-container);
|
|
265
|
+
border-bottom: 1px solid var(--md-sys-color-tertiary);
|
|
266
|
+
font-size: 12px;
|
|
267
|
+
font-weight: 600;
|
|
268
|
+
line-height: 1.35;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.audience md-icon {
|
|
272
|
+
--md-icon-size: 16px;
|
|
273
|
+
flex: none;
|
|
274
|
+
}
|
|
275
|
+
|
|
210
276
|
ox-assistant-session-toolbar {
|
|
211
277
|
flex: none;
|
|
212
278
|
min-width: 0;
|
|
@@ -239,12 +305,54 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
239
305
|
gap: 4px;
|
|
240
306
|
font: inherit;
|
|
241
307
|
}
|
|
308
|
+
|
|
309
|
+
.next-step {
|
|
310
|
+
display: flex;
|
|
311
|
+
align-items: center;
|
|
312
|
+
justify-content: space-between;
|
|
313
|
+
gap: 10px;
|
|
314
|
+
padding: 8px 12px;
|
|
315
|
+
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
316
|
+
background: var(--md-sys-color-surface-container-low);
|
|
317
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
318
|
+
font-size: 12px;
|
|
319
|
+
line-height: 1.4;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.next-step a {
|
|
323
|
+
display: inline-flex;
|
|
324
|
+
align-items: center;
|
|
325
|
+
gap: 3px;
|
|
326
|
+
flex: none;
|
|
327
|
+
color: var(--md-sys-color-primary);
|
|
328
|
+
font-weight: 650;
|
|
329
|
+
text-decoration: none;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.next-step a:hover { text-decoration: underline; }
|
|
333
|
+
.next-step md-icon { --md-icon-size: 16px; }
|
|
334
|
+
ox-assistant-chat[hidden] { display: none; }
|
|
335
|
+
.transition { padding: 10px 12px; font-size: 13px; line-height: 1.5; border-bottom: 1px solid var(--md-sys-color-outline-variant); background: var(--md-sys-color-surface-container-low); }
|
|
336
|
+
.transition button { display: block; margin-top: 6px; font: inherit; }
|
|
242
337
|
`
|
|
243
338
|
]; }
|
|
339
|
+
/** Who reads the open conversation - absent until the list or the create answer says. */
|
|
340
|
+
get audience() {
|
|
341
|
+
return this.sessions.find(session => session.id === this.sessionId)?.visibility || undefined;
|
|
342
|
+
}
|
|
343
|
+
updated(changed) {
|
|
344
|
+
super.updated?.(changed);
|
|
345
|
+
const audience = !this.showingHistory && this.audience === 'open' ? 'open' : null;
|
|
346
|
+
if (audience)
|
|
347
|
+
this.setAttribute('audience', audience);
|
|
348
|
+
else
|
|
349
|
+
this.removeAttribute('audience');
|
|
350
|
+
}
|
|
244
351
|
connectedCallback() {
|
|
245
352
|
super.connectedCallback();
|
|
246
353
|
this.addEventListener('assistant-start-new-session', this.onStartNewSession);
|
|
247
|
-
this.unsubscribers.push(subscribeAssistantSurface(() => this.follow()),
|
|
354
|
+
this.unsubscribers.push(subscribeAssistantSurface(() => this.follow()), store.subscribe(() => { if (this.openedIdentity !== this.identityKey())
|
|
355
|
+
this.follow(); }), subscribeAssistantAsk(() => void this.takeAsk()), subscribeSessionActivity(activity => {
|
|
248
356
|
/* A rename or a new conversation elsewhere on this anchor - the tabs read again. */
|
|
249
357
|
if (activity.kind === 'meta' && isAnchor(this.anchor) && activity.anchorId === this.anchor.anchorId)
|
|
250
358
|
void this.reloadSessions();
|
|
@@ -259,23 +367,73 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
259
367
|
this.controller.clear();
|
|
260
368
|
super.disconnectedCallback();
|
|
261
369
|
}
|
|
262
|
-
scopeKey(surface
|
|
370
|
+
scopeKey(surface) {
|
|
263
371
|
return JSON.stringify([this.app.contextPath, surface?.key ?? '']);
|
|
264
372
|
}
|
|
373
|
+
identityKey() {
|
|
374
|
+
const user = store.getState().auth?.user;
|
|
375
|
+
return JSON.stringify([this.app.contextPath, user?.id || user?.email || '']);
|
|
376
|
+
}
|
|
377
|
+
get navigationState() {
|
|
378
|
+
return this.renderRoot.querySelector('ox-assistant-chat')?.navigationState ?? { busy: false, draft: false };
|
|
379
|
+
}
|
|
380
|
+
async mayLeaveConversation() {
|
|
381
|
+
if (this.navigationState.busy) {
|
|
382
|
+
notify({ level: 'info', message: t('wait-before-switch', 'Wait for the current response before changing conversations.') });
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
if (!this.navigationState.draft)
|
|
386
|
+
return true;
|
|
387
|
+
const identity = this.identityKey();
|
|
388
|
+
const accepted = await OxPrompt.open({
|
|
389
|
+
type: 'warning', title: t('switch-title', 'Change conversation?'),
|
|
390
|
+
text: t('switch-draft', 'Your unsent text and attachments will not move to the other conversation.'),
|
|
391
|
+
confirmButton: { text: t('switch-confirm', 'Discard draft and switch') },
|
|
392
|
+
cancelButton: { text: t('stay', 'Keep writing') }
|
|
393
|
+
});
|
|
394
|
+
return !!accepted && identity === this.identityKey();
|
|
395
|
+
}
|
|
396
|
+
async requestSurface(surface) {
|
|
397
|
+
if (!(await this.mayLeaveConversation()))
|
|
398
|
+
return;
|
|
399
|
+
this.chosenKind = '';
|
|
400
|
+
this.surface = surface;
|
|
401
|
+
this.navigationNotice = surface ? t('now-about', 'Conversation subject: {name}', { name: surface.label() }) : '';
|
|
402
|
+
await this.open();
|
|
403
|
+
}
|
|
265
404
|
/** The screen changed - a different surface or domain is a different conversation. */
|
|
266
405
|
follow(force = false) {
|
|
267
406
|
const next = currentAssistantSurface();
|
|
268
|
-
|
|
269
|
-
|
|
407
|
+
const transition = surfaceTransition({
|
|
408
|
+
identityChanged: this.openedIdentity !== this.identityKey(),
|
|
409
|
+
sameSubject: this.scopeKey(next) === this.openedFor,
|
|
410
|
+
active: isAnchor(this.anchor) && (!!this.sessionId || this.navigationState.draft || this.navigationState.busy)
|
|
411
|
+
});
|
|
412
|
+
if (!force && transition === 'refresh') {
|
|
413
|
+
this.surface = next;
|
|
414
|
+
this.screenChanged = false;
|
|
270
415
|
this.requestUpdate();
|
|
271
416
|
return;
|
|
272
417
|
}
|
|
418
|
+
if (!force && transition === 'offer') {
|
|
419
|
+
this.screenChanged = true;
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (transition === 'reset') {
|
|
423
|
+
this.asking = undefined;
|
|
424
|
+
this.capability = 'unknown';
|
|
425
|
+
if (this.openedIdentity)
|
|
426
|
+
takeAssistantAsk();
|
|
427
|
+
}
|
|
428
|
+
this.navigationNotice = transition === 'follow' && next ? t('now-about', 'Conversation subject: {name}', { name: next.label() }) : '';
|
|
273
429
|
if (next?.key !== this.surface?.key)
|
|
274
430
|
this.chosenKind = '';
|
|
275
431
|
this.surface = next;
|
|
276
432
|
void this.open();
|
|
277
433
|
}
|
|
278
434
|
async open() {
|
|
435
|
+
this.openedIdentity = this.identityKey();
|
|
436
|
+
this.screenChanged = false;
|
|
279
437
|
const ticket = ++this.revision;
|
|
280
438
|
this.conversationView++;
|
|
281
439
|
this.showingHistory = false;
|
|
@@ -283,7 +441,7 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
283
441
|
this.loading = true;
|
|
284
442
|
this.failure = '';
|
|
285
443
|
this.anchor = undefined;
|
|
286
|
-
this.openedFor = this.scopeKey();
|
|
444
|
+
this.openedFor = this.scopeKey(this.surface);
|
|
287
445
|
try {
|
|
288
446
|
if (this.capability !== 'configured') {
|
|
289
447
|
this.capability = await readAiCapability();
|
|
@@ -342,13 +500,17 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
342
500
|
async newConversation() {
|
|
343
501
|
if (this.loading || !isAnchor(this.anchor))
|
|
344
502
|
return;
|
|
503
|
+
if (!(await this.mayLeaveConversation()))
|
|
504
|
+
return;
|
|
345
505
|
this.showingHistory = false;
|
|
346
506
|
const revision = this.controller.state.revision;
|
|
347
507
|
await this.controller.reset();
|
|
348
508
|
if (revision !== this.controller.state.revision)
|
|
349
509
|
this.conversationView++;
|
|
350
510
|
}
|
|
351
|
-
selectSession(id, pickedKind) {
|
|
511
|
+
async selectSession(id, pickedKind) {
|
|
512
|
+
if (id !== this.sessionId && !(await this.mayLeaveConversation()))
|
|
513
|
+
return;
|
|
352
514
|
this.showingHistory = false;
|
|
353
515
|
const follow = followPickedConversation(pickedKind, this.kind);
|
|
354
516
|
if (follow) {
|
|
@@ -365,6 +527,12 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
365
527
|
async takeAsk() {
|
|
366
528
|
if (this.loading || !this.anchor)
|
|
367
529
|
return;
|
|
530
|
+
if (this.screenChanged || this.navigationState.busy || this.navigationState.draft) {
|
|
531
|
+
const waiting = takeAssistantAsk();
|
|
532
|
+
if (waiting)
|
|
533
|
+
notify({ level: 'info', message: t('ask-kept-current', 'The current conversation was kept. Switch to the intended subject before asking again.') });
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
368
536
|
if (!isAnchor(this.anchor)) {
|
|
369
537
|
/*
|
|
370
538
|
A question is not sent later on its own, once some conversation happens to stand - by then the person is looking
|
|
@@ -438,6 +606,8 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
438
606
|
}
|
|
439
607
|
/* ── proposals ───────────────────────────────────────────────────────────────────── */
|
|
440
608
|
proposalContext(sessionId) {
|
|
609
|
+
const identity = this.identityKey();
|
|
610
|
+
const scope = this.openedFor;
|
|
441
611
|
return {
|
|
442
612
|
sessionId,
|
|
443
613
|
surface: this.surface,
|
|
@@ -447,7 +617,7 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
447
617
|
text,
|
|
448
618
|
confirmButton: { text: confirmText ?? t('confirm', 'OK') },
|
|
449
619
|
cancelButton: { text: cancelText ?? t('cancel', 'Cancel') }
|
|
450
|
-
})),
|
|
620
|
+
})) && identity === this.identityKey() && scope === this.scopeKey(currentAssistantSurface()),
|
|
451
621
|
notify: (level, message) => notify({ level, message })
|
|
452
622
|
};
|
|
453
623
|
}
|
|
@@ -483,6 +653,12 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
483
653
|
/* the outcome is already reported; a lost note is not a lost outcome */
|
|
484
654
|
}
|
|
485
655
|
}
|
|
656
|
+
mayApplyOnScreen() {
|
|
657
|
+
if (this.openedFor === this.scopeKey(currentAssistantSurface()) && this.openedIdentity === this.identityKey())
|
|
658
|
+
return true;
|
|
659
|
+
notify({ level: 'info', message: t('return-to-subject', 'Return to the conversation subject before applying this proposal.') });
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
486
662
|
/* ── drawing ─────────────────────────────────────────────────────────────────────── */
|
|
487
663
|
stuckLine() {
|
|
488
664
|
if (this.capability === 'not-configured')
|
|
@@ -512,16 +688,16 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
512
688
|
<md-icon>home</md-icon>
|
|
513
689
|
</button>`
|
|
514
690
|
: nothing}
|
|
515
|
-
${ready
|
|
691
|
+
${ready && this.showingHistory
|
|
516
692
|
? html `<button
|
|
517
693
|
class="sbtn"
|
|
518
694
|
title=${this.showingHistory ? t('back-to-conversation', 'back to the conversation') : t('conversations', 'conversations')}
|
|
519
695
|
@click=${() => (this.showingHistory = !this.showingHistory)}
|
|
520
696
|
>
|
|
521
|
-
<md-icon>${
|
|
697
|
+
<md-icon>arrow_back</md-icon>${t('back-to-conversation', 'back to the conversation')}
|
|
522
698
|
</button>`
|
|
523
699
|
: nothing}
|
|
524
|
-
<button class="sbtn" title=${t('rebind', 'follow this screen again')} @click=${() => this.
|
|
700
|
+
<button class="sbtn" title=${t('rebind', 'follow this screen again')} @click=${() => this.requestSurface(currentAssistantSurface())}>
|
|
525
701
|
<md-icon>refresh</md-icon>
|
|
526
702
|
</button>
|
|
527
703
|
<button class="sbtn" title=${t('close', 'close')} @click=${() => closeOverlay(this.viewpart)}>
|
|
@@ -532,9 +708,7 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
532
708
|
}
|
|
533
709
|
/** The home button: talk about the application instead of this screen, until the screen changes. */
|
|
534
710
|
useSurface(surface) {
|
|
535
|
-
this.surface
|
|
536
|
-
this.chosenKind = '';
|
|
537
|
-
void this.open();
|
|
711
|
+
void this.requestSurface(surface);
|
|
538
712
|
}
|
|
539
713
|
render() {
|
|
540
714
|
const anchor = this.anchor;
|
|
@@ -546,6 +720,14 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
546
720
|
const mode = ready ? { kind: this.kind, target: anchor.anchorId, hostContext: {} } : undefined;
|
|
547
721
|
return html `
|
|
548
722
|
${this.header()}
|
|
723
|
+
${surface?.nextStep ? html `<div class="next-step" role="status">
|
|
724
|
+
<span>${surface.nextStep.description?.() || ''}</span>
|
|
725
|
+
<a href=${surface.nextStep.href}>${surface.nextStep.label()}<md-icon>arrow_forward</md-icon></a>
|
|
726
|
+
</div>` : nothing}
|
|
727
|
+
${this.screenChanged ? html `<div class="transition" role="status">
|
|
728
|
+
${t('screen-and-conversation', 'Screen: {screen}. Conversation: {conversation}. Your conversation has been kept.', { screen: currentAssistantSurface()?.label() || t('no-subject', 'No subject'), conversation: surface?.label() || '' })}
|
|
729
|
+
<button class="sbtn" @click=${() => this.requestSurface(currentAssistantSurface())}>${t('switch-to-screen', 'Talk about this screen')}</button>
|
|
730
|
+
</div>` : this.navigationNotice ? html `<div class="transition" role="status">${this.navigationNotice}</div>` : nothing}
|
|
549
731
|
${ready && this.showingHistory
|
|
550
732
|
? html `<ox-assistant-session-manager
|
|
551
733
|
.anchorType=${anchor.anchorType}
|
|
@@ -553,6 +735,7 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
553
735
|
.sessionId=${this.sessionId}
|
|
554
736
|
.kind=${this.kind}
|
|
555
737
|
.kindLabels=${this.kindLabels}
|
|
738
|
+
.scopeLabel=${t('conversation-scope', 'Conversations · {name}', { name: surface?.label() || '' })}
|
|
556
739
|
@assistant-session-select=${(event) => this.selectSession(event.detail.sessionId, event.detail.kind)}
|
|
557
740
|
@assistant-session-reset=${() => this.newConversation()}
|
|
558
741
|
@assistant-session-changed=${() => this.reloadSessions()}
|
|
@@ -565,20 +748,29 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
565
748
|
.loading=${this.loading}
|
|
566
749
|
.error=${this.failure}
|
|
567
750
|
historyEnabled
|
|
751
|
+
singleConversation
|
|
568
752
|
@assistant-session-select=${(event) => this.selectSession(event.detail.sessionId)}
|
|
569
753
|
@assistant-session-reset=${() => this.newConversation()}
|
|
570
754
|
@assistant-session-history=${() => (this.showingHistory = true)}
|
|
571
755
|
@assistant-session-retry=${() => this.open()}
|
|
572
756
|
></ox-assistant-session-toolbar>`
|
|
573
757
|
: nothing}
|
|
574
|
-
${ready && !this.showingHistory &&
|
|
758
|
+
${ready && !this.showingHistory && this.audience === 'open'
|
|
759
|
+
? html `<div class="audience" role="status">
|
|
760
|
+
<md-icon>public</md-icon>
|
|
761
|
+
<span>${t('audience-open-band', 'Public conversation - everyone in this domain can read and write here.')}</span>
|
|
762
|
+
</div>`
|
|
763
|
+
: nothing}
|
|
764
|
+
${ready && !this.loading && !this.failure
|
|
575
765
|
? keyed(this.conversationView, html `<ox-assistant-chat
|
|
766
|
+
?hidden=${this.showingHistory}
|
|
767
|
+
.sendBlocked=${this.screenChanged ? t('return-to-subject', 'Return to the conversation subject before sending or applying changes.') : ''}
|
|
576
768
|
.sessionId=${this.sessionId}
|
|
577
769
|
.prepareSession=${(adopt) => this.controller.prepareSession(adopt)}
|
|
578
770
|
.contextProvider=${() => {
|
|
579
771
|
/* The screen moved on between writing and sending - do not answer about the old one. */
|
|
580
|
-
if (openedFor !== this.scopeKey(currentAssistantSurface()
|
|
581
|
-
throw new Error(t('
|
|
772
|
+
if (openedFor !== this.scopeKey(currentAssistantSurface()) || this.openedIdentity !== this.identityKey())
|
|
773
|
+
throw new Error(t('return-to-subject', 'Return to the conversation subject before applying this proposal.'));
|
|
582
774
|
return { hostContext: surface?.hostContext?.() ?? {} };
|
|
583
775
|
}}
|
|
584
776
|
.mode=${mode}
|
|
@@ -598,6 +790,7 @@ let AssistantDock = class AssistantDock extends localize(i18next)(LitElement) {
|
|
|
598
790
|
.draftRequestId=${this.asking?.requestId}
|
|
599
791
|
@assistant-mode-change=${this.onModeChange}
|
|
600
792
|
@assistant-proposal-execute=${this.onProposal}
|
|
793
|
+
@assistant-proposal-check=${this.onProposalCheck}
|
|
601
794
|
@scene-edit-patch=${this.onScenePatch}
|
|
602
795
|
@board-edit-revert=${this.onBoardRevert}
|
|
603
796
|
@scene-action-execute=${this.onSceneAction}
|
|
@@ -676,6 +869,14 @@ __decorate([
|
|
|
676
869
|
state(),
|
|
677
870
|
__metadata("design:type", Object)
|
|
678
871
|
], AssistantDock.prototype, "asking", void 0);
|
|
872
|
+
__decorate([
|
|
873
|
+
state(),
|
|
874
|
+
__metadata("design:type", Object)
|
|
875
|
+
], AssistantDock.prototype, "screenChanged", void 0);
|
|
876
|
+
__decorate([
|
|
877
|
+
state(),
|
|
878
|
+
__metadata("design:type", Object)
|
|
879
|
+
], AssistantDock.prototype, "navigationNotice", void 0);
|
|
679
880
|
AssistantDock = __decorate([
|
|
680
881
|
customElement('ox-assistant-dock')
|
|
681
882
|
], AssistantDock);
|