@genesislcap/ai-assistant 15.60.0 → 15.62.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.
Files changed (134) hide show
  1. package/dist/ai-assistant.api.json +18231 -11171
  2. package/dist/ai-assistant.d.ts +1235 -9
  3. package/dist/chat-driver.cjs +658 -50
  4. package/dist/chat-driver.cjs.map +4 -4
  5. package/dist/chat-driver.mjs +657 -50
  6. package/dist/chat-driver.mjs.map +4 -4
  7. package/dist/custom-elements.json +4419 -377
  8. package/dist/dts/autopilot/autopilot-driver.d.ts +278 -0
  9. package/dist/dts/autopilot/autopilot-driver.d.ts.map +1 -0
  10. package/dist/dts/autopilot/autopilot-session.d.ts +163 -0
  11. package/dist/dts/autopilot/autopilot-session.d.ts.map +1 -0
  12. package/dist/dts/autopilot/autopilot-tools.d.ts +15 -0
  13. package/dist/dts/autopilot/autopilot-tools.d.ts.map +1 -0
  14. package/dist/dts/autopilot/decision-message.d.ts +62 -0
  15. package/dist/dts/autopilot/decision-message.d.ts.map +1 -0
  16. package/dist/dts/autopilot/hand-back/hand-back.controller.d.ts +69 -0
  17. package/dist/dts/autopilot/hand-back/hand-back.controller.d.ts.map +1 -0
  18. package/dist/dts/autopilot/hand-back/hand-back.d.ts +22 -0
  19. package/dist/dts/autopilot/hand-back/hand-back.d.ts.map +1 -0
  20. package/dist/dts/autopilot/index.d.ts +4 -0
  21. package/dist/dts/autopilot/index.d.ts.map +1 -0
  22. package/dist/dts/channel/ai-activity-bus.d.ts.map +1 -1
  23. package/dist/dts/channel/ai-activity-channel.d.ts +17 -0
  24. package/dist/dts/channel/ai-activity-channel.d.ts.map +1 -1
  25. package/dist/dts/channel/autopilot-needs-user.d.ts +8 -0
  26. package/dist/dts/channel/autopilot-needs-user.d.ts.map +1 -0
  27. package/dist/dts/components/agent-picker/agent-picker.constants.d.ts +10 -0
  28. package/dist/dts/components/agent-picker/agent-picker.constants.d.ts.map +1 -1
  29. package/dist/dts/components/agent-picker/agent-picker.d.ts +4 -0
  30. package/dist/dts/components/agent-picker/agent-picker.d.ts.map +1 -1
  31. package/dist/dts/components/agent-picker/agent-picker.template.d.ts.map +1 -1
  32. package/dist/dts/components/ai-driver/ai-driver.d.ts +34 -1
  33. package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
  34. package/dist/dts/components/ai-driver/base-driver-decorator.d.ts +3 -1
  35. package/dist/dts/components/ai-driver/base-driver-decorator.d.ts.map +1 -1
  36. package/dist/dts/components/chat-bubble/chat-bubble.d.ts +21 -0
  37. package/dist/dts/components/chat-bubble/chat-bubble.d.ts.map +1 -1
  38. package/dist/dts/components/chat-bubble/chat-bubble.styles.d.ts.map +1 -1
  39. package/dist/dts/components/chat-bubble/chat-bubble.template.d.ts.map +1 -1
  40. package/dist/dts/components/chat-driver/chat-driver.d.ts +5 -1
  41. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  42. package/dist/dts/components/chat-driver/interaction-controller.d.ts +27 -3
  43. package/dist/dts/components/chat-driver/interaction-controller.d.ts.map +1 -1
  44. package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts +10 -2
  45. package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts.map +1 -1
  46. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +9 -1
  47. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
  48. package/dist/dts/config/config.d.ts +183 -0
  49. package/dist/dts/config/config.d.ts.map +1 -1
  50. package/dist/dts/config/define-stateful-agent.d.ts +31 -1
  51. package/dist/dts/config/define-stateful-agent.d.ts.map +1 -1
  52. package/dist/dts/index.d.ts +7 -3
  53. package/dist/dts/index.d.ts.map +1 -1
  54. package/dist/dts/main/main.d.ts +128 -5
  55. package/dist/dts/main/main.d.ts.map +1 -1
  56. package/dist/dts/main/main.styles.d.ts.map +1 -1
  57. package/dist/dts/main/main.template.d.ts +2 -2
  58. package/dist/dts/main/main.template.d.ts.map +1 -1
  59. package/dist/dts/react.d.ts +10 -0
  60. package/dist/dts/state/debug-event-log.d.ts +1 -1
  61. package/dist/dts/state/debug-event-log.d.ts.map +1 -1
  62. package/dist/dts/state/decision-surface.d.ts +46 -0
  63. package/dist/dts/state/decision-surface.d.ts.map +1 -0
  64. package/dist/dts/state/interaction-context.d.ts +21 -1
  65. package/dist/dts/state/interaction-context.d.ts.map +1 -1
  66. package/dist/dts/state/interaction-registry.d.ts +63 -0
  67. package/dist/dts/state/interaction-registry.d.ts.map +1 -0
  68. package/dist/dts/state/persistence/session-persister.d.ts.map +1 -1
  69. package/dist/dts/state/persistence/session-snapshot.d.ts +21 -0
  70. package/dist/dts/state/persistence/session-snapshot.d.ts.map +1 -1
  71. package/dist/dts/state/run-steps.d.ts +66 -0
  72. package/dist/dts/state/run-steps.d.ts.map +1 -0
  73. package/dist/dts/types/ai-chat-widget.d.ts +7 -1
  74. package/dist/dts/types/ai-chat-widget.d.ts.map +1 -1
  75. package/dist/dts/types/interaction-context.d.ts +66 -1
  76. package/dist/dts/types/interaction-context.d.ts.map +1 -1
  77. package/dist/dts/types/interaction-interceptor.d.ts +60 -2
  78. package/dist/dts/types/interaction-interceptor.d.ts.map +1 -1
  79. package/dist/dts/types/interaction-surface.d.ts +195 -0
  80. package/dist/dts/types/interaction-surface.d.ts.map +1 -0
  81. package/dist/dts/utils/context-tokens.d.ts +6 -0
  82. package/dist/dts/utils/context-tokens.d.ts.map +1 -1
  83. package/dist/dts/utils/delegated-message.d.ts +13 -0
  84. package/dist/dts/utils/delegated-message.d.ts.map +1 -1
  85. package/dist/dts/utils/history-transform.d.ts.map +1 -1
  86. package/dist/dts/utils/preserved-user-messages.d.ts +21 -0
  87. package/dist/dts/utils/preserved-user-messages.d.ts.map +1 -0
  88. package/dist/esm/autopilot/autopilot-driver.js +906 -0
  89. package/dist/esm/autopilot/autopilot-session.js +449 -0
  90. package/dist/esm/autopilot/autopilot-tools.js +68 -0
  91. package/dist/esm/autopilot/decision-message.js +206 -0
  92. package/dist/esm/autopilot/hand-back/hand-back.controller.js +47 -0
  93. package/dist/esm/autopilot/hand-back/hand-back.js +129 -0
  94. package/dist/esm/autopilot/index.js +4 -0
  95. package/dist/esm/channel/ai-activity-bus.js +7 -0
  96. package/dist/esm/channel/autopilot-needs-user.js +26 -0
  97. package/dist/esm/components/agent-picker/agent-picker.constants.js +10 -0
  98. package/dist/esm/components/agent-picker/agent-picker.js +11 -1
  99. package/dist/esm/components/agent-picker/agent-picker.template.js +2 -4
  100. package/dist/esm/components/ai-driver/ai-driver.js +2 -0
  101. package/dist/esm/components/ai-driver/base-driver-decorator.js +8 -0
  102. package/dist/esm/components/chat-bubble/chat-bubble.js +45 -0
  103. package/dist/esm/components/chat-bubble/chat-bubble.styles.js +26 -0
  104. package/dist/esm/components/chat-bubble/chat-bubble.template.js +13 -0
  105. package/dist/esm/components/chat-driver/chat-driver.js +53 -18
  106. package/dist/esm/components/chat-driver/interaction-controller.js +297 -12
  107. package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.js +16 -2
  108. package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +28 -11
  109. package/dist/esm/config/define-stateful-agent.js +34 -29
  110. package/dist/esm/index.js +3 -0
  111. package/dist/esm/main/main.js +334 -15
  112. package/dist/esm/main/main.styles.js +126 -0
  113. package/dist/esm/main/main.template.js +116 -11
  114. package/dist/esm/state/debug-event-log.js +28 -1
  115. package/dist/esm/state/decision-surface.js +209 -0
  116. package/dist/esm/state/interaction-context.js +89 -1
  117. package/dist/esm/state/interaction-registry.js +33 -0
  118. package/dist/esm/state/persistence/session-persister.js +23 -11
  119. package/dist/esm/state/persistence/session-snapshot.js +1 -1
  120. package/dist/esm/state/run-steps.js +77 -0
  121. package/dist/esm/types/interaction-surface.js +1 -0
  122. package/dist/esm/utils/context-tokens.js +23 -9
  123. package/dist/esm/utils/delegated-message.js +15 -0
  124. package/dist/esm/utils/history-transform.js +18 -7
  125. package/dist/esm/utils/preserved-user-messages.js +31 -0
  126. package/dist/react.cjs +7 -0
  127. package/dist/react.mjs +6 -0
  128. package/docs/styling.md +1 -1
  129. package/package.json +17 -17
  130. package/sandbox/README.md +38 -2
  131. package/sandbox/autopilot.ts +358 -0
  132. package/sandbox/controls.ts +24 -1
  133. package/sandbox/fixtures.ts +2 -0
  134. package/sandbox/sandbox.ts +188 -1
@@ -27,9 +27,12 @@ import { showNotificationDialog } from '@genesislcap/foundation-notifications';
27
27
  import { avoidTreeShaking } from '@genesislcap/foundation-utils';
28
28
  import { customElement, DOM, html, GenesisElement, observable, volatile, attr, } from '@genesislcap/web-core';
29
29
  import DOMPurify from 'dompurify';
30
+ import { AutopilotDriver, autopilotOf, } from '../autopilot/autopilot-driver';
30
31
  import { agenticActivityBus } from '../channel/ai-activity-bus';
32
+ import { setAutopilotNeedsUser } from '../channel/autopilot-needs-user';
31
33
  import { AiActivityHalo } from '../components/activity-halo/activity-halo';
32
34
  import { AgentPicker } from '../components/agent-picker/agent-picker';
35
+ import { DEFAULT_ORCHESTRATION_DESCRIPTION, DEFAULT_ORCHESTRATION_LABEL, DEFAULT_ORCHESTRATION_MENU_LABEL, } from '../components/agent-picker/agent-picker.constants';
33
36
  import { AiChatBubble } from '../components/chat-bubble/chat-bubble';
34
37
  import { ChatDriver } from '../components/chat-driver/chat-driver';
35
38
  import { AiChatInteractionWrapper } from '../components/chat-interaction-wrapper/chat-interaction-wrapper';
@@ -44,6 +47,7 @@ import { AiWavesIndicator } from '../components/waves-indicator';
44
47
  import { AssistantAppSettingsProvider, } from '../provider/assistant-app-settings';
45
48
  import { recordMetaEvent, getMetaEvents, clearSession as clearMetaSession, DEBUG_LOG_README, } from '../state/debug-event-log';
46
49
  import { getOrCreateDriver, getDriver, getDriverAgentsKey, deleteDriver, } from '../state/driver-registry';
50
+ import { getInteractionRegistration } from '../state/interaction-registry';
47
51
  import { buildTimelineEntries } from '../state/persistence/build-timeline-entries';
48
52
  import { assembleDebugLog, withFreshMetaSnapshot } from '../state/persistence/diagnostics';
49
53
  import { deleteDiagnosticsCursorsFor, resetDiagnosticsCursorsFor, } from '../state/persistence/diagnostics-cursors';
@@ -487,6 +491,8 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
487
491
  // one session (bubble + popped-out panel) and must share cursors, or they'd
488
492
  // double-append the stream.
489
493
  this.showHalo = 'no';
494
+ /** Who holds the trailing pending interaction: `'user'` unless a claimant took it. @internal */
495
+ this.activeHeldBy = 'user';
490
496
  // ── Session lifecycle menu (GENC-1351 §5.5) ─────────────────────────────────
491
497
  /** Two-step confirm for the destructive Clear action; reset whenever the menu toggles. */
492
498
  this.confirmingClear = false;
@@ -1191,7 +1197,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1191
1197
  }
1192
1198
  /**
1193
1199
  * Name of the agent the user has pinned via the agent picker. `null` means
1194
- * automatic routing (Auto). Persisted on the session store, so it survives
1200
+ * orchestration: the assistant routes each message. Persisted on the session store, so it survives
1195
1201
  * pop-in/pop-out but resets on page refresh.
1196
1202
  *
1197
1203
  * Only changes on explicit user action (picker click or host's `setAgent`).
@@ -1610,10 +1616,10 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1610
1616
  this.showHalo = 'no';
1611
1617
  return;
1612
1618
  }
1613
- const last = this.messages[this.messages.length - 1];
1614
1619
  // Hide only while a pending interaction blocks on the user; a resolved
1615
- // interaction means the assistant is computing again (keep the halo).
1616
- if ((last === null || last === void 0 ? void 0 : last.interaction) && !last.interaction.resolved) {
1620
+ // interaction means the assistant is computing again (keep the halo), and so
1621
+ // does one a claimant such as the autopilot holds (GENC-1660 §4.10).
1622
+ if (this.waitingOnUser) {
1617
1623
  this.showHalo = 'no';
1618
1624
  }
1619
1625
  else if (this.showHalo !== 'orchestrating') {
@@ -1627,6 +1633,229 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1627
1633
  const last = this.messages[this.messages.length - 1];
1628
1634
  return !!(last === null || last === void 0 ? void 0 : last.interaction) && !last.interaction.resolved;
1629
1635
  }
1636
+ /**
1637
+ * True when the turn is parked on the person: a pending interaction they hold. One a claimant
1638
+ * holds (the autopilot deciding it) is the assistant still working, so the halo and the loading
1639
+ * indicator stay on (GENC-1660 §4.10).
1640
+ */
1641
+ get waitingOnUser() {
1642
+ return this.hasActivePendingInteraction && this.activeHeldBy === 'user';
1643
+ }
1644
+ /** The autopilot behind the slim bar and the banner, if there is one. */
1645
+ get autopilotHost() {
1646
+ var _a;
1647
+ return (_a = this.autopilotHostOverride) !== null && _a !== void 0 ? _a : autopilotOf(this.driver);
1648
+ }
1649
+ /** Whether the autopilot is available for the current flow, running or paused. @internal */
1650
+ get autopilotAvailable() {
1651
+ return !!this.autopilotState && this.autopilotState.mode !== 'unavailable';
1652
+ }
1653
+ /** Running and not waiting on an answer, so its control pauses it; otherwise it resumes. @internal */
1654
+ get autopilotCanPause() {
1655
+ var _a;
1656
+ return ((_a = this.autopilotState) === null || _a === void 0 ? void 0 : _a.mode) === 'running' && !this.autopilotSelfPaused;
1657
+ }
1658
+ /**
1659
+ * What clicking the toggle does, at the head of its tooltip. While it waits on a question it
1660
+ * handed back, Resume is not a plain resume: it takes that question back and decides it, with no
1661
+ * way to hand it back again. @internal
1662
+ */
1663
+ get autopilotToggleAction() {
1664
+ const copy = this.autopilotCopy;
1665
+ if (this.autopilotCanPause)
1666
+ return copy === null || copy === void 0 ? void 0 : copy.pauseLabel;
1667
+ return this.autopilotSelfPaused ? copy === null || copy === void 0 ? void 0 : copy.resumeDecideLabel : copy === null || copy === void 0 ? void 0 : copy.resumeLabel;
1668
+ }
1669
+ /**
1670
+ * The toggle's tooltip: what clicking does now, then what the autopilot does. The action is here
1671
+ * and not in its accessible name: the toggle is a toggle (`aria-pressed`), so its name stays
1672
+ * `toggleLabel` and its state is announced once, by the pressed state. @internal
1673
+ */
1674
+ get autopilotToggleTitle() {
1675
+ const copy = this.autopilotCopy;
1676
+ if (!copy)
1677
+ return undefined;
1678
+ return `${this.autopilotToggleAction}: ${copy.description}`;
1679
+ }
1680
+ /** Waiting on one answer it handed back. @internal */
1681
+ get autopilotSelfPaused() {
1682
+ var _a, _b;
1683
+ return ((_b = (_a = this.autopilotState) === null || _a === void 0 ? void 0 : _a.pause) === null || _b === void 0 ? void 0 : _b.scope) === 'this-interaction';
1684
+ }
1685
+ /**
1686
+ * The slim bar takes the composer's place while something is happening and the autopilot runs or
1687
+ * waits on one answer, and otherwise wherever the agent's own rules would hide the composer. Running
1688
+ * but idle — stopped at a wall such as the budget, or at the end of a turn it had nothing to
1689
+ * answer for — shows what those rules show, normally the composer, with the Autopilot pill on among
1690
+ * its pills. It never forces the composer open. A host that hides the built-in composer
1691
+ * (`chatConfig.ui.hideComposer`) has no pills to put it among, so there the slim bar stays up
1692
+ * whenever the autopilot is available, running or paused, idle or not: the person can always see
1693
+ * that it is on, and pause or resume it. @internal
1694
+ */
1695
+ get slimBarVisible() {
1696
+ const state = this.autopilotState;
1697
+ if (!state || state.mode === 'unavailable')
1698
+ return false;
1699
+ if (this.composerHiddenByConfig)
1700
+ return true;
1701
+ if ((state.mode === 'running' || this.autopilotSelfPaused) && state.working)
1702
+ return true;
1703
+ return this.busy && this.effectiveChatInputDuringExecution === 'hidden';
1704
+ }
1705
+ /**
1706
+ * What the autopilot's status region announces (GENC-1660 §4.10): the hand-back, with its reason,
1707
+ * while the autopilot waits on an answer; otherwise the slim bar's status while that shows;
1708
+ * otherwise nothing. The region stays mounted and only this text changes, so each change is
1709
+ * announced. @internal
1710
+ */
1711
+ get autopilotAnnouncement() {
1712
+ var _a, _b;
1713
+ const state = this.autopilotState;
1714
+ if (!state || state.mode === 'unavailable')
1715
+ return '';
1716
+ if (this.autopilotSelfPaused) {
1717
+ return [(_a = this.autopilotCopy) === null || _a === void 0 ? void 0 : _a.handBackLead, (_b = state.pause) === null || _b === void 0 ? void 0 : _b.reason].filter(Boolean).join(' ');
1718
+ }
1719
+ return this.slimBarVisible ? state.status : '';
1720
+ }
1721
+ /**
1722
+ * The Autopilot pill among the composer's pills: available, with the composer shown — paused, or
1723
+ * running with nothing happening. Where the host hides the composer, it is in the slim bar
1724
+ * instead (see `slimBarVisible`). @internal
1725
+ */
1726
+ get composerAutopilotVisible() {
1727
+ return this.autopilotAvailable && !this.slimBarVisible;
1728
+ }
1729
+ autopilotHostOverrideChanged() {
1730
+ if (this.$fastController.isConnected)
1731
+ this.wireAutopilot();
1732
+ }
1733
+ /** Follow the autopilot host's state, publishing the "needs you" signal for the bubble. */
1734
+ wireAutopilot() {
1735
+ var _a, _b;
1736
+ (_a = this.autopilotCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
1737
+ this.autopilotCleanup = undefined;
1738
+ const host = this.autopilotHost;
1739
+ const sessionKey = (_b = this.getStateKey()) !== null && _b !== void 0 ? _b : '';
1740
+ const read = () => {
1741
+ this.autopilotState = host === null || host === void 0 ? void 0 : host.state;
1742
+ this.autopilotCopy = host === null || host === void 0 ? void 0 : host.copy;
1743
+ setAutopilotNeedsUser(sessionKey, !!(host === null || host === void 0 ? void 0 : host.state.needsUser));
1744
+ };
1745
+ read();
1746
+ if (!host)
1747
+ return;
1748
+ const unsubscribeHost = host.subscribe(read);
1749
+ // Opened from the badge: bring what waits on the person into view.
1750
+ const unsubscribeShow = agenticActivityBus.subscribe('autopilot-show-waiting', (detail) => {
1751
+ if ((detail === null || detail === void 0 ? void 0 : detail.sessionKey) && detail.sessionKey !== sessionKey)
1752
+ return;
1753
+ this.showWaiting();
1754
+ });
1755
+ this.autopilotCleanup = () => {
1756
+ unsubscribeHost();
1757
+ unsubscribeShow();
1758
+ };
1759
+ }
1760
+ /**
1761
+ * Scroll to the pending interaction that waits on the person, and pulse it, so opening the chat
1762
+ * from the badge lands on it rather than wherever the transcript was left.
1763
+ */
1764
+ showWaiting() {
1765
+ const id = this.heldInteractionId;
1766
+ if (!id)
1767
+ return;
1768
+ this._userScrolledAway = false;
1769
+ this.scrollToBottom();
1770
+ this.attentionInteractionId = id;
1771
+ clearTimeout(this.attentionTimer);
1772
+ this.attentionTimer = setTimeout(() => {
1773
+ this.attentionInteractionId = undefined;
1774
+ }, FoundationAiAssistant_1.ATTENTION_MS);
1775
+ }
1776
+ /**
1777
+ * Follow who holds the trailing pending interaction. A claimant changes it on its context, which
1778
+ * notifies, so the view re-reads it on every notification rather than once (GENC-1660 §4.3).
1779
+ */
1780
+ syncActiveHold() {
1781
+ var _a;
1782
+ const row = this.activeInteractionRow[0];
1783
+ const pending = (row === null || row === void 0 ? void 0 : row.interaction) && !row.interaction.resolved ? row.interaction.interactionId : undefined;
1784
+ if (pending !== this.heldInteractionId) {
1785
+ (_a = this.heldCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
1786
+ this.heldCleanup = undefined;
1787
+ this.heldInteractionId = pending;
1788
+ const ctx = pending ? this.getInteractionContext(pending) : undefined;
1789
+ if (ctx)
1790
+ this.heldCleanup = ctx.subscribe(() => this.readActiveHold());
1791
+ }
1792
+ this.readActiveHold();
1793
+ }
1794
+ readActiveHold() {
1795
+ var _a;
1796
+ const id = this.heldInteractionId;
1797
+ const next = (id && ((_a = this.getInteractionContext(id)) === null || _a === void 0 ? void 0 : _a.heldBy)) || 'user';
1798
+ if (next === this.activeHeldBy)
1799
+ return;
1800
+ this.activeHeldBy = next;
1801
+ if (this.busy)
1802
+ this.syncLoadingIndicator();
1803
+ this.syncShowHalo();
1804
+ }
1805
+ /**
1806
+ * Whether a pending interaction's bubble is drawn at all. A widget registered with
1807
+ * `whileAutopilot: 'hidden'` asks for no chrome while a claimant holds it: the view renders
1808
+ * nothing, so an empty bubble would be left behind. @internal
1809
+ */
1810
+ isHiddenWhileHeld(m) {
1811
+ var _a;
1812
+ const interaction = m.interaction;
1813
+ if (!interaction || interaction.resolved)
1814
+ return false;
1815
+ if (interaction.interactionId !== this.heldInteractionId || this.activeHeldBy === 'user') {
1816
+ return false;
1817
+ }
1818
+ return ((_a = getInteractionRegistration(interaction.componentName)) === null || _a === void 0 ? void 0 : _a.whileAutopilot) === 'hidden';
1819
+ }
1820
+ /** The hand-back banner's reason, when this interaction is the one the autopilot handed back. @internal */
1821
+ handBackReasonFor(m) {
1822
+ var _a, _b;
1823
+ const pause = (_a = this.autopilotState) === null || _a === void 0 ? void 0 : _a.pause;
1824
+ if (!m.interaction || m.interaction.resolved)
1825
+ return undefined;
1826
+ if ((pause === null || pause === void 0 ? void 0 : pause.scope) !== 'this-interaction' ||
1827
+ pause.interactionId !== m.interaction.interactionId) {
1828
+ return undefined;
1829
+ }
1830
+ return (_b = pause.reason) !== null && _b !== void 0 ? _b : '';
1831
+ }
1832
+ /** Whether to mark a message as done in autopilot mode. @internal */
1833
+ showsDelegateMark(m) {
1834
+ var _a, _b, _c;
1835
+ if (((_b = (_a = this.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.delegatedMessages) === null || _b === void 0 ? void 0 : _b.marker) === 'none')
1836
+ return false;
1837
+ if (m.delegate)
1838
+ return true;
1839
+ const answeredBy = (_c = m.interaction) === null || _c === void 0 ? void 0 : _c.answeredBy;
1840
+ return !!answeredBy && answeredBy !== 'user';
1841
+ }
1842
+ /** The autopilot mark's tooltip. @internal */
1843
+ get delegateMarkLabel() {
1844
+ var _a, _b;
1845
+ return (_b = (_a = this.autopilotCopy) === null || _a === void 0 ? void 0 : _a.markLabel) !== null && _b !== void 0 ? _b : 'Done in autopilot mode';
1846
+ }
1847
+ handleAutopilotPause() {
1848
+ var _a;
1849
+ (_a = this.autopilotHost) === null || _a === void 0 ? void 0 : _a.pause();
1850
+ }
1851
+ handleAutopilotResume() {
1852
+ var _a;
1853
+ (_a = this.autopilotHost) === null || _a === void 0 ? void 0 : _a.resume();
1854
+ }
1855
+ handleKeepPaused(interactionId) {
1856
+ var _a;
1857
+ (_a = this.autopilotHost) === null || _a === void 0 ? void 0 : _a.keepPaused(interactionId);
1858
+ }
1630
1859
  showHaloChanged() {
1631
1860
  var _a;
1632
1861
  if (!((_a = this.enabledAnimations) === null || _a === void 0 ? void 0 : _a.includes('halo')))
@@ -1789,7 +2018,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1789
2018
  }
1790
2019
  }
1791
2020
  createDriver() {
1792
- var _a, _b, _c;
2021
+ var _a, _b, _c, _d;
1793
2022
  this.warnUnreachableStatefulAgents();
1794
2023
  const agent = (_a = this.chatConfig.agent) !== null && _a !== void 0 ? _a : {};
1795
2024
  const { agents } = this;
@@ -1807,7 +2036,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1807
2036
  // this via `agent-changed` once installAgent fires on first sendMessage.
1808
2037
  this.activeAgent = agents[0];
1809
2038
  }
1810
- return new OrchestratingDriver(this.providerRegistry, agents, {
2039
+ const orchestrator = new OrchestratingDriver(this.providerRegistry, agents, {
1811
2040
  sessionKey: (_b = this.getStateKey()) !== null && _b !== void 0 ? _b : '',
1812
2041
  maxHandoffs: agent.maxHandoffs,
1813
2042
  classifierHistoryLength: agent.classifierHistoryLength,
@@ -1819,12 +2048,22 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1819
2048
  budgetExhaustedMessage: this.transcriptBudgetExhaustedMessage,
1820
2049
  aiServiceErrorMessages: this.aiServiceErrorMessages,
1821
2050
  });
2051
+ // The autopilot is installed outermost, and only when some agent declares one (GENC-1660).
2052
+ // The element keeps reading it as an `AutopilotHost`; nothing about it travels through
2053
+ // `AiDriver`.
2054
+ if (!agents.some((a) => a.autopilot))
2055
+ return orchestrator;
2056
+ return new AutopilotDriver(orchestrator, {
2057
+ agents,
2058
+ providerRegistry: this.providerRegistry,
2059
+ sessionKey: (_c = this.getStateKey()) !== null && _c !== void 0 ? _c : '',
2060
+ });
1822
2061
  }
1823
2062
  return new ChatDriver(this.providerRegistry, {
1824
2063
  maxToolIterations: agent.maxToolIterations,
1825
2064
  maxFoldOperations: agent.maxFoldOperations,
1826
2065
  maxTurnSnapshots: agent.maxTurnSnapshots,
1827
- sessionKey: (_c = this.getStateKey()) !== null && _c !== void 0 ? _c : '',
2066
+ sessionKey: (_d = this.getStateKey()) !== null && _d !== void 0 ? _d : '',
1828
2067
  activityBus: agenticActivityBus,
1829
2068
  budgetExhaustedMessage: this.transcriptBudgetExhaustedMessage,
1830
2069
  aiServiceErrorMessages: this.aiServiceErrorMessages,
@@ -1877,6 +2116,9 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1877
2116
  (_b = this.persister()) === null || _b === void 0 ? void 0 : _b.scheduleDiagnostics();
1878
2117
  };
1879
2118
  driver.addEventListener('external-cost-recorded', onExternalCostRecorded);
2119
+ // A long action's finished step changes no message, so autosave would miss it (GENC-1660).
2120
+ const onCheckpointSaved = () => { var _a; return (_a = this.persister()) === null || _a === void 0 ? void 0 : _a.scheduleSave(); };
2121
+ driver.addEventListener('checkpoint-saved', onCheckpointSaved);
1880
2122
  // Re-seed the rendered list from the driver's current history. `wireDriver`
1881
2123
  // runs on (re)connect, popin, and when adopting a sibling's driver
1882
2124
  // (GENC-1388); in those cases `messages` would otherwise stay stale until the
@@ -1940,6 +2182,14 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1940
2182
  (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.removeInputOverride({ id: interactionId });
1941
2183
  }
1942
2184
  };
2185
+ // An interaction answered by any route — including a controller's `ctx.resolve`, which never
2186
+ // reaches `handleInteractionCompleted` — means the turn is about to compute again (GENC-1660).
2187
+ // Not on a timeout or a stop, which carry no `answeredBy`: the turn may be ending.
2188
+ const onInteractionSettled = (e) => {
2189
+ var _a;
2190
+ if ((_a = e.detail) === null || _a === void 0 ? void 0 : _a.answeredBy)
2191
+ this.startLoadingTimer();
2192
+ };
1943
2193
  const onProviderChanged = (e) => {
1944
2194
  const { name } = e.detail;
1945
2195
  this.activeProviderName = name;
@@ -1952,15 +2202,18 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1952
2202
  driver.addEventListener('sub-agent-stop', onSubAgentStop);
1953
2203
  driver.addEventListener('interaction-start', onInteractionStart);
1954
2204
  driver.addEventListener('interaction-stop', onInteractionStop);
2205
+ driver.addEventListener('interaction-settled', onInteractionSettled);
1955
2206
  driver.addEventListener('provider-changed', onProviderChanged);
1956
2207
  const cleanups = [
1957
2208
  () => driver.removeEventListener('history-updated', onHistoryUpdated),
1958
2209
  () => driver.removeEventListener('external-cost-recorded', onExternalCostRecorded),
2210
+ () => driver.removeEventListener('checkpoint-saved', onCheckpointSaved),
1959
2211
  () => driver.removeEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated),
1960
2212
  () => driver.removeEventListener('sub-agent-start', onSubAgentStart),
1961
2213
  () => driver.removeEventListener('sub-agent-stop', onSubAgentStop),
1962
2214
  () => driver.removeEventListener('interaction-start', onInteractionStart),
1963
2215
  () => driver.removeEventListener('interaction-stop', onInteractionStop),
2216
+ () => driver.removeEventListener('interaction-settled', onInteractionSettled),
1964
2217
  () => driver.removeEventListener('provider-changed', onProviderChanged),
1965
2218
  ];
1966
2219
  // Wired on the driver this element holds, whatever it is, rather than on an orchestrator found
@@ -2036,15 +2289,22 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
2036
2289
  for (const fn of cleanups)
2037
2290
  fn();
2038
2291
  };
2292
+ this.wireAutopilot();
2293
+ this.syncActiveHold();
2039
2294
  }
2040
2295
  /**
2041
2296
  * Removes event listeners attached by `wireDriver`. Does not destroy
2042
2297
  * the driver or remove it from the registry.
2043
2298
  */
2044
2299
  unwireDriver() {
2045
- var _a;
2300
+ var _a, _b, _c;
2046
2301
  (_a = this.driverCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
2047
2302
  this.driverCleanup = undefined;
2303
+ (_b = this.autopilotCleanup) === null || _b === void 0 ? void 0 : _b.call(this);
2304
+ this.autopilotCleanup = undefined;
2305
+ (_c = this.heldCleanup) === null || _c === void 0 ? void 0 : _c.call(this);
2306
+ this.heldCleanup = undefined;
2307
+ this.heldInteractionId = undefined;
2048
2308
  }
2049
2309
  /**
2050
2310
  * Tear down the session's currently-wired driver (GENC-1351): unwire this view, drop
@@ -2054,8 +2314,11 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
2054
2314
  * `this.driver`, so the instance is still readable here for disposal.
2055
2315
  */
2056
2316
  teardownDriver(key) {
2317
+ var _a;
2057
2318
  const old = this.driver;
2058
2319
  this.unwireDriver();
2320
+ // Its autopilot goes with it, so nothing waits on the person any more (GENC-1660).
2321
+ setAutopilotNeedsUser((_a = key !== null && key !== void 0 ? key : this.getStateKey()) !== null && _a !== void 0 ? _a : '', false);
2059
2322
  if (key)
2060
2323
  deleteDriver(key);
2061
2324
  if (old && 'dispose' in old && typeof old.dispose === 'function') {
@@ -2505,6 +2768,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
2505
2768
  // individual step gets a fresh window before the spinner appears.
2506
2769
  // If the last message is a blocking interaction, stop the timer — the AI is
2507
2770
  // waiting for the user, not computing.
2771
+ this.syncActiveHold();
2508
2772
  if (this.busy)
2509
2773
  this.syncLoadingIndicator();
2510
2774
  this.syncShowHalo();
@@ -2639,7 +2903,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
2639
2903
  * resume (e.g. while it works out the next planning question after the user answers a widget).
2640
2904
  */
2641
2905
  syncLoadingIndicator() {
2642
- if (this.hasActivePendingInteraction)
2906
+ if (this.waitingOnUser)
2643
2907
  this.stopLoadingTimer();
2644
2908
  else
2645
2909
  this.startLoadingTimer();
@@ -2655,6 +2919,17 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
2655
2919
  agenticActivityBus.publish('chat-popin', undefined);
2656
2920
  }
2657
2921
  }
2922
+ /**
2923
+ * The key this assistant's session is published under (on the activity bus, in the debug log,
2924
+ * in storage): the wired session's once one is active, else the one its attributes imply. Not
2925
+ * always the `session-key` attribute, which can run ahead of a deferred switch and is absent when
2926
+ * the key is derived from `id` and the header title. `undefined` when it has no identity.
2927
+ *
2928
+ * @beta
2929
+ */
2930
+ get stateKey() {
2931
+ return this.getStateKey();
2932
+ }
2658
2933
  /** Returns a cache key for this instance, or undefined if the component has no identity. */
2659
2934
  getStateKey() {
2660
2935
  var _a;
@@ -3459,7 +3734,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
3459
3734
  ? `${this.pinnedAgentName} — ${this.pinnedAgentHint}`
3460
3735
  : this.pinnedAgentName;
3461
3736
  }
3462
- return 'Attempts to route messages to the correct available agent. Click to manually pin an agent.';
3737
+ return `${this.orchestrationMenuLabel}: ${this.orchestrationDescription} Click to pin an agent instead.`;
3463
3738
  }
3464
3739
  /**
3465
3740
  * Tint applied to the pin icon when an agent is pinned. Picked from the
@@ -3479,14 +3754,32 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
3479
3754
  return pinColourAt((_c = (_b = this.agents) === null || _b === void 0 ? void 0 : _b.findIndex((a) => a.name === this.pinnedAgentName)) !== null && _c !== void 0 ? _c : -1);
3480
3755
  }
3481
3756
  /**
3482
- * Label beside the composer's agent glyph: `AUTO` while the orchestrator is
3483
- * routing, otherwise the pinned agent's name. The name is NOT shortened here —
3757
+ * Label beside the composer's agent glyph: the orchestration label (`Orchestration` unless the
3758
+ * host renames it) while the orchestrator is routing, otherwise the pinned agent's name. The name is NOT shortened here —
3484
3759
  * the button truncates with an ellipsis in CSS, so the full name stays
3485
3760
  * available to a screen reader and to the `title` tooltip.
3486
3761
  */
3487
3762
  get agentButtonLabel() {
3488
3763
  var _a;
3489
- return (_a = this.pinnedAgentName) !== null && _a !== void 0 ? _a : 'AUTO';
3764
+ return (_a = this.pinnedAgentName) !== null && _a !== void 0 ? _a : this.orchestrationLabel;
3765
+ }
3766
+ /**
3767
+ * The picker's name for orchestration, from `chatConfig.picker.orchestrationLabel`. Not "Auto":
3768
+ * other tools use that for picking a model tier, and here it is the agent that is chosen.
3769
+ */
3770
+ get orchestrationLabel() {
3771
+ var _a;
3772
+ return ((_a = this.chatConfig.picker) === null || _a === void 0 ? void 0 : _a.orchestrationLabel) || DEFAULT_ORCHESTRATION_LABEL;
3773
+ }
3774
+ /** The same choice's name in the picker menu, from `chatConfig.picker.orchestrationMenuLabel`. */
3775
+ get orchestrationMenuLabel() {
3776
+ var _a;
3777
+ return ((_a = this.chatConfig.picker) === null || _a === void 0 ? void 0 : _a.orchestrationMenuLabel) || DEFAULT_ORCHESTRATION_MENU_LABEL;
3778
+ }
3779
+ /** What orchestration does, from `chatConfig.picker.orchestrationDescription`. */
3780
+ get orchestrationDescription() {
3781
+ var _a;
3782
+ return ((_a = this.chatConfig.picker) === null || _a === void 0 ? void 0 : _a.orchestrationDescription) || DEFAULT_ORCHESTRATION_DESCRIPTION;
3490
3783
  }
3491
3784
  /**
3492
3785
  * Placeholder shown in the chat input. Substitutes the pinned agent's name
@@ -4141,12 +4434,15 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
4141
4434
  * finishes first). Guarded so a second click is a no-op.
4142
4435
  */
4143
4436
  handleStopClick() {
4144
- var _a, _b;
4437
+ var _a, _b, _c, _d;
4145
4438
  // Only valid mid-turn; once `cancelling`, a second click is a no-op.
4146
4439
  if (this.state !== 'loading')
4147
4440
  return;
4148
4441
  this.state = 'cancelling';
4149
- (_b = (_a = this.driver) === null || _a === void 0 ? void 0 : _a.cancel) === null || _b === void 0 ? void 0 : _b.call(_a);
4442
+ // Stop also pauses the autopilot, so the slim bar does not read "running" over a stopped turn.
4443
+ if (((_a = this.autopilotState) === null || _a === void 0 ? void 0 : _a.mode) === 'running')
4444
+ (_b = this.autopilotHost) === null || _b === void 0 ? void 0 : _b.pause();
4445
+ (_d = (_c = this.driver) === null || _c === void 0 ? void 0 : _c.cancel) === null || _d === void 0 ? void 0 : _d.call(_c);
4150
4446
  }
4151
4447
  handleSuggestionClick(suggestion) {
4152
4448
  // Belt-and-braces with the template gate that hides the chips while blocked:
@@ -4463,6 +4759,8 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
4463
4759
  FoundationAiAssistant.SCROLL_BOTTOM_THRESHOLD_PX = 50;
4464
4760
  /** Context-usage percentage that fires the one-shot `context.threshold-crossed` event. */
4465
4761
  FoundationAiAssistant.CONTEXT_USAGE_WARN_PERCENT = 80;
4762
+ /** How long a pointed-out interaction pulses for. */
4763
+ FoundationAiAssistant.ATTENTION_MS = 2400;
4466
4764
  FoundationAiAssistant.DEFAULT_LOADING_DELAY_S = 0;
4467
4765
  FoundationAiAssistant.DEFAULT_SUGGESTION_COUNT = 3;
4468
4766
  FoundationAiAssistant.MS_PER_SECOND = 1000;
@@ -4577,6 +4875,27 @@ __decorate([
4577
4875
  __decorate([
4578
4876
  observable
4579
4877
  ], FoundationAiAssistant.prototype, "showHalo", void 0);
4878
+ __decorate([
4879
+ observable
4880
+ ], FoundationAiAssistant.prototype, "autopilotHostOverride", void 0);
4881
+ __decorate([
4882
+ observable
4883
+ ], FoundationAiAssistant.prototype, "autopilotState", void 0);
4884
+ __decorate([
4885
+ observable
4886
+ ], FoundationAiAssistant.prototype, "autopilotCopy", void 0);
4887
+ __decorate([
4888
+ observable
4889
+ ], FoundationAiAssistant.prototype, "attentionInteractionId", void 0);
4890
+ __decorate([
4891
+ observable
4892
+ ], FoundationAiAssistant.prototype, "activeHeldBy", void 0);
4893
+ __decorate([
4894
+ volatile
4895
+ ], FoundationAiAssistant.prototype, "slimBarVisible", null);
4896
+ __decorate([
4897
+ volatile
4898
+ ], FoundationAiAssistant.prototype, "autopilotAnnouncement", null);
4580
4899
  __decorate([
4581
4900
  volatile
4582
4901
  ], FoundationAiAssistant.prototype, "visibleMessages", null);