@genesislcap/ai-assistant 15.26.0 → 15.27.0-agent-log-submit.3
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 +1014 -110
- package/dist/ai-assistant.d.ts +236 -99
- package/dist/chat-driver.cjs +460 -373
- package/dist/chat-driver.cjs.map +4 -4
- package/dist/chat-driver.mjs +460 -373
- package/dist/chat-driver.mjs.map +4 -4
- package/dist/custom-elements.json +1171 -248
- package/dist/dts/components/chat-driver/chat-driver.d.ts +28 -200
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/interaction-controller.d.ts +99 -0
- package/dist/dts/components/chat-driver/interaction-controller.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/turn-recorder.d.ts +191 -0
- package/dist/dts/components/chat-driver/turn-recorder.d.ts.map +1 -0
- package/dist/dts/components/settings-modal/settings-modal.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts +28 -0
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +180 -1
- 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 +19 -0
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +7 -1
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/persistence/session-persistence-provider.d.ts +5 -0
- package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +1 -0
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/dts/utils/format-message-timestamp.d.ts +77 -0
- package/dist/dts/utils/format-message-timestamp.d.ts.map +1 -0
- package/dist/dts/utils/resolve-debug-log-note.d.ts +25 -0
- package/dist/dts/utils/resolve-debug-log-note.d.ts.map +1 -0
- package/dist/dts/utils/resolve-preference-baseline.d.ts +18 -1
- package/dist/dts/utils/resolve-preference-baseline.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +68 -404
- package/dist/esm/components/chat-driver/interaction-controller.js +235 -0
- package/dist/esm/components/chat-driver/turn-recorder.js +206 -0
- package/dist/esm/components/settings-modal/settings-modal.js +1 -0
- package/dist/esm/components/settings-modal/settings-modal.styles.js +85 -5
- package/dist/esm/components/settings-modal/settings-modal.template.js +220 -25
- package/dist/esm/main/main.js +510 -23
- package/dist/esm/main/main.styles.js +75 -0
- package/dist/esm/main/main.template.js +43 -2
- package/dist/esm/state/ai-assistant-slice.js +5 -0
- package/dist/esm/utils/format-message-timestamp.js +126 -0
- package/dist/esm/utils/resolve-debug-log-note.js +37 -0
- package/dist/esm/utils/resolve-preference-baseline.js +54 -2
- package/package.json +16 -16
- package/sandbox/README.md +45 -2
- package/sandbox/sandbox.ts +95 -3
|
@@ -31,6 +31,54 @@ const toggleAnimationEnabled = (host, value, enabled) => {
|
|
|
31
31
|
host.setEnabledAnimations(next);
|
|
32
32
|
};
|
|
33
33
|
const readSwitchChecked = (event) => event.target.checked;
|
|
34
|
+
/**
|
|
35
|
+
* The timestamp modes, in the order they read as an increasing amount of chrome.
|
|
36
|
+
*
|
|
37
|
+
* Keyed by {@link TimestampDisplay} rather than listed as an array of `{ value, label }`,
|
|
38
|
+
* so adding a mode to the union is a compile error here instead of a picker that silently
|
|
39
|
+
* cannot reach it.
|
|
40
|
+
*/
|
|
41
|
+
const TIMESTAMP_MODE_LABELS = {
|
|
42
|
+
off: 'Off',
|
|
43
|
+
hover: 'On hover',
|
|
44
|
+
always: 'Always',
|
|
45
|
+
};
|
|
46
|
+
const TIMESTAMP_MODE_OPTIONS = Object.keys(TIMESTAMP_MODE_LABELS).map((value) => ({ value, label: TIMESTAMP_MODE_LABELS[value] }));
|
|
47
|
+
/**
|
|
48
|
+
* Three-way picker for {@link TimestampDisplay} (GENC-1257).
|
|
49
|
+
*
|
|
50
|
+
* The design system's segmented control rather than the `switch` every other row uses,
|
|
51
|
+
* because the setting genuinely has three states — and rather than hand-rolled buttons
|
|
52
|
+
* carrying `role="radio"`, because ARIA roles supply semantics but never behaviour:
|
|
53
|
+
* promising a radio group means owning roving `tabindex` and arrow-key navigation.
|
|
54
|
+
*
|
|
55
|
+
* `SegmentedControl extends FASTRadioGroup` (and `SegmentedItem extends FASTRadio`), so
|
|
56
|
+
* this IS the DS radio group — it inherits the whole keyboard pattern — just skinned as
|
|
57
|
+
* segments rather than dots, which is the right affordance for three short mode labels.
|
|
58
|
+
*
|
|
59
|
+
* The usual reason to avoid a DS control here does not apply. `RadioGroup.valueChanged`
|
|
60
|
+
* emits `change` whenever `value` is written — including the write this template's own
|
|
61
|
+
* binding performs on render, exactly the phantom-change footgun the DS switch has
|
|
62
|
+
* (GENC-1351 #1). It is harmless because the `timestampDisplay` setter guards on
|
|
63
|
+
* `preferenceUnchanged`, as every preference setter does, so a render-time echo returns early
|
|
64
|
+
* and never reaches the store or marks preferences user-changed.
|
|
65
|
+
*/
|
|
66
|
+
export const timestampModePickerTemplate = (segmentedControlTag, segmentedItemTag) => html `
|
|
67
|
+
<${segmentedControlTag}
|
|
68
|
+
part="toggle-timestamps"
|
|
69
|
+
aria-label="Show timestamps"
|
|
70
|
+
:value=${(x) => x.timestampDisplay}
|
|
71
|
+
@change=${(x, c) => {
|
|
72
|
+
x.timestampDisplay = c.event.target.value;
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
${repeat(() => TIMESTAMP_MODE_OPTIONS, html `
|
|
76
|
+
<${segmentedItemTag} part="timestamp-mode-option" value="${(option) => option.value}"
|
|
77
|
+
>${(option) => option.label}</${segmentedItemTag}
|
|
78
|
+
>
|
|
79
|
+
`)}
|
|
80
|
+
</${segmentedControlTag}>
|
|
81
|
+
`;
|
|
34
82
|
/** Inline animation picker — categories and options always visible (no multiselect popup). */
|
|
35
83
|
const animationsPickerTemplate = (switchTag) => html `
|
|
36
84
|
<div class="settings-animation-list" part="toggle-animations">
|
|
@@ -198,7 +246,7 @@ export const settingsUsageMetersTemplate = (progressTag, buttonTag, iconTag) =>
|
|
|
198
246
|
</div>
|
|
199
247
|
`)}
|
|
200
248
|
`;
|
|
201
|
-
const chatBotSettingsTemplate = (switchTag, buttonTag) => html `
|
|
249
|
+
const chatBotSettingsTemplate = (switchTag, buttonTag, segmentedControlTag, segmentedItemTag) => html `
|
|
202
250
|
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showToolCalls) != null; }, chatBotToggleRow('Show tool calls', "Display each tool the chatbot invokes — file reads, searches, edits and commands — inline as it works, so you can follow exactly what it's doing behind the scenes.", switchTag, 'toggle-tool-calls', (x) => x.showToolCalls, (x, c) => {
|
|
203
251
|
x.showToolCalls = readSwitchChecked(c.event);
|
|
204
252
|
}))}
|
|
@@ -211,6 +259,7 @@ const chatBotSettingsTemplate = (switchTag, buttonTag) => html `
|
|
|
211
259
|
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showAgentSwitchIndicator) != null; }, chatBotToggleRow('Show delegation', 'Show in the chat window when tasks are delegated to different agents.', switchTag, 'toggle-agent-switch', (x) => x.showAgentSwitchIndicator, (x, c) => {
|
|
212
260
|
x.showAgentSwitchIndicator = readSwitchChecked(c.event);
|
|
213
261
|
}))}
|
|
262
|
+
${settingsToggleRow('Show timestamps', 'Show when each message was sent, next to the sender name. Screen readers announce the full date in either visible mode.', 'toggle-timestamps', timestampModePickerTemplate(segmentedControlTag, segmentedItemTag))}
|
|
214
263
|
${when((x) => x.persistenceToggleable, chatBotToggleRow('Remember chat', 'Save this conversation so it can be restored after a page refresh. Turning this off deletes the saved copy.', switchTag, 'toggle-remember-chat', (x) => x.persistenceActive, (x, c) => {
|
|
215
264
|
x.setPersistenceEnabled(readSwitchChecked(c.event));
|
|
216
265
|
}))}
|
|
@@ -513,6 +562,171 @@ const costSessionHistoryTemplate = (iconTag, buttonTag) => html `
|
|
|
513
562
|
</div>
|
|
514
563
|
`)}
|
|
515
564
|
`;
|
|
565
|
+
/**
|
|
566
|
+
* The settings "Agent log" section: the Download / Send row, the always-present status
|
|
567
|
+
* live region, and the Send button's compose box. Exported (like
|
|
568
|
+
* `settingsUsageMetersTemplate`) so `agent-log-section.template.test.ts` can render it on
|
|
569
|
+
* an unconnected element and pin what the getters alone cannot show — that the `when`s,
|
|
570
|
+
* `?disabled`s and part tokens are actually wired to them.
|
|
571
|
+
*/
|
|
572
|
+
export const agentLogSectionTemplate = (buttonTag, textareaTag) => html `
|
|
573
|
+
${when((x) => x.settingsAgentLogSectionVisible, html `
|
|
574
|
+
<section class="settings-modal-section" part="settings-section-agent-log">
|
|
575
|
+
<div class="settings-modal-section-body">
|
|
576
|
+
<!--
|
|
577
|
+
Row and compose box share a wrapper so the box can drop straight under the
|
|
578
|
+
row (full width, no divider between them) while the row keeps its layout.
|
|
579
|
+
-->
|
|
580
|
+
<div class="agent-log-block" part="agent-log-block">
|
|
581
|
+
${settingsToggleRow('Agent log', (x) => x.debugLogRowDescription,
|
|
582
|
+
// The helper appends "-row", so this renders as
|
|
583
|
+
// part="download-agent-log-row agent-log-row": the original token stays
|
|
584
|
+
// for hosts already styling it, and `agent-log-row` names what the row
|
|
585
|
+
// now is — the container of both actions. Pinned in
|
|
586
|
+
// agent-log-section.template.test.ts.
|
|
587
|
+
'download-agent-log-row agent-log', html `
|
|
588
|
+
<div class="agent-log-actions" part="agent-log-actions">
|
|
589
|
+
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.allowDebugDownload) === true; }, html `
|
|
590
|
+
<${buttonTag}
|
|
591
|
+
part="download-button"
|
|
592
|
+
appearance="outline"
|
|
593
|
+
?disabled=${(x) => x.downloadingDebugLog}
|
|
594
|
+
@click=${(x) => x.downloadDebugLog()}
|
|
595
|
+
>
|
|
596
|
+
${when((x) => x.downloadingDebugLog, html `
|
|
597
|
+
<span
|
|
598
|
+
class="download-spinner"
|
|
599
|
+
part="download-spinner"
|
|
600
|
+
aria-hidden="true"
|
|
601
|
+
></span>
|
|
602
|
+
`)}
|
|
603
|
+
${(x) => (x.downloadingDebugLog ? 'Downloading…' : 'Download')}
|
|
604
|
+
</${buttonTag}>
|
|
605
|
+
`)}
|
|
606
|
+
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.debugLogSubmit) != null; }, html `
|
|
607
|
+
<${buttonTag}
|
|
608
|
+
part="submit-log-button"
|
|
609
|
+
appearance="outline"
|
|
610
|
+
?disabled=${(x) => x.submittingDebugLog || x.debugLogComposeOpen}
|
|
611
|
+
aria-expanded=${(x) => x.debugLogNoteConfig ? String(x.debugLogComposeOpen) : null}
|
|
612
|
+
@click=${(x) => x.openDebugLogCompose()}
|
|
613
|
+
>
|
|
614
|
+
${when((x) => x.submittingDebugLog && !x.debugLogComposeOpen, html `
|
|
615
|
+
<span
|
|
616
|
+
class="download-spinner"
|
|
617
|
+
part="download-spinner"
|
|
618
|
+
aria-hidden="true"
|
|
619
|
+
></span>
|
|
620
|
+
`)}
|
|
621
|
+
${(x) => x.debugLogSubmitButtonLabel}
|
|
622
|
+
</${buttonTag}>
|
|
623
|
+
`)}
|
|
624
|
+
</div>
|
|
625
|
+
`, 'row-centered')}
|
|
626
|
+
<!--
|
|
627
|
+
Present whenever Send is configured (not gated on the compose box) so a live region exists
|
|
628
|
+
BEFORE an outcome lands in it — one that appears together with its text is
|
|
629
|
+
not announced — and so a note-less (note: false) host, whose only visible change is
|
|
630
|
+
the button label, is announced too.
|
|
631
|
+
-->
|
|
632
|
+
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.debugLogSubmit) != null; }, html `
|
|
633
|
+
<span
|
|
634
|
+
class="visually-hidden"
|
|
635
|
+
part="agent-log-status"
|
|
636
|
+
role="status"
|
|
637
|
+
aria-live="polite"
|
|
638
|
+
>
|
|
639
|
+
${(x) => x.debugLogSubmitAnnouncement}
|
|
640
|
+
</span>
|
|
641
|
+
`)}
|
|
642
|
+
${when((x) => x.debugLogComposeOpen && x.debugLogNoteConfig !== null, html `
|
|
643
|
+
<!--
|
|
644
|
+
Keys are handled on the wrapper so they mean the same from every control:
|
|
645
|
+
Escape cancels the box (and does not reach the dialog, which would close
|
|
646
|
+
the whole modal and lose the note) whether focus is on the note, Cancel or
|
|
647
|
+
Send; Enter submits only from the note, and only when a submit would
|
|
648
|
+
actually go — otherwise the key keeps its default so it is not simply dead.
|
|
649
|
+
-->
|
|
650
|
+
<div
|
|
651
|
+
class="agent-log-compose"
|
|
652
|
+
part="agent-log-compose"
|
|
653
|
+
@keydown=${(x, c) => {
|
|
654
|
+
const e = c.event;
|
|
655
|
+
if (e.key === 'Escape') {
|
|
656
|
+
x.cancelDebugLogCompose();
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
if (e.key === 'Enter' &&
|
|
660
|
+
!e.shiftKey &&
|
|
661
|
+
e.target === x.debugLogNoteEl &&
|
|
662
|
+
!x.debugLogSendDisabled) {
|
|
663
|
+
void x.submitDebugLog();
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
return true;
|
|
667
|
+
}}
|
|
668
|
+
>
|
|
669
|
+
<${textareaTag}
|
|
670
|
+
${ref('debugLogNoteEl')}
|
|
671
|
+
class="agent-log-note"
|
|
672
|
+
part="agent-log-note"
|
|
673
|
+
rows="3"
|
|
674
|
+
resize="vertical"
|
|
675
|
+
aria-label=${(x) => x.debugLogNoteAriaLabel}
|
|
676
|
+
placeholder=${(x) => { var _a; return (_a = x.debugLogNoteConfig) === null || _a === void 0 ? void 0 : _a.placeholder; }}
|
|
677
|
+
maxlength=${(x) => { var _a; return (_a = x.debugLogNoteConfig) === null || _a === void 0 ? void 0 : _a.maxLength; }}
|
|
678
|
+
:value=${(x) => x.debugLogNote}
|
|
679
|
+
?disabled=${(x) => x.submittingDebugLog}
|
|
680
|
+
@input=${(x, c) => x.noteDebugLogInput(c.event.target.value)}
|
|
681
|
+
></${textareaTag}>
|
|
682
|
+
<div class="agent-log-compose-footer">
|
|
683
|
+
<!--
|
|
684
|
+
Visual hint only (aria-hidden): a live counter would be announced on
|
|
685
|
+
every keystroke, and an IDREF from the text-area cannot reach across
|
|
686
|
+
its shadow boundary. AT gets the cap from the note's static aria-label,
|
|
687
|
+
the remaining count near the cap and every outcome from the row's
|
|
688
|
+
status region.
|
|
689
|
+
-->
|
|
690
|
+
<span
|
|
691
|
+
class="agent-log-compose-hint ${(x) => x.debugLogSubmitResult === 'error' ? 'is-error' : ''}"
|
|
692
|
+
part="agent-log-compose-hint"
|
|
693
|
+
aria-hidden="true"
|
|
694
|
+
>
|
|
695
|
+
${(x) => x.debugLogComposeHint}
|
|
696
|
+
</span>
|
|
697
|
+
<div class="agent-log-actions">
|
|
698
|
+
<${buttonTag}
|
|
699
|
+
part="agent-log-cancel-button"
|
|
700
|
+
appearance="outline"
|
|
701
|
+
?disabled=${(x) => x.submittingDebugLog}
|
|
702
|
+
@click=${(x) => x.cancelDebugLogCompose()}
|
|
703
|
+
>
|
|
704
|
+
Cancel
|
|
705
|
+
</${buttonTag}>
|
|
706
|
+
<${buttonTag}
|
|
707
|
+
part="agent-log-send-button"
|
|
708
|
+
appearance="accent"
|
|
709
|
+
?disabled=${(x) => x.debugLogSendDisabled}
|
|
710
|
+
@click=${(x) => x.submitDebugLog()}
|
|
711
|
+
>
|
|
712
|
+
${when((x) => x.submittingDebugLog, html `
|
|
713
|
+
<span
|
|
714
|
+
class="download-spinner"
|
|
715
|
+
part="download-spinner"
|
|
716
|
+
aria-hidden="true"
|
|
717
|
+
></span>
|
|
718
|
+
`)}
|
|
719
|
+
${(x) => (x.submittingDebugLog ? 'Sending…' : x.debugLogSubmitLabel)}
|
|
720
|
+
</${buttonTag}>
|
|
721
|
+
</div>
|
|
722
|
+
</div>
|
|
723
|
+
</div>
|
|
724
|
+
`)}
|
|
725
|
+
</div>
|
|
726
|
+
</div>
|
|
727
|
+
</section>
|
|
728
|
+
`)}
|
|
729
|
+
`;
|
|
516
730
|
/**
|
|
517
731
|
* Modal shell for assistant settings — Configuration and Usage tabs, section slots for
|
|
518
732
|
* app-specific UI, and built-in chat-bot toggles.
|
|
@@ -523,9 +737,12 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
523
737
|
const switchTag = `${designSystemPrefix}-switch`;
|
|
524
738
|
const iconTag = `${designSystemPrefix}-icon`;
|
|
525
739
|
const progressTag = `${designSystemPrefix}-progress`;
|
|
740
|
+
const textareaTag = `${designSystemPrefix}-text-area`;
|
|
526
741
|
const tabsTag = `${designSystemPrefix}-tabs`;
|
|
527
742
|
const tabTag = `${designSystemPrefix}-tab`;
|
|
528
743
|
const tabPanelTag = `${designSystemPrefix}-tab-panel`;
|
|
744
|
+
const segmentedControlTag = `${designSystemPrefix}-segmented-control`;
|
|
745
|
+
const segmentedItemTag = `${designSystemPrefix}-segmented-item`;
|
|
529
746
|
const settingsTabPanel = html `
|
|
530
747
|
<${tabPanelTag}
|
|
531
748
|
slot="tabpanel"
|
|
@@ -551,29 +768,7 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
551
768
|
with the assistant's other sections rather than trailing the host's — where, now that the
|
|
552
769
|
host section carries no heading of its own, it read as one more of the host's settings.
|
|
553
770
|
-->
|
|
554
|
-
${
|
|
555
|
-
<section class="settings-modal-section" part="settings-section-agent-log">
|
|
556
|
-
<div class="settings-modal-section-body">
|
|
557
|
-
${settingsToggleRow('Download agent log', "Export a structured debug timeline of this session's agent activity.", 'download-agent-log', html `
|
|
558
|
-
<${buttonTag}
|
|
559
|
-
part="download-button"
|
|
560
|
-
appearance="outline"
|
|
561
|
-
?disabled=${(x) => x.downloadingDebugLog}
|
|
562
|
-
@click=${(x) => x.downloadDebugLog()}
|
|
563
|
-
>
|
|
564
|
-
${when((x) => x.downloadingDebugLog, html `
|
|
565
|
-
<span
|
|
566
|
-
class="download-spinner"
|
|
567
|
-
part="download-spinner"
|
|
568
|
-
aria-hidden="true"
|
|
569
|
-
></span>
|
|
570
|
-
`)}
|
|
571
|
-
${(x) => (x.downloadingDebugLog ? 'Downloading…' : 'Download')}
|
|
572
|
-
</${buttonTag}>
|
|
573
|
-
`, 'row-centered')}
|
|
574
|
-
</div>
|
|
575
|
-
</section>
|
|
576
|
-
`)}
|
|
771
|
+
${agentLogSectionTemplate(buttonTag, textareaTag)}
|
|
577
772
|
<!--
|
|
578
773
|
No heading here, by design. This section belongs to the host: only it knows what its
|
|
579
774
|
settings are called, so the assistant supplies neither text nor icon and the host titles
|
|
@@ -595,7 +790,7 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
595
790
|
</h3>
|
|
596
791
|
<p class="settings-modal-section-note">These options only control what you see in the chat window and do not control model behaviour.</p>
|
|
597
792
|
<div class="settings-modal-section-body">
|
|
598
|
-
${chatBotSettingsTemplate(switchTag, buttonTag)}
|
|
793
|
+
${chatBotSettingsTemplate(switchTag, buttonTag, segmentedControlTag, segmentedItemTag)}
|
|
599
794
|
</div>
|
|
600
795
|
</section>
|
|
601
796
|
</div>
|