@genesislcap/ai-assistant 15.61.0 → 15.63.0
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/dist/ai-assistant.api.json +18231 -11171
- package/dist/ai-assistant.d.ts +1235 -9
- package/dist/chat-driver.cjs +658 -50
- package/dist/chat-driver.cjs.map +4 -4
- package/dist/chat-driver.mjs +657 -50
- package/dist/chat-driver.mjs.map +4 -4
- package/dist/custom-elements.json +4759 -717
- package/dist/dts/autopilot/autopilot-driver.d.ts +278 -0
- package/dist/dts/autopilot/autopilot-driver.d.ts.map +1 -0
- package/dist/dts/autopilot/autopilot-session.d.ts +163 -0
- package/dist/dts/autopilot/autopilot-session.d.ts.map +1 -0
- package/dist/dts/autopilot/autopilot-tools.d.ts +15 -0
- package/dist/dts/autopilot/autopilot-tools.d.ts.map +1 -0
- package/dist/dts/autopilot/decision-message.d.ts +62 -0
- package/dist/dts/autopilot/decision-message.d.ts.map +1 -0
- package/dist/dts/autopilot/hand-back/hand-back.controller.d.ts +69 -0
- package/dist/dts/autopilot/hand-back/hand-back.controller.d.ts.map +1 -0
- package/dist/dts/autopilot/hand-back/hand-back.d.ts +22 -0
- package/dist/dts/autopilot/hand-back/hand-back.d.ts.map +1 -0
- package/dist/dts/autopilot/index.d.ts +4 -0
- package/dist/dts/autopilot/index.d.ts.map +1 -0
- package/dist/dts/channel/ai-activity-bus.d.ts.map +1 -1
- package/dist/dts/channel/ai-activity-channel.d.ts +17 -0
- package/dist/dts/channel/ai-activity-channel.d.ts.map +1 -1
- package/dist/dts/channel/autopilot-needs-user.d.ts +8 -0
- package/dist/dts/channel/autopilot-needs-user.d.ts.map +1 -0
- package/dist/dts/components/agent-picker/agent-picker.constants.d.ts +10 -0
- package/dist/dts/components/agent-picker/agent-picker.constants.d.ts.map +1 -1
- package/dist/dts/components/agent-picker/agent-picker.d.ts +4 -0
- package/dist/dts/components/agent-picker/agent-picker.d.ts.map +1 -1
- package/dist/dts/components/agent-picker/agent-picker.template.d.ts.map +1 -1
- package/dist/dts/components/ai-driver/ai-driver.d.ts +34 -1
- package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
- package/dist/dts/components/ai-driver/base-driver-decorator.d.ts +3 -1
- package/dist/dts/components/ai-driver/base-driver-decorator.d.ts.map +1 -1
- package/dist/dts/components/chat-bubble/chat-bubble.d.ts +21 -0
- package/dist/dts/components/chat-bubble/chat-bubble.d.ts.map +1 -1
- package/dist/dts/components/chat-bubble/chat-bubble.styles.d.ts.map +1 -1
- package/dist/dts/components/chat-bubble/chat-bubble.template.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.d.ts +5 -1
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/interaction-controller.d.ts +27 -3
- package/dist/dts/components/chat-driver/interaction-controller.d.ts.map +1 -1
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts +10 -2
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts.map +1 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +9 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/config/config.d.ts +183 -0
- package/dist/dts/config/config.d.ts.map +1 -1
- package/dist/dts/config/define-stateful-agent.d.ts +31 -1
- package/dist/dts/config/define-stateful-agent.d.ts.map +1 -1
- package/dist/dts/genesis/write-commit.d.ts +17 -7
- package/dist/dts/genesis/write-commit.d.ts.map +1 -1
- package/dist/dts/index.d.ts +7 -3
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +128 -5
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts +2 -2
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/react.d.ts +10 -0
- package/dist/dts/state/debug-event-log.d.ts +1 -1
- package/dist/dts/state/debug-event-log.d.ts.map +1 -1
- package/dist/dts/state/decision-surface.d.ts +46 -0
- package/dist/dts/state/decision-surface.d.ts.map +1 -0
- package/dist/dts/state/interaction-context.d.ts +21 -1
- package/dist/dts/state/interaction-context.d.ts.map +1 -1
- package/dist/dts/state/interaction-registry.d.ts +63 -0
- package/dist/dts/state/interaction-registry.d.ts.map +1 -0
- package/dist/dts/state/persistence/session-persister.d.ts.map +1 -1
- package/dist/dts/state/persistence/session-snapshot.d.ts +21 -0
- package/dist/dts/state/persistence/session-snapshot.d.ts.map +1 -1
- package/dist/dts/state/run-steps.d.ts +66 -0
- package/dist/dts/state/run-steps.d.ts.map +1 -0
- package/dist/dts/types/ai-chat-widget.d.ts +7 -1
- package/dist/dts/types/ai-chat-widget.d.ts.map +1 -1
- package/dist/dts/types/interaction-context.d.ts +66 -1
- package/dist/dts/types/interaction-context.d.ts.map +1 -1
- package/dist/dts/types/interaction-interceptor.d.ts +60 -2
- package/dist/dts/types/interaction-interceptor.d.ts.map +1 -1
- package/dist/dts/types/interaction-surface.d.ts +195 -0
- package/dist/dts/types/interaction-surface.d.ts.map +1 -0
- package/dist/dts/utils/context-tokens.d.ts +6 -0
- package/dist/dts/utils/context-tokens.d.ts.map +1 -1
- package/dist/dts/utils/delegated-message.d.ts +13 -0
- package/dist/dts/utils/delegated-message.d.ts.map +1 -1
- package/dist/dts/utils/history-transform.d.ts.map +1 -1
- package/dist/dts/utils/preserved-user-messages.d.ts +21 -0
- package/dist/dts/utils/preserved-user-messages.d.ts.map +1 -0
- package/dist/esm/autopilot/autopilot-driver.js +906 -0
- package/dist/esm/autopilot/autopilot-session.js +449 -0
- package/dist/esm/autopilot/autopilot-tools.js +68 -0
- package/dist/esm/autopilot/decision-message.js +206 -0
- package/dist/esm/autopilot/hand-back/hand-back.controller.js +47 -0
- package/dist/esm/autopilot/hand-back/hand-back.js +129 -0
- package/dist/esm/autopilot/index.js +4 -0
- package/dist/esm/channel/ai-activity-bus.js +7 -0
- package/dist/esm/channel/autopilot-needs-user.js +26 -0
- package/dist/esm/components/agent-picker/agent-picker.constants.js +10 -0
- package/dist/esm/components/agent-picker/agent-picker.js +11 -1
- package/dist/esm/components/agent-picker/agent-picker.template.js +2 -4
- package/dist/esm/components/ai-driver/ai-driver.js +2 -0
- package/dist/esm/components/ai-driver/base-driver-decorator.js +8 -0
- package/dist/esm/components/chat-bubble/chat-bubble.js +45 -0
- package/dist/esm/components/chat-bubble/chat-bubble.styles.js +26 -0
- package/dist/esm/components/chat-bubble/chat-bubble.template.js +13 -0
- package/dist/esm/components/chat-driver/chat-driver.js +53 -18
- package/dist/esm/components/chat-driver/interaction-controller.js +297 -12
- package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.js +16 -2
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +28 -11
- package/dist/esm/config/define-stateful-agent.js +34 -29
- package/dist/esm/genesis/write-outcome.js +2 -2
- package/dist/esm/index.js +3 -0
- package/dist/esm/main/main.js +334 -15
- package/dist/esm/main/main.styles.js +126 -0
- package/dist/esm/main/main.template.js +116 -11
- package/dist/esm/state/debug-event-log.js +28 -1
- package/dist/esm/state/decision-surface.js +209 -0
- package/dist/esm/state/interaction-context.js +89 -1
- package/dist/esm/state/interaction-registry.js +33 -0
- package/dist/esm/state/persistence/session-persister.js +23 -11
- package/dist/esm/state/persistence/session-snapshot.js +1 -1
- package/dist/esm/state/run-steps.js +77 -0
- package/dist/esm/types/interaction-surface.js +1 -0
- package/dist/esm/utils/context-tokens.js +23 -9
- package/dist/esm/utils/delegated-message.js +15 -0
- package/dist/esm/utils/history-transform.js +18 -7
- package/dist/esm/utils/preserved-user-messages.js +31 -0
- package/dist/react.cjs +7 -0
- package/dist/react.mjs +6 -0
- package/docs/styling.md +1 -1
- package/package.json +17 -17
- package/sandbox/README.md +38 -2
- package/sandbox/autopilot.ts +358 -0
- package/sandbox/controls.ts +24 -1
- package/sandbox/fixtures.ts +2 -0
- package/sandbox/sandbox.ts +188 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { getInteractionRegistration } from '../state/interaction-registry';
|
|
2
|
+
import { filterVisibleMessages } from '../utils/message-partition';
|
|
3
|
+
/** How long a fallback dump of a widget's data may run, in characters. */
|
|
4
|
+
const FALLBACK_DATA_CHARS = 2000;
|
|
5
|
+
/**
|
|
6
|
+
* A widget as text: what the person saw (GENC-1660 §4.7). From its registration's `asText` when it
|
|
7
|
+
* has one; otherwise its name and a size-limited dump of its data — ugly, never wrong, and a nudge
|
|
8
|
+
* to register one.
|
|
9
|
+
*/
|
|
10
|
+
export function widgetAsText(componentName, data, result) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
const asText = (_a = getInteractionRegistration(componentName)) === null || _a === void 0 ? void 0 : _a.asText;
|
|
13
|
+
if (asText) {
|
|
14
|
+
try {
|
|
15
|
+
return asText(data, result);
|
|
16
|
+
}
|
|
17
|
+
catch (_c) {
|
|
18
|
+
// Fall through to the dump: a broken text form must not hide the decision.
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const dump = (_b = JSON.stringify(data)) !== null && _b !== void 0 ? _b : '';
|
|
22
|
+
return `[${componentName}] ${dump.length > FALLBACK_DATA_CHARS ? `${dump.slice(0, FALLBACK_DATA_CHARS)}…` : dump}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* List a surface's actions for the model (GENC-1660 §4.2). Options are numbered from 1, so they are
|
|
26
|
+
* chosen by number rather than by retyping a label; platform-owned actions keep their names. An
|
|
27
|
+
* unavailable action is listed, and marked, so the model knows it exists but cannot take it.
|
|
28
|
+
*/
|
|
29
|
+
export function renderActions(actions, options = {}) {
|
|
30
|
+
var _a;
|
|
31
|
+
const numbering = [];
|
|
32
|
+
const lines = [];
|
|
33
|
+
for (const action of actions) {
|
|
34
|
+
// Past the refinement limit, `reply` is not offered at all: not listed, not runnable.
|
|
35
|
+
if (options.withholdReply && action.args === 'text')
|
|
36
|
+
continue;
|
|
37
|
+
const unavailable = action.enabled ? '' : ' (not available right now)';
|
|
38
|
+
if (action.description !== undefined) {
|
|
39
|
+
// A full-form action: named, described, and finishing or not.
|
|
40
|
+
const call = action.args === 'fields' ? `${action.name}({fields})` : `${action.name}()`;
|
|
41
|
+
const settles = action.finishes ? 'settles it' : 'does not settle it';
|
|
42
|
+
lines.push(` ${call} — ${action.description} (${settles})${unavailable}`);
|
|
43
|
+
if (action.argsSchema)
|
|
44
|
+
lines.push(` fields schema: ${JSON.stringify(action.argsSchema)}`);
|
|
45
|
+
}
|
|
46
|
+
else if (action.args === 'options') {
|
|
47
|
+
lines.push(` select({options}) — choose several, by number or label${unavailable}`);
|
|
48
|
+
}
|
|
49
|
+
else if (action.args === 'text') {
|
|
50
|
+
lines.push(` reply({text}) — answer in your own words${unavailable}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
numbering.push(action.name);
|
|
54
|
+
lines.push(` [${numbering.length}] "${(_a = action.label) !== null && _a !== void 0 ? _a : action.name}"${unavailable}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const allSettle = actions.every((a) => a.description === undefined);
|
|
58
|
+
return {
|
|
59
|
+
text: `${allSettle ? 'Actions (each settles it)' : 'Actions'}:\n${lines.join('\n')}`,
|
|
60
|
+
numbering,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The current decision as one message for the autopilot (GENC-1660 §4.2). */
|
|
64
|
+
export function renderDecision(opts) {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
const { surface } = opts;
|
|
67
|
+
const facts = surface.facts();
|
|
68
|
+
const actions = renderActions(surface.actions(), { withholdReply: opts.withholdReply });
|
|
69
|
+
// A full-form surface describes itself, lists its views, and shows its default view up front, to
|
|
70
|
+
// save a round trip.
|
|
71
|
+
let full = [];
|
|
72
|
+
if (surface.describe) {
|
|
73
|
+
let preview = '';
|
|
74
|
+
try {
|
|
75
|
+
preview = JSON.stringify((_a = surface.read) === null || _a === void 0 ? void 0 : _a.call(surface));
|
|
76
|
+
}
|
|
77
|
+
catch (_c) {
|
|
78
|
+
preview = '';
|
|
79
|
+
}
|
|
80
|
+
full = [
|
|
81
|
+
surface.describe(),
|
|
82
|
+
...(((_b = surface.views) === null || _b === void 0 ? void 0 : _b.length) ? [`Views (widget_read): ${surface.views.join(', ')}`] : []),
|
|
83
|
+
...(preview ? [`Now: ${preview}`] : []),
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
const parts = [
|
|
87
|
+
`<interaction id="${opts.interactionId}" widget="${opts.componentName}">`,
|
|
88
|
+
widgetAsText(opts.componentName, opts.data),
|
|
89
|
+
...full,
|
|
90
|
+
...(Object.keys(facts).length ? [`Facts: ${JSON.stringify(facts)}`] : []),
|
|
91
|
+
...(surface.prompt ? [`Guidance: ${surface.prompt}`] : []),
|
|
92
|
+
actions.text,
|
|
93
|
+
...(opts.decideYourself
|
|
94
|
+
? [
|
|
95
|
+
'The user handed this one back to you and asked you to use your best judgement: decide it yourself. hand_back is not available.',
|
|
96
|
+
]
|
|
97
|
+
: []),
|
|
98
|
+
'</interaction>',
|
|
99
|
+
];
|
|
100
|
+
return { text: parts.join('\n'), numbering: actions.numbering };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A written question the working agent ended its turn on, as one message for the autopilot
|
|
104
|
+
* (GENC-1660 §4.2): answer it in the user's place, or hand it back.
|
|
105
|
+
*/
|
|
106
|
+
export function renderQuestion(question, opts = {}) {
|
|
107
|
+
return [
|
|
108
|
+
'<question>',
|
|
109
|
+
'The assistant asked the user this, and is waiting for their answer:',
|
|
110
|
+
question,
|
|
111
|
+
"Actions:\n reply({text}) — answer it in the user's place, with widget_act",
|
|
112
|
+
...(opts.decideYourself
|
|
113
|
+
? ['The user asked you to use your best judgement: hand_back is not available.']
|
|
114
|
+
: []),
|
|
115
|
+
'</question>',
|
|
116
|
+
].join('\n');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* What the person sees with the chat's default settings: no reasoning, no narration, no tool calls.
|
|
120
|
+
* The autopilot sees the same, whatever toggles this user has switched on, so runs are repeatable
|
|
121
|
+
* (§4.7, §4.11).
|
|
122
|
+
*/
|
|
123
|
+
const DEFAULT_VISIBILITY = {
|
|
124
|
+
showToolCalls: false,
|
|
125
|
+
showThinkingSteps: false,
|
|
126
|
+
showNarration: false,
|
|
127
|
+
showAgentSwitchIndicator: false,
|
|
128
|
+
showRestoreNotices: false,
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Who answered a resolved widget, as the autopilot is told. Nobody, only when it timed out: the
|
|
132
|
+
* record of who answered is newer than some saved sessions, so a widget without one that did not
|
|
133
|
+
* time out was answered by the person. `claimant` is this autopilot; any other claimant answered on
|
|
134
|
+
* the user's behalf.
|
|
135
|
+
*/
|
|
136
|
+
const answeredPhrase = (resolved, answeredBy, claimant) => {
|
|
137
|
+
if ((resolved === null || resolved === void 0 ? void 0 : resolved.status) === 'timeout') {
|
|
138
|
+
return 'answered by nobody';
|
|
139
|
+
}
|
|
140
|
+
if (answeredBy === claimant)
|
|
141
|
+
return 'answered by you';
|
|
142
|
+
if (answeredBy === undefined || answeredBy === 'user')
|
|
143
|
+
return 'answered by the user';
|
|
144
|
+
return "answered on the user's behalf";
|
|
145
|
+
};
|
|
146
|
+
/** Recent entries a short-form transcript keeps verbatim. */
|
|
147
|
+
const SHORT_FORM_RECENT = 20;
|
|
148
|
+
/**
|
|
149
|
+
* What the person could see in `messages`, as lines, for the autopilot's `<since-last>` block
|
|
150
|
+
* (GENC-1660 §4.7). Built with the renderer's own visibility function at the default settings, so
|
|
151
|
+
* what the autopilot is told and what the person sees cannot drift: verbatim user messages and
|
|
152
|
+
* visible assistant output (driver notices included — hidden from the model is not hidden from the
|
|
153
|
+
* person); interactions by their text form and who answered. Never the working agent's hidden prose,
|
|
154
|
+
* tool calls or results: the autopilot checks proposals against its grounding, not against the
|
|
155
|
+
* argument that produced them.
|
|
156
|
+
*
|
|
157
|
+
* `claimant` is this autopilot's id. Its own messages — what it said to the person, and what it
|
|
158
|
+
* sent on the user's behalf — are left out while its own history holds them; `includeOwn` puts them
|
|
159
|
+
* in, labelled as its own, for when it does not (a first decision, a reload, a rebuild, or a
|
|
160
|
+
* compaction that removed what it last saw). `short` keeps the last entries verbatim and reduces
|
|
161
|
+
* older answered widgets to their first line — the form a catch-up after a long flow uses.
|
|
162
|
+
*/
|
|
163
|
+
export function visibleTranscript(messages, opts) {
|
|
164
|
+
const visible = filterVisibleMessages([...messages], DEFAULT_VISIBILITY);
|
|
165
|
+
const olderThan = opts.short ? visible.length - SHORT_FORM_RECENT : -1;
|
|
166
|
+
const lines = [];
|
|
167
|
+
visible.forEach((m, i) => {
|
|
168
|
+
var _a, _b, _c, _d, _e, _f;
|
|
169
|
+
if (m.interaction) {
|
|
170
|
+
const { interactionId, componentName, data, resolved, answeredBy } = m.interaction;
|
|
171
|
+
if (interactionId === opts.skipInteractionId || !resolved)
|
|
172
|
+
return;
|
|
173
|
+
const answered = answeredPhrase(resolved, answeredBy, opts.claimant);
|
|
174
|
+
const text = widgetAsText(componentName, data, resolved);
|
|
175
|
+
lines.push(`[${componentName}, ${answered}] ${i < olderThan ? text.split('\n')[0] : text}`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (m.role === 'compacted-summary') {
|
|
179
|
+
lines.push(`[Earlier, summarised] ${(_a = m.content) !== null && _a !== void 0 ? _a : ''}`);
|
|
180
|
+
// The user's own words from the summarised part, which a summary must not paraphrase.
|
|
181
|
+
for (const u of (_c = (_b = m.compaction) === null || _b === void 0 ? void 0 : _b.preservedUserMessages) !== null && _c !== void 0 ? _c : []) {
|
|
182
|
+
lines.push(u.delegate === opts.claimant && opts.includeOwn
|
|
183
|
+
? `You (on the user's behalf, earlier): ${u.content}`
|
|
184
|
+
: u.delegate
|
|
185
|
+
? `User (on their behalf, earlier): ${u.content}`
|
|
186
|
+
: `User (earlier): ${u.content}`);
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (m.delegate === opts.claimant) {
|
|
191
|
+
if (!opts.includeOwn || !((_d = m.content) === null || _d === void 0 ? void 0 : _d.trim()))
|
|
192
|
+
return;
|
|
193
|
+
lines.push(m.role === 'assistant'
|
|
194
|
+
? `You (to the user): ${m.content}`
|
|
195
|
+
: `You (on the user's behalf): ${m.content}`);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if ((m.role === 'user' || m.role === 'synthetic-user') && ((_e = m.content) === null || _e === void 0 ? void 0 : _e.trim())) {
|
|
199
|
+
lines.push(m.delegate ? `User (on their behalf): ${m.content}` : `User: ${m.content}`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (m.role === 'assistant' && ((_f = m.content) === null || _f === void 0 ? void 0 : _f.trim()))
|
|
203
|
+
lines.push(`Assistant: ${m.content}`);
|
|
204
|
+
});
|
|
205
|
+
return lines;
|
|
206
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tag of the turn-level hand-back widget (GENC-1660 §4.10): what the autopilot shows when a
|
|
3
|
+
* working turn ends needing the person, and there is no widget to hand over.
|
|
4
|
+
*
|
|
5
|
+
* @beta
|
|
6
|
+
*/
|
|
7
|
+
export const AUTOPILOT_HAND_BACK = 'ai-autopilot-hand-back';
|
|
8
|
+
/**
|
|
9
|
+
* The hand-back's controller. DOM-free: it exposes the choices as a decision (so the visible
|
|
10
|
+
* transcript and the debug log describe it like any widget) and resolves through `ctx.resolve`. The
|
|
11
|
+
* hand-back is always `userOnly`, so nothing but the person ever answers it.
|
|
12
|
+
*/
|
|
13
|
+
export class HandBackController {
|
|
14
|
+
constructor(data, ctx) {
|
|
15
|
+
this.data = data;
|
|
16
|
+
this.ctx = ctx;
|
|
17
|
+
ctx.exposeDecision({
|
|
18
|
+
options: data.options.map((o) => ({ id: o.id, label: o.label })),
|
|
19
|
+
freeText: data.freeText,
|
|
20
|
+
choose: (answer) => this.choose(answer),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/** The person's choice, from the view's buttons or its text box. */
|
|
24
|
+
choose(answer) {
|
|
25
|
+
const payload = answer.kind === 'text'
|
|
26
|
+
? { choice: 'reply', text: answer.text }
|
|
27
|
+
: {
|
|
28
|
+
choice: (answer.kind === 'option'
|
|
29
|
+
? answer.option
|
|
30
|
+
: answer.options[0]),
|
|
31
|
+
};
|
|
32
|
+
this.ctx.resolve({ status: 'approved', payload });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** The hand-back as text: what the person saw, and what they chose. */
|
|
36
|
+
export function handBackAsText(data, result) {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
const d = data;
|
|
39
|
+
const lines = [d.message, ...(d.question ? [`Question: ${d.question}`] : [])];
|
|
40
|
+
lines.push(`Options: ${d.options.map((o) => o.label).join(' | ')}`);
|
|
41
|
+
const payload = result === null || result === void 0 ? void 0 : result.payload;
|
|
42
|
+
if (payload) {
|
|
43
|
+
const label = (_b = (_a = d.options.find((o) => o.id === payload.choice)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : payload.choice;
|
|
44
|
+
lines.push(`Answer: ${payload.choice === 'reply' ? payload.text : label}`);
|
|
45
|
+
}
|
|
46
|
+
return lines.join('\n');
|
|
47
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { css, customElement, GenesisElement, html, observable, repeat, when, } from '@genesislcap/web-core';
|
|
3
|
+
import { AUTOPILOT_HAND_BACK, } from './hand-back.controller';
|
|
4
|
+
const template = html `
|
|
5
|
+
<p class="message">${(x) => { var _a; return (_a = x.data) === null || _a === void 0 ? void 0 : _a.message; }}</p>
|
|
6
|
+
${when((x) => { var _a; return !!((_a = x.data) === null || _a === void 0 ? void 0 : _a.question); }, html `
|
|
7
|
+
<p class="question">${(x) => { var _a; return (_a = x.data) === null || _a === void 0 ? void 0 : _a.question; }}</p>
|
|
8
|
+
`)}
|
|
9
|
+
${when((x) => x.answer !== undefined, html `
|
|
10
|
+
<p class="answer">✓ ${(x) => x.answer}</p>
|
|
11
|
+
`)}
|
|
12
|
+
${when((x) => x.answer === undefined, html `
|
|
13
|
+
${when((x) => { var _a; return !!((_a = x.data) === null || _a === void 0 ? void 0 : _a.freeText); }, html `
|
|
14
|
+
<textarea
|
|
15
|
+
class="reply"
|
|
16
|
+
rows="2"
|
|
17
|
+
:value="${(x) => x.draft}"
|
|
18
|
+
@input="${(x, c) => {
|
|
19
|
+
x.draft = c.event.target.value;
|
|
20
|
+
return true;
|
|
21
|
+
}}"
|
|
22
|
+
></textarea>
|
|
23
|
+
<rapid-button
|
|
24
|
+
appearance="accent"
|
|
25
|
+
?disabled="${(x) => !x.draft.trim()}"
|
|
26
|
+
@click="${(x) => {
|
|
27
|
+
x.reply();
|
|
28
|
+
return true;
|
|
29
|
+
}}"
|
|
30
|
+
>
|
|
31
|
+
${(x) => { var _a; return (_a = x.data) === null || _a === void 0 ? void 0 : _a.sendLabel; }}
|
|
32
|
+
</rapid-button>
|
|
33
|
+
`)}
|
|
34
|
+
<div class="options">
|
|
35
|
+
${repeat((x) => { var _a, _b; return (_b = (_a = x.data) === null || _a === void 0 ? void 0 : _a.options) !== null && _b !== void 0 ? _b : []; }, html `
|
|
36
|
+
<rapid-button
|
|
37
|
+
@click="${(o, c) => {
|
|
38
|
+
c.parent.choose(o.id);
|
|
39
|
+
return true;
|
|
40
|
+
}}"
|
|
41
|
+
>
|
|
42
|
+
${(o) => o.label}
|
|
43
|
+
</rapid-button>
|
|
44
|
+
`)}
|
|
45
|
+
</div>
|
|
46
|
+
`)}
|
|
47
|
+
`;
|
|
48
|
+
const styles = css `
|
|
49
|
+
:host {
|
|
50
|
+
display: block;
|
|
51
|
+
font: inherit;
|
|
52
|
+
}
|
|
53
|
+
.message,
|
|
54
|
+
.question,
|
|
55
|
+
.answer {
|
|
56
|
+
margin: 0 0 calc(var(--design-unit) * 2px);
|
|
57
|
+
}
|
|
58
|
+
.question {
|
|
59
|
+
font-style: italic;
|
|
60
|
+
}
|
|
61
|
+
.reply {
|
|
62
|
+
width: 100%;
|
|
63
|
+
box-sizing: border-box;
|
|
64
|
+
font: inherit;
|
|
65
|
+
margin-bottom: calc(var(--design-unit) * 2px);
|
|
66
|
+
}
|
|
67
|
+
.options {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-wrap: wrap;
|
|
70
|
+
gap: calc(var(--design-unit) * 2px);
|
|
71
|
+
margin-top: calc(var(--design-unit) * 2px);
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
/**
|
|
75
|
+
* The turn-level hand-back's view (GENC-1660 §4.10): the message, the working agent's question if
|
|
76
|
+
* there was one, and the choices. It only renders: choosing calls the controller, which resolves.
|
|
77
|
+
* Always the person's to answer (`userOnly`), so it never hides itself.
|
|
78
|
+
*
|
|
79
|
+
* @beta
|
|
80
|
+
*/
|
|
81
|
+
let AutopilotHandBack = class AutopilotHandBack extends GenesisElement {
|
|
82
|
+
constructor() {
|
|
83
|
+
super(...arguments);
|
|
84
|
+
this.interactionId = '';
|
|
85
|
+
this.draft = '';
|
|
86
|
+
}
|
|
87
|
+
get data() {
|
|
88
|
+
var _a;
|
|
89
|
+
return (_a = this.interaction) === null || _a === void 0 ? void 0 : _a.data;
|
|
90
|
+
}
|
|
91
|
+
/** What was chosen, once resolved. */
|
|
92
|
+
get answer() {
|
|
93
|
+
var _a, _b, _c, _d, _e;
|
|
94
|
+
if (((_a = this.interaction) === null || _a === void 0 ? void 0 : _a.status) !== 'resolved')
|
|
95
|
+
return undefined;
|
|
96
|
+
const payload = this.interaction.result.payload;
|
|
97
|
+
if (!payload)
|
|
98
|
+
return '';
|
|
99
|
+
if (payload.choice === 'reply')
|
|
100
|
+
return (_b = payload.text) !== null && _b !== void 0 ? _b : '';
|
|
101
|
+
return (_e = (_d = (_c = this.data) === null || _c === void 0 ? void 0 : _c.options.find((o) => o.id === payload.choice)) === null || _d === void 0 ? void 0 : _d.label) !== null && _e !== void 0 ? _e : payload.choice;
|
|
102
|
+
}
|
|
103
|
+
get controller() {
|
|
104
|
+
var _a;
|
|
105
|
+
return ((_a = this.interaction) === null || _a === void 0 ? void 0 : _a.status) === 'pending'
|
|
106
|
+
? this.interaction.interactionContext.controller
|
|
107
|
+
: undefined;
|
|
108
|
+
}
|
|
109
|
+
choose(option) {
|
|
110
|
+
var _a;
|
|
111
|
+
(_a = this.controller) === null || _a === void 0 ? void 0 : _a.choose({ kind: 'option', option });
|
|
112
|
+
}
|
|
113
|
+
reply() {
|
|
114
|
+
var _a;
|
|
115
|
+
const text = this.draft.trim();
|
|
116
|
+
if (text)
|
|
117
|
+
(_a = this.controller) === null || _a === void 0 ? void 0 : _a.choose({ kind: 'text', text });
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
__decorate([
|
|
121
|
+
observable
|
|
122
|
+
], AutopilotHandBack.prototype, "interaction", void 0);
|
|
123
|
+
__decorate([
|
|
124
|
+
observable
|
|
125
|
+
], AutopilotHandBack.prototype, "draft", void 0);
|
|
126
|
+
AutopilotHandBack = __decorate([
|
|
127
|
+
customElement({ name: AUTOPILOT_HAND_BACK, template, styles })
|
|
128
|
+
], AutopilotHandBack);
|
|
129
|
+
export { AutopilotHandBack };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AUTOPILOT_CLAIMANT, AutopilotDriver, } from './autopilot-driver';
|
|
2
|
+
export { AUTOPILOT_HAND_BACK, } from './hand-back/hand-back.controller';
|
|
3
|
+
// The view: importing the package defines the element, so the host can render the hand-back.
|
|
4
|
+
export { AutopilotHandBack } from './hand-back/hand-back';
|
|
@@ -41,6 +41,7 @@ export class AgenticActivityBus {
|
|
|
41
41
|
* browser environment; elsewhere the bus stays purely in-process.
|
|
42
42
|
*/
|
|
43
43
|
ensureChannel() {
|
|
44
|
+
var _a, _b;
|
|
44
45
|
if (this.channelInitialised)
|
|
45
46
|
return;
|
|
46
47
|
this.channelInitialised = true;
|
|
@@ -48,6 +49,12 @@ export class AgenticActivityBus {
|
|
|
48
49
|
if (this.crossTabEvents.size === 0 || !this.channelNameFactory || !inBrowser)
|
|
49
50
|
return;
|
|
50
51
|
this.channel = new BroadcastChannel(this.channelNameFactory());
|
|
52
|
+
// Node's BroadcastChannel (which jsdom test runs get, since they also have a `window`) is an
|
|
53
|
+
// open handle that keeps the process alive, and tests that touched the bus hung after their last
|
|
54
|
+
// assertion, again and again, unless they remembered to `close()` it. Unref it so a channel can
|
|
55
|
+
// never hold the process open: it still delivers while anything else keeps the process running.
|
|
56
|
+
// Browsers have no `unref` (a tab never "exits"), so there this does nothing.
|
|
57
|
+
(_b = (_a = this.channel).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
51
58
|
this.channel.onmessage = (ev) => {
|
|
52
59
|
var _a;
|
|
53
60
|
const { type, detail } = ((_a = ev.data) !== null && _a !== void 0 ? _a : {});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { agenticActivityBus } from './ai-activity-bus';
|
|
2
|
+
/**
|
|
3
|
+
* Which sessions have something waiting on the person while their autopilot is available
|
|
4
|
+
* (GENC-1660 §4.10), kept as well as announced: the collapsed assistant can mount after the change
|
|
5
|
+
* was published — a popin, or a host adding the bubble late — and an event alone would leave its
|
|
6
|
+
* badge wrong until the next change. Keyed by session, so two assistants on one page each badge
|
|
7
|
+
* only their own.
|
|
8
|
+
*/
|
|
9
|
+
const waiting = new Set();
|
|
10
|
+
/** Set it for one session, announcing `autopilot-needs-user` when it changes. */
|
|
11
|
+
export function setAutopilotNeedsUser(sessionKey, needsUser) {
|
|
12
|
+
if (waiting.has(sessionKey) === needsUser)
|
|
13
|
+
return;
|
|
14
|
+
if (needsUser)
|
|
15
|
+
waiting.add(sessionKey);
|
|
16
|
+
else
|
|
17
|
+
waiting.delete(sessionKey);
|
|
18
|
+
agenticActivityBus.publish('autopilot-needs-user', { sessionKey, needsUser });
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Whether a session has something waiting on the person — or, without a key (a bubble that cannot
|
|
22
|
+
* tell which assistant it holds), whether any session has.
|
|
23
|
+
*/
|
|
24
|
+
export function autopilotNeedsUser(sessionKey) {
|
|
25
|
+
return sessionKey === undefined ? waiting.size > 0 : waiting.has(sessionKey);
|
|
26
|
+
}
|
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
/** Sentinel value representing "Auto" where a menu row needs a string value. */
|
|
2
2
|
export const AGENT_PICKER_AUTO_VALUE = '__auto__';
|
|
3
|
+
/**
|
|
4
|
+
* The picker's default name for orchestration: the assistant routes each message to the agent it
|
|
5
|
+
* suits, as opposed to a pinned agent. Not "Auto", which other tools use for picking a model tier;
|
|
6
|
+
* "Orchestration" says that several agents stand behind it.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_ORCHESTRATION_LABEL = 'Orchestration';
|
|
9
|
+
/** The same choice as the picker menu's first row. The same word by default; separate so a host can say more there. */
|
|
10
|
+
export const DEFAULT_ORCHESTRATION_MENU_LABEL = 'Orchestration';
|
|
11
|
+
/** What orchestration does, as the menu row's hint and the pill's tooltip. */
|
|
12
|
+
export const DEFAULT_ORCHESTRATION_DESCRIPTION = 'Each message goes to the specialist it suits.';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { customElement, GenesisElement, observable, volatile } from '@genesislcap/web-core';
|
|
3
3
|
import { pinColourAt } from '../../styles/ai-colours';
|
|
4
|
-
import { AGENT_PICKER_AUTO_VALUE } from './agent-picker.constants';
|
|
4
|
+
import { AGENT_PICKER_AUTO_VALUE, DEFAULT_ORCHESTRATION_DESCRIPTION, DEFAULT_ORCHESTRATION_MENU_LABEL, } from './agent-picker.constants';
|
|
5
5
|
import { styles } from './agent-picker.styles';
|
|
6
6
|
import { AgentPickerTemplate } from './agent-picker.template';
|
|
7
7
|
export { AGENT_PICKER_AUTO_VALUE };
|
|
@@ -39,6 +39,10 @@ let AgentPicker = class AgentPicker extends GenesisElement {
|
|
|
39
39
|
this.pinnedAgentName = null;
|
|
40
40
|
/** When true, rows show a neutral dot instead of the per-agent brand tint. */
|
|
41
41
|
this.disablePinColours = false;
|
|
42
|
+
/** The orchestration row's name, from `chatConfig.picker.orchestrationMenuLabel` (resolved by the host). */
|
|
43
|
+
this.orchestrationLabel = DEFAULT_ORCHESTRATION_MENU_LABEL;
|
|
44
|
+
/** The orchestration row's hint, from `chatConfig.picker.orchestrationDescription` (resolved by the host). */
|
|
45
|
+
this.orchestrationDescription = DEFAULT_ORCHESTRATION_DESCRIPTION;
|
|
42
46
|
}
|
|
43
47
|
/** Top-level agents that opted in to manual selection. */
|
|
44
48
|
get selectableAgents() {
|
|
@@ -103,6 +107,12 @@ __decorate([
|
|
|
103
107
|
__decorate([
|
|
104
108
|
observable
|
|
105
109
|
], AgentPicker.prototype, "disablePinColours", void 0);
|
|
110
|
+
__decorate([
|
|
111
|
+
observable
|
|
112
|
+
], AgentPicker.prototype, "orchestrationLabel", void 0);
|
|
113
|
+
__decorate([
|
|
114
|
+
observable
|
|
115
|
+
], AgentPicker.prototype, "orchestrationDescription", void 0);
|
|
106
116
|
__decorate([
|
|
107
117
|
volatile
|
|
108
118
|
], AgentPicker.prototype, "selectableAgents", null);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { html, repeat } from '@genesislcap/web-core';
|
|
2
|
-
const AUTO_LABEL = 'Auto';
|
|
3
|
-
const AUTO_HINT = 'Let the assistant route each message to the right agent.';
|
|
4
2
|
/**
|
|
5
3
|
* One selectable row. `menuitemradio` rather than `menuitem` because the choice
|
|
6
4
|
* is single-select and sticky — a screen reader should announce which agent is
|
|
@@ -41,8 +39,8 @@ export const AgentPickerTemplate = () => html `
|
|
|
41
39
|
>
|
|
42
40
|
<span class="menu-item-mark" aria-hidden="true"></span>
|
|
43
41
|
<span class="menu-item-body">
|
|
44
|
-
<span class="menu-item-name">${() =>
|
|
45
|
-
<span class="menu-item-hint">${() =>
|
|
42
|
+
<span class="menu-item-name">${(x) => x.orchestrationLabel}</span>
|
|
43
|
+
<span class="menu-item-hint">${(x) => x.orchestrationDescription}</span>
|
|
46
44
|
</span>
|
|
47
45
|
</button>
|
|
48
46
|
<div class="menu-separator" role="separator"></div>
|
|
@@ -11,8 +11,10 @@ export const AI_DRIVER_EVENT_TYPES = Object.keys({
|
|
|
11
11
|
'sub-agent-stop': true,
|
|
12
12
|
'interaction-start': true,
|
|
13
13
|
'interaction-stop': true,
|
|
14
|
+
'interaction-settled': true,
|
|
14
15
|
'provider-changed': true,
|
|
15
16
|
'external-cost-recorded': true,
|
|
17
|
+
'checkpoint-saved': true,
|
|
16
18
|
'agent-changed': true,
|
|
17
19
|
'agent-released': true,
|
|
18
20
|
'flow-owner-changed': true,
|
|
@@ -119,6 +119,14 @@ export class BaseDriverDecorator extends EventTarget {
|
|
|
119
119
|
var _a, _b, _c;
|
|
120
120
|
return (_c = (_b = (_a = this.inner).getFlowOwner) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : null;
|
|
121
121
|
}
|
|
122
|
+
getInteractionCheckpoint() {
|
|
123
|
+
var _a, _b;
|
|
124
|
+
return (_b = (_a = this.inner).getInteractionCheckpoint) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
125
|
+
}
|
|
126
|
+
restoreInteractionCheckpoint(saved) {
|
|
127
|
+
var _a, _b;
|
|
128
|
+
(_b = (_a = this.inner).restoreInteractionCheckpoint) === null || _b === void 0 ? void 0 : _b.call(_a, saved);
|
|
129
|
+
}
|
|
122
130
|
/**
|
|
123
131
|
* Forwarded, so an interceptor installed on any layer lands on the driver that opens the
|
|
124
132
|
* interactions. A decorator that answers interactions installs its own on `this.inner`.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { attr, customElement, GenesisElement, html, observable } from '@genesislcap/web-core';
|
|
3
3
|
import { agenticActivityBus } from '../../channel/ai-activity-bus';
|
|
4
|
+
import { autopilotNeedsUser } from '../../channel/autopilot-needs-user';
|
|
4
5
|
import { styles } from './chat-bubble.styles';
|
|
5
6
|
import { AiChatBubbleTemplate } from './chat-bubble.template';
|
|
6
7
|
/**
|
|
@@ -60,6 +61,12 @@ let AiChatBubble = class AiChatBubble extends GenesisElement {
|
|
|
60
61
|
super(...arguments);
|
|
61
62
|
this.title = 'AI Assistant';
|
|
62
63
|
this.designSystemPrefix = 'rapid';
|
|
64
|
+
/**
|
|
65
|
+
* What the "needs you" badge on the orb says — its tooltip, and what a screen reader announces
|
|
66
|
+
* when it appears (GENC-1660 §4.10). The bubble cannot read the autopilot's own wording, so a host
|
|
67
|
+
* that renames or localises the autopilot sets this too.
|
|
68
|
+
*/
|
|
69
|
+
this.needsInputLabel = 'The assistant needs your input';
|
|
63
70
|
/** @internal */
|
|
64
71
|
this.dialogContent = [];
|
|
65
72
|
/** @internal */
|
|
@@ -80,6 +87,11 @@ let AiChatBubble = class AiChatBubble extends GenesisElement {
|
|
|
80
87
|
this.dialogOpen = false;
|
|
81
88
|
/** Whether the bubble orb is currently hovered. @internal */
|
|
82
89
|
this.hovered = false;
|
|
90
|
+
/**
|
|
91
|
+
* Whether the autopilot waits on the person (GENC-1660 §4.10): a hand-back the closed chat would
|
|
92
|
+
* otherwise hide. Shown as a badge on the orb; opening the chat shows what it waits on. @internal
|
|
93
|
+
*/
|
|
94
|
+
this.needsUser = false;
|
|
83
95
|
this.dragging = false;
|
|
84
96
|
this.dragTarget = null;
|
|
85
97
|
this.startMouseX = 0;
|
|
@@ -153,6 +165,7 @@ let AiChatBubble = class AiChatBubble extends GenesisElement {
|
|
|
153
165
|
this.dialogLeft = Math.max(VIEWPORT_EDGE_MARGIN, this.bubbleLeft - DIALOG_BUBBLE_HORIZONTAL_OFFSET);
|
|
154
166
|
this.dialogTop = Math.max(VIEWPORT_EDGE_MARGIN, this.bubbleTop - DIALOG_OPEN_TOP_OFFSET);
|
|
155
167
|
this.dialogOpen = true;
|
|
168
|
+
this.showWaitingIfBadged();
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
171
|
}
|
|
@@ -182,9 +195,12 @@ let AiChatBubble = class AiChatBubble extends GenesisElement {
|
|
|
182
195
|
this.hidden = false;
|
|
183
196
|
this.dialogOpen = true;
|
|
184
197
|
});
|
|
198
|
+
this.refreshNeedsUser();
|
|
199
|
+
const unsubNeedsUser = agenticActivityBus.subscribe('autopilot-needs-user', () => this.refreshNeedsUser());
|
|
185
200
|
this.unsubBus = () => {
|
|
186
201
|
unsubPopout();
|
|
187
202
|
unsubPopin();
|
|
203
|
+
unsubNeedsUser();
|
|
188
204
|
};
|
|
189
205
|
// Measure tooltip width once after first render. The bubble is visible on connect
|
|
190
206
|
// (dialogOpen starts false), so the element is in the DOM by the time rAF fires.
|
|
@@ -266,7 +282,30 @@ let AiChatBubble = class AiChatBubble extends GenesisElement {
|
|
|
266
282
|
this.resizeObserver = undefined;
|
|
267
283
|
}
|
|
268
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* The session of the assistant this bubble holds, when it can tell: the key the assistant
|
|
287
|
+
* publishes under, read from the assistant in the bubble's light DOM — whether or not the dialog
|
|
288
|
+
* (and with it the slot) is rendered, since the badge shows while it is not.
|
|
289
|
+
*/
|
|
290
|
+
assistantSessionKey() {
|
|
291
|
+
var _a;
|
|
292
|
+
const assistant = this.findAssistant([...this.children]);
|
|
293
|
+
return (_a = assistant === null || assistant === void 0 ? void 0 : assistant.stateKey) !== null && _a !== void 0 ? _a : undefined;
|
|
294
|
+
}
|
|
295
|
+
/** Opened from the badge: take the person to what is waiting on them (GENC-1660). */
|
|
296
|
+
showWaitingIfBadged() {
|
|
297
|
+
if (!this.needsUser)
|
|
298
|
+
return;
|
|
299
|
+
agenticActivityBus.publish('autopilot-show-waiting', {
|
|
300
|
+
sessionKey: this.assistantSessionKey(),
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
/** Badge only for this bubble's own assistant (GENC-1660). */
|
|
304
|
+
refreshNeedsUser() {
|
|
305
|
+
this.needsUser = autopilotNeedsUser(this.assistantSessionKey());
|
|
306
|
+
}
|
|
269
307
|
dialogContentChanged(_, next) {
|
|
308
|
+
this.refreshNeedsUser();
|
|
270
309
|
const assistant = this.findAssistant(next);
|
|
271
310
|
if (!assistant) {
|
|
272
311
|
this.removeCloseButton();
|
|
@@ -415,6 +454,9 @@ __decorate([
|
|
|
415
454
|
__decorate([
|
|
416
455
|
attr({ attribute: 'design-system-prefix' })
|
|
417
456
|
], AiChatBubble.prototype, "designSystemPrefix", void 0);
|
|
457
|
+
__decorate([
|
|
458
|
+
attr({ attribute: 'needs-input-label' })
|
|
459
|
+
], AiChatBubble.prototype, "needsInputLabel", void 0);
|
|
418
460
|
__decorate([
|
|
419
461
|
observable
|
|
420
462
|
], AiChatBubble.prototype, "dialogContent", void 0);
|
|
@@ -445,6 +487,9 @@ __decorate([
|
|
|
445
487
|
__decorate([
|
|
446
488
|
observable
|
|
447
489
|
], AiChatBubble.prototype, "hovered", void 0);
|
|
490
|
+
__decorate([
|
|
491
|
+
observable
|
|
492
|
+
], AiChatBubble.prototype, "needsUser", void 0);
|
|
448
493
|
AiChatBubble = __decorate([
|
|
449
494
|
customElement({
|
|
450
495
|
name: 'foundation-ai-chat-bubble',
|
|
@@ -99,6 +99,32 @@ export const styles = css `
|
|
|
99
99
|
translate: 0 0;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/* The autopilot waits on the person (GENC-1660): a dot on the orb, which opening the chat answers. */
|
|
103
|
+
.needs-you-badge {
|
|
104
|
+
position: absolute;
|
|
105
|
+
top: 2px;
|
|
106
|
+
right: 2px;
|
|
107
|
+
width: 14px;
|
|
108
|
+
height: 14px;
|
|
109
|
+
border: 2px solid var(--neutral-layer-1, #fff);
|
|
110
|
+
border-radius: 50%;
|
|
111
|
+
background: var(--accent-fill-rest, rgb(0 120 255));
|
|
112
|
+
pointer-events: none;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* The badge's live region: out of paint and flow, kept in the accessibility tree. */
|
|
116
|
+
.visually-hidden {
|
|
117
|
+
position: absolute;
|
|
118
|
+
width: 1px;
|
|
119
|
+
height: 1px;
|
|
120
|
+
margin: -1px;
|
|
121
|
+
padding: 0;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
clip-path: inset(50%);
|
|
124
|
+
white-space: nowrap;
|
|
125
|
+
border: 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
102
128
|
.pulse-ring {
|
|
103
129
|
position: absolute;
|
|
104
130
|
width: 62px;
|