@newheap/platform-ai-chat 0.3.0 → 0.5.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/fesm2022/newheap-platform-ai-chat.mjs +231 -19
- package/fesm2022/newheap-platform-ai-chat.mjs.map +1 -1
- package/i18n/en.json +15 -1
- package/i18n/nl.json +15 -1
- package/index.d.ts +56 -4
- package/package.json +1 -1
|
@@ -123,7 +123,8 @@ var en = {
|
|
|
123
123
|
assistant: "Assistant",
|
|
124
124
|
tool: "Tool",
|
|
125
125
|
working: "The assistant is working",
|
|
126
|
-
loading: "Loading conversation"
|
|
126
|
+
loading: "Loading conversation",
|
|
127
|
+
elapsed: "{{seconds}}s"
|
|
127
128
|
},
|
|
128
129
|
composer: {
|
|
129
130
|
label: "Message",
|
|
@@ -154,6 +155,16 @@ var en = {
|
|
|
154
155
|
rejected: "Rejected"
|
|
155
156
|
}
|
|
156
157
|
},
|
|
158
|
+
"tool-group": {
|
|
159
|
+
running: "Calling {{name}}…",
|
|
160
|
+
"awaiting-approval": "Waiting for approval: {{name}}",
|
|
161
|
+
"used-one": "Used 1 tool",
|
|
162
|
+
"used-many": "Used {{count}} tools",
|
|
163
|
+
progress: "{{finished}} of {{total}} done",
|
|
164
|
+
failed: "{{count}} failed",
|
|
165
|
+
"show-calls": "Show tool calls",
|
|
166
|
+
"hide-calls": "Hide tool calls"
|
|
167
|
+
},
|
|
157
168
|
approval: {
|
|
158
169
|
title: "Approval required",
|
|
159
170
|
"fallback-summary": "Review this action before it runs.",
|
|
@@ -233,6 +244,9 @@ var en = {
|
|
|
233
244
|
"assistant-turn-failed": "The assistant could not finish the answer. Try again.",
|
|
234
245
|
"assistant-turn-timeout": "The answer took too long and was stopped. Try again or ask a narrower question."
|
|
235
246
|
},
|
|
247
|
+
notices: {
|
|
248
|
+
"no-answer": "The assistant finished without an answer. Try again or rephrase your question."
|
|
249
|
+
},
|
|
236
250
|
preferences: {
|
|
237
251
|
title: "Your preferences",
|
|
238
252
|
description: "Choose how the assistant answers you. Preferences change the style only; they never change what the assistant may do or which actions need your approval.",
|
|
@@ -508,7 +522,8 @@ var nl = {
|
|
|
508
522
|
assistant: "Assistent",
|
|
509
523
|
tool: "Tool",
|
|
510
524
|
working: "De assistent is bezig",
|
|
511
|
-
loading: "Gesprek laden"
|
|
525
|
+
loading: "Gesprek laden",
|
|
526
|
+
elapsed: "{{seconds}} s"
|
|
512
527
|
},
|
|
513
528
|
composer: {
|
|
514
529
|
label: "Bericht",
|
|
@@ -539,6 +554,16 @@ var nl = {
|
|
|
539
554
|
rejected: "Afgewezen"
|
|
540
555
|
}
|
|
541
556
|
},
|
|
557
|
+
"tool-group": {
|
|
558
|
+
running: "Roept {{name}} aan…",
|
|
559
|
+
"awaiting-approval": "Wacht op goedkeuring: {{name}}",
|
|
560
|
+
"used-one": "1 tool gebruikt",
|
|
561
|
+
"used-many": "{{count}} tools gebruikt",
|
|
562
|
+
progress: "{{finished}} van {{total}} klaar",
|
|
563
|
+
failed: "{{count}} mislukt",
|
|
564
|
+
"show-calls": "Tool-aanroepen tonen",
|
|
565
|
+
"hide-calls": "Tool-aanroepen verbergen"
|
|
566
|
+
},
|
|
542
567
|
approval: {
|
|
543
568
|
title: "Goedkeuring nodig",
|
|
544
569
|
"fallback-summary": "Controleer deze actie voordat ze wordt uitgevoerd.",
|
|
@@ -618,6 +643,9 @@ var nl = {
|
|
|
618
643
|
"assistant-turn-failed": "De assistent kon het antwoord niet afmaken. Probeer het opnieuw.",
|
|
619
644
|
"assistant-turn-timeout": "Het antwoord duurde te lang en is gestopt. Probeer het opnieuw of stel een gerichtere vraag."
|
|
620
645
|
},
|
|
646
|
+
notices: {
|
|
647
|
+
"no-answer": "De assistent is klaar zonder antwoord. Probeer het opnieuw of stel je vraag anders."
|
|
648
|
+
},
|
|
621
649
|
preferences: {
|
|
622
650
|
title: "Je voorkeuren",
|
|
623
651
|
description: "Kies hoe de assistent je antwoordt. Voorkeuren veranderen alleen de stijl; ze veranderen nooit wat de assistent mag of welke acties je goedkeuring nodig hebben.",
|
|
@@ -1463,6 +1491,22 @@ function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
|
|
|
1463
1491
|
}
|
|
1464
1492
|
return updated;
|
|
1465
1493
|
}
|
|
1494
|
+
/**
|
|
1495
|
+
* True when an assistant message after the latest user message contains non-blank text,
|
|
1496
|
+
* so the latest turn produced a visible answer. Tool calls and approvals alone do not count.
|
|
1497
|
+
*/
|
|
1498
|
+
function nhAssistantLatestTurnHasText(conversation) {
|
|
1499
|
+
for (let position = conversation.messages.length - 1; position >= 0; position--) {
|
|
1500
|
+
const message = conversation.messages[position];
|
|
1501
|
+
if (message.role === 'user') {
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
if (message.role === 'assistant' && message.parts.some(part => part.type === 'text' && part.text.trim().length > 0)) {
|
|
1505
|
+
return true;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return false;
|
|
1509
|
+
}
|
|
1466
1510
|
function conversationStatusFor(status) {
|
|
1467
1511
|
switch (status) {
|
|
1468
1512
|
case 'completed':
|
|
@@ -1718,6 +1762,8 @@ function validId(value) {
|
|
|
1718
1762
|
return typeof value === 'string' && value.length > 0 && value.length <= 256 ? value : null;
|
|
1719
1763
|
}
|
|
1720
1764
|
|
|
1765
|
+
/** Notice code for a completed turn that produced no answer text and no server code. */
|
|
1766
|
+
const NH_ASSISTANT_NO_ANSWER_NOTICE_CODE = 'assistant-no-answer';
|
|
1721
1767
|
const conversationPageSize = 50;
|
|
1722
1768
|
const cancelGracePeriodMs = 5_000;
|
|
1723
1769
|
/**
|
|
@@ -1743,6 +1789,7 @@ class NhAssistantStore {
|
|
|
1743
1789
|
this.streamingState = signal(false, ...(ngDevMode ? [{ debugName: "streamingState" }] : []));
|
|
1744
1790
|
this.decidingState = signal(false, ...(ngDevMode ? [{ debugName: "decidingState" }] : []));
|
|
1745
1791
|
this.errorState = signal(null, ...(ngDevMode ? [{ debugName: "errorState" }] : []));
|
|
1792
|
+
this.noticeState = signal(null, ...(ngDevMode ? [{ debugName: "noticeState" }] : []));
|
|
1746
1793
|
this.lastUsageState = signal(null, ...(ngDevMode ? [{ debugName: "lastUsageState" }] : []));
|
|
1747
1794
|
this.restoredDraftState = signal(null, ...(ngDevMode ? [{ debugName: "restoredDraftState" }] : []));
|
|
1748
1795
|
this.pageContextState = signal(null, ...(ngDevMode ? [{ debugName: "pageContextState" }] : []));
|
|
@@ -1769,6 +1816,8 @@ class NhAssistantStore {
|
|
|
1769
1816
|
this.pendingApproval = computed(() => this.activeConversationState()?.pendingApproval ?? null, ...(ngDevMode ? [{ debugName: "pendingApproval" }] : []));
|
|
1770
1817
|
this.deciding = this.decidingState.asReadonly();
|
|
1771
1818
|
this.error = this.errorState.asReadonly();
|
|
1819
|
+
/** Non-blocking remark about the latest completed turn; shown only while no error is shown. */
|
|
1820
|
+
this.notice = this.noticeState.asReadonly();
|
|
1772
1821
|
this.lastUsage = this.lastUsageState.asReadonly();
|
|
1773
1822
|
/** Text of a message the server did not accept, so the composer can offer it again. */
|
|
1774
1823
|
this.restoredDraft = this.restoredDraftState.asReadonly();
|
|
@@ -1812,6 +1861,7 @@ class NhAssistantStore {
|
|
|
1812
1861
|
this.pageContextExcludedState.set(false);
|
|
1813
1862
|
this.restoredDraftState.set(null);
|
|
1814
1863
|
this.errorState.set(null);
|
|
1864
|
+
this.noticeState.set(null);
|
|
1815
1865
|
this.lastUsageState.set(null);
|
|
1816
1866
|
this.restorePanelOpenState.set(false);
|
|
1817
1867
|
this.uiState.deactivate();
|
|
@@ -1836,6 +1886,7 @@ class NhAssistantStore {
|
|
|
1836
1886
|
this.pageContextExcludedState.set(false);
|
|
1837
1887
|
this.restoredDraftState.set(null);
|
|
1838
1888
|
this.errorState.set(null);
|
|
1889
|
+
this.noticeState.set(null);
|
|
1839
1890
|
this.lastUsageState.set(null);
|
|
1840
1891
|
this.selectedAgentIdState.set(restored.state.agentId);
|
|
1841
1892
|
this.restorePanelOpenState.set(restored.state.panelOpen);
|
|
@@ -1908,6 +1959,7 @@ class NhAssistantStore {
|
|
|
1908
1959
|
this.activeConversationState.set(null);
|
|
1909
1960
|
this.uiState.update({ conversationId: null });
|
|
1910
1961
|
this.errorState.set(null);
|
|
1962
|
+
this.noticeState.set(null);
|
|
1911
1963
|
this.lastUsageState.set(null);
|
|
1912
1964
|
}
|
|
1913
1965
|
async openConversation(conversationId) {
|
|
@@ -1920,6 +1972,7 @@ class NhAssistantStore {
|
|
|
1920
1972
|
const revision = this.accountRevision;
|
|
1921
1973
|
this.conversationLoadingState.set(true);
|
|
1922
1974
|
this.errorState.set(null);
|
|
1975
|
+
this.noticeState.set(null);
|
|
1923
1976
|
try {
|
|
1924
1977
|
const conversation = await firstValueFrom(this.api.getConversation(conversationId));
|
|
1925
1978
|
if (revision !== this.accountRevision) {
|
|
@@ -1964,6 +2017,7 @@ class NhAssistantStore {
|
|
|
1964
2017
|
this.conversationsTotalState.update(total => Math.max(0, total - 1));
|
|
1965
2018
|
if (this.activeConversationState()?.id === conversationId) {
|
|
1966
2019
|
this.activeConversationState.set(null);
|
|
2020
|
+
this.noticeState.set(null);
|
|
1967
2021
|
this.uiState.update({ conversationId: null });
|
|
1968
2022
|
}
|
|
1969
2023
|
}
|
|
@@ -1987,6 +2041,7 @@ class NhAssistantStore {
|
|
|
1987
2041
|
return false;
|
|
1988
2042
|
}
|
|
1989
2043
|
this.errorState.set(null);
|
|
2044
|
+
this.noticeState.set(null);
|
|
1990
2045
|
this.restoredDraftState.set(null);
|
|
1991
2046
|
this.streamingState.set(true);
|
|
1992
2047
|
const accountRevision = this.accountRevision;
|
|
@@ -2060,6 +2115,7 @@ class NhAssistantStore {
|
|
|
2060
2115
|
this.decidingState.set(true);
|
|
2061
2116
|
this.streamingState.set(true);
|
|
2062
2117
|
this.errorState.set(null);
|
|
2118
|
+
this.noticeState.set(null);
|
|
2063
2119
|
let accepted = false;
|
|
2064
2120
|
let failed = false;
|
|
2065
2121
|
const request = { decision, expectedProposalHash: approval.proposalHash, ...(reason ? { reason } : {}) };
|
|
@@ -2121,6 +2177,9 @@ class NhAssistantStore {
|
|
|
2121
2177
|
clearError() {
|
|
2122
2178
|
this.errorState.set(null);
|
|
2123
2179
|
}
|
|
2180
|
+
clearNotice() {
|
|
2181
|
+
this.noticeState.set(null);
|
|
2182
|
+
}
|
|
2124
2183
|
/** Persists only drawer visibility, never the page context or a message draft. */
|
|
2125
2184
|
setPanelOpen(open) {
|
|
2126
2185
|
this.restorePanelOpenState.set(open);
|
|
@@ -2261,7 +2320,21 @@ class NhAssistantStore {
|
|
|
2261
2320
|
const code = event.data.errorCode ?? NhAssistantClientErrorCodes.server;
|
|
2262
2321
|
this.errorState.set(clientError(code));
|
|
2263
2322
|
}
|
|
2323
|
+
else if (event.data.status === 'completed') {
|
|
2324
|
+
this.noticeState.set(this.completionNotice(event.data.errorCode));
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
/** A completed turn with a server code, or without any answer text, explains itself with a notice. */
|
|
2329
|
+
completionNotice(errorCode) {
|
|
2330
|
+
if (errorCode) {
|
|
2331
|
+
return clientError(errorCode);
|
|
2332
|
+
}
|
|
2333
|
+
const conversation = this.activeConversationState();
|
|
2334
|
+
if (conversation && !nhAssistantLatestTurnHasText(conversation)) {
|
|
2335
|
+
return { code: NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, messageKey: 'nh-assistant.notices.no-answer' };
|
|
2264
2336
|
}
|
|
2337
|
+
return null;
|
|
2265
2338
|
}
|
|
2266
2339
|
afterTurn(conversationId, reload) {
|
|
2267
2340
|
const active = this.activeConversationState();
|
|
@@ -2695,7 +2768,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
2695
2768
|
args: [{ name: 'nhAssistantTranslate', standalone: true, pure: false }]
|
|
2696
2769
|
}], ctorParameters: () => [] });
|
|
2697
2770
|
|
|
2698
|
-
let nextId$
|
|
2771
|
+
let nextId$5 = 0;
|
|
2699
2772
|
/**
|
|
2700
2773
|
* Chooses the agent for new conversations. Agent names come from the host's translation
|
|
2701
2774
|
* keys; agents created by an administrator carry literal text, which is shown as is.
|
|
@@ -2706,7 +2779,7 @@ class NhAssistantAgentPickerComponent {
|
|
|
2706
2779
|
this.selectedAgentId = input(null, ...(ngDevMode ? [{ debugName: "selectedAgentId" }] : []));
|
|
2707
2780
|
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
2708
2781
|
this.agentChange = output();
|
|
2709
|
-
this.selectId = `nh-assistant-agent-picker-${nextId$
|
|
2782
|
+
this.selectId = `nh-assistant-agent-picker-${nextId$5++}`;
|
|
2710
2783
|
this.selected = computed(() => this.agents().find(agent => agent.id === this.selectedAgentId()) ?? null, ...(ngDevMode ? [{ debugName: "selected" }] : []));
|
|
2711
2784
|
}
|
|
2712
2785
|
onChange(event) {
|
|
@@ -2756,7 +2829,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
2756
2829
|
`, styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;gap:2px;min-width:0}select{align-self:flex-start;max-width:100%;min-height:32px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 28px 4px 10px;color:var(--nha-text);background:var(--nha-background);font:inherit;font-size:13px;font-weight:650}select:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}select:disabled{opacity:1;cursor:default}.capability{padding-left:2px;color:var(--nha-text-muted);font-size:11px}.capability[data-can-mutate=true]{color:var(--nha-warning)}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
2757
2830
|
}], propDecorators: { agents: [{ type: i0.Input, args: [{ isSignal: true, alias: "agents", required: true }] }], selectedAgentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedAgentId", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], agentChange: [{ type: i0.Output, args: ["agentChange"] }] } });
|
|
2758
2831
|
|
|
2759
|
-
let nextId$
|
|
2832
|
+
let nextId$4 = 0;
|
|
2760
2833
|
/**
|
|
2761
2834
|
* Message input. Enter sends when sending is available; Shift+Enter inserts a new line.
|
|
2762
2835
|
* Drafting remains available while the assistant runs or waits for approval.
|
|
@@ -2781,7 +2854,7 @@ class NhAssistantComposerComponent {
|
|
|
2781
2854
|
this.textarea = viewChild.required('textarea');
|
|
2782
2855
|
this.ownedFocus = false;
|
|
2783
2856
|
this.previousBusy = false;
|
|
2784
|
-
this.inputId = `nh-assistant-composer-${nextId$
|
|
2857
|
+
this.inputId = `nh-assistant-composer-${nextId$4++}`;
|
|
2785
2858
|
this.hintId = `${this.inputId}-hint`;
|
|
2786
2859
|
this.text = signal('', ...(ngDevMode ? [{ debugName: "text" }] : []));
|
|
2787
2860
|
this.length = computed(() => this.text().trim().length, ...(ngDevMode ? [{ debugName: "length" }] : []));
|
|
@@ -2888,7 +2961,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
2888
2961
|
|
|
2889
2962
|
/** Maximum length of the user's own instructions. */
|
|
2890
2963
|
const NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS = 1_000;
|
|
2891
|
-
let nextId$
|
|
2964
|
+
let nextId$3 = 0;
|
|
2892
2965
|
/**
|
|
2893
2966
|
* The user's own assistant preferences: style, form of address, answer length and
|
|
2894
2967
|
* optional instructions. Preferences steer style only; the server keeps them below the
|
|
@@ -2901,7 +2974,7 @@ class NhAssistantPreferencesComponent {
|
|
|
2901
2974
|
this.closed = output();
|
|
2902
2975
|
/** Emitted with the stored preferences after a successful save. */
|
|
2903
2976
|
this.saved = output();
|
|
2904
|
-
this.id = `nh-assistant-preferences-${nextId$
|
|
2977
|
+
this.id = `nh-assistant-preferences-${nextId$3++}`;
|
|
2905
2978
|
this.styles = ['default', 'direct', 'personal', 'detailed'];
|
|
2906
2979
|
this.addressForms = ['informal', 'formal'];
|
|
2907
2980
|
this.responseLengths = ['short', 'normal', 'long'];
|
|
@@ -3095,6 +3168,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
3095
3168
|
args: [{ name: 'nhAssistantMarkdown', standalone: true }]
|
|
3096
3169
|
}] });
|
|
3097
3170
|
|
|
3171
|
+
/**
|
|
3172
|
+
* Groups consecutive tool calls of a message. Text and approvals break a group, so an
|
|
3173
|
+
* approval always stays visible. A group's key is its first invocation id, so it keeps
|
|
3174
|
+
* its identity while later calls of the same run are appended.
|
|
3175
|
+
*/
|
|
3176
|
+
function groupNhAssistantParts(parts) {
|
|
3177
|
+
const groups = [];
|
|
3178
|
+
let tools = null;
|
|
3179
|
+
parts.forEach((part, index) => {
|
|
3180
|
+
if (part.type === 'tool-call') {
|
|
3181
|
+
if (!tools) {
|
|
3182
|
+
tools = { kind: 'tools', key: `tools:${part.invocationId}`, calls: [] };
|
|
3183
|
+
groups.push(tools);
|
|
3184
|
+
}
|
|
3185
|
+
tools.calls.push(part);
|
|
3186
|
+
return;
|
|
3187
|
+
}
|
|
3188
|
+
tools = null;
|
|
3189
|
+
if (part.type === 'approval') {
|
|
3190
|
+
groups.push({ kind: 'approval', key: `approval:${part.approvalId}`, part });
|
|
3191
|
+
}
|
|
3192
|
+
else {
|
|
3193
|
+
groups.push({ kind: 'text', key: `text:${index}`, part });
|
|
3194
|
+
}
|
|
3195
|
+
});
|
|
3196
|
+
return groups;
|
|
3197
|
+
}
|
|
3198
|
+
/** Pure, so the groups are only rebuilt when the reducer replaces a message's parts. */
|
|
3199
|
+
class NhAssistantPartGroupsPipe {
|
|
3200
|
+
transform(parts) {
|
|
3201
|
+
return groupNhAssistantParts(parts);
|
|
3202
|
+
}
|
|
3203
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantPartGroupsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
3204
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantPartGroupsPipe, isStandalone: true, name: "nhAssistantPartGroups" }); }
|
|
3205
|
+
}
|
|
3206
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantPartGroupsPipe, decorators: [{
|
|
3207
|
+
type: Pipe,
|
|
3208
|
+
args: [{ name: 'nhAssistantPartGroups', standalone: true }]
|
|
3209
|
+
}] });
|
|
3210
|
+
|
|
3098
3211
|
/** Formats remaining milliseconds as `m:ss`, or `h:mm:ss` above one hour. */
|
|
3099
3212
|
function formatNhAssistantCountdown(milliseconds) {
|
|
3100
3213
|
const totalSeconds = Math.max(0, Math.ceil(milliseconds / 1000));
|
|
@@ -3165,7 +3278,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
3165
3278
|
}, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"actionable() ? 'warning' : effectiveStatus() === 'approved' ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ 'nh-assistant.approval.status.' + effectiveStatus() | translate }}</span>\n </header>\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable()) {\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.reject{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}\n"] }]
|
|
3166
3279
|
}], ctorParameters: () => [], propDecorators: { approval: [{ type: i0.Input, args: [{ isSignal: true, alias: "approval", required: true }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], decide: [{ type: i0.Output, args: ["decide"] }] } });
|
|
3167
3280
|
|
|
3168
|
-
let nextId$
|
|
3281
|
+
let nextId$2 = 0;
|
|
3169
3282
|
const statusIcons = {
|
|
3170
3283
|
running: 'tool',
|
|
3171
3284
|
succeeded: 'check',
|
|
@@ -3177,7 +3290,7 @@ const statusIcons = {
|
|
|
3177
3290
|
class NhAssistantToolCallCardComponent {
|
|
3178
3291
|
constructor() {
|
|
3179
3292
|
this.part = input.required(...(ngDevMode ? [{ debugName: "part" }] : []));
|
|
3180
|
-
this.detailsId = `nh-assistant-tool-call-${nextId$
|
|
3293
|
+
this.detailsId = `nh-assistant-tool-call-${nextId$2++}`;
|
|
3181
3294
|
this.expanded = signal(false, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
|
|
3182
3295
|
this.statusIcon = computed(() => statusIcons[this.part().status], ...(ngDevMode ? [{ debugName: "statusIcon" }] : []));
|
|
3183
3296
|
this.hasDetails = computed(() => !!this.part().toolId, ...(ngDevMode ? [{ debugName: "hasDetails" }] : []));
|
|
@@ -3195,14 +3308,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
3195
3308
|
}, template: "<article class=\"card\" [attr.aria-label]=\"'nh-assistant.tool-call.label' | translate: { name: part().displayName }\">\n <header class=\"header\">\n <span class=\"status-icon\" [class.spinning]=\"part().status === 'running'\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n </span>\n <span class=\"title\">{{ part().displayName }}</span>\n <span class=\"status\">{{ 'nh-assistant.tool-call.status.' + part().status | translate }}</span>\n @if (hasDetails()) {\n <button\n class=\"toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"detailsId\"\n [attr.aria-label]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n (click)=\"toggle()\">\n <nh-assistant-icon name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n }\n </header>\n\n @if (part().resultCode; as resultCode) {\n <p class=\"result-code\">\n {{ ['nh-assistant.result-codes.' + resultCode, 'nh-assistant.errors.' + resultCode] | nhAssistantTranslate: resultCode }}\n </p>\n }\n\n @if (hasDetails()) {\n <div class=\"details\" [id]=\"detailsId\" [hidden]=\"!expanded()\">\n <p class=\"label\">{{ 'nh-assistant.tool-call.tool-id' | translate }}</p>\n <code>{{ part().toolId }}</code>\n @if (part().argumentsPreview; as argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.arguments' | translate }}</p>\n <pre>{{ argumentsPreview }}</pre>\n }\n @if (part().resultPreview; as resultPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <pre>{{ resultPreview }}</pre>\n }\n </div>\n }\n</article>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=failed]){--nha-status-color: var(--nha-danger);--nha-status-background: var(--nha-danger-soft)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=rejected]){--nha-status-color: var(--nha-text-muted)}.card{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:8px 10px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;min-width:0}.status-icon{display:inline-flex;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.status{flex:none;border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:28px;height:28px}.toggle:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.toggle:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.toggle:disabled{cursor:not-allowed;opacity:.5}.rotated{transform:rotate(180deg)}.result-code{margin:6px 0 0;color:var(--nha-text-muted);font-size:12px}.details{margin-top:8px}.label{margin:8px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}pre{max-height:180px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}nh-assistant-icon{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"] }]
|
|
3196
3309
|
}], propDecorators: { part: [{ type: i0.Input, args: [{ isSignal: true, alias: "part", required: true }] }] } });
|
|
3197
3310
|
|
|
3311
|
+
let nextId$1 = 0;
|
|
3312
|
+
const stateIcons = {
|
|
3313
|
+
'awaiting-approval': 'clock',
|
|
3314
|
+
running: 'tool',
|
|
3315
|
+
failed: 'warning',
|
|
3316
|
+
succeeded: 'check'
|
|
3317
|
+
};
|
|
3318
|
+
/**
|
|
3319
|
+
* Summarizes consecutive tool calls in one collapsed line that counts along live: the
|
|
3320
|
+
* tool that runs now while the assistant works, and how many tools were used and failed
|
|
3321
|
+
* afterwards. Expanding it shows every call as a card.
|
|
3322
|
+
*/
|
|
3323
|
+
class NhAssistantToolCallGroupComponent {
|
|
3324
|
+
constructor() {
|
|
3325
|
+
this.calls = input.required(...(ngDevMode ? [{ debugName: "calls" }] : []));
|
|
3326
|
+
this.callsId = `nh-assistant-tool-call-group-${nextId$1++}`;
|
|
3327
|
+
this.expanded = signal(false, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
|
|
3328
|
+
/** The call that currently needs attention or runs; the latest one when several do. */
|
|
3329
|
+
this.current = computed(() => {
|
|
3330
|
+
const calls = this.calls();
|
|
3331
|
+
return findLast(calls, call => call.status === 'awaiting-approval')
|
|
3332
|
+
?? findLast(calls, call => call.status === 'running')
|
|
3333
|
+
?? null;
|
|
3334
|
+
}, ...(ngDevMode ? [{ debugName: "current" }] : []));
|
|
3335
|
+
this.total = computed(() => this.calls().length, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
3336
|
+
this.finished = computed(() => this.calls().filter(call => !isActive(call)).length, ...(ngDevMode ? [{ debugName: "finished" }] : []));
|
|
3337
|
+
this.failed = computed(() => this.calls().filter(call => call.status === 'failed').length, ...(ngDevMode ? [{ debugName: "failed" }] : []));
|
|
3338
|
+
this.state = computed(() => {
|
|
3339
|
+
const current = this.current();
|
|
3340
|
+
if (current) {
|
|
3341
|
+
return current.status === 'awaiting-approval' ? 'awaiting-approval' : 'running';
|
|
3342
|
+
}
|
|
3343
|
+
return this.failed() > 0 ? 'failed' : 'succeeded';
|
|
3344
|
+
}, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
3345
|
+
this.stateIcon = computed(() => stateIcons[this.state()], ...(ngDevMode ? [{ debugName: "stateIcon" }] : []));
|
|
3346
|
+
}
|
|
3347
|
+
toggle() {
|
|
3348
|
+
this.expanded.update(expanded => !expanded);
|
|
3349
|
+
}
|
|
3350
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantToolCallGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3351
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: NhAssistantToolCallGroupComponent, isStandalone: true, selector: "nh-assistant-tool-call-group", inputs: { calls: { classPropertyName: "calls", publicName: "calls", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-status": "state()" } }, ngImport: i0, template: "<section class=\"group\">\n <button\n class=\"summary\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"callsId\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-group.hide-calls' : 'nh-assistant.tool-group.show-calls') | translate\"\n (click)=\"toggle()\">\n <span class=\"status-icon\" [class.spinning]=\"state() === 'running'\">\n <nh-assistant-icon [name]=\"stateIcon()\" />\n </span>\n <span class=\"title\">\n @switch (state()) {\n @case ('running') {\n {{ 'nh-assistant.tool-group.running' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-approval') {\n {{ 'nh-assistant.tool-group.awaiting-approval' | translate: { name: current()?.displayName } }}\n }\n @default {\n {{ (total() === 1 ? 'nh-assistant.tool-group.used-one' : 'nh-assistant.tool-group.used-many') | translate: { count: total() } }}\n }\n }\n </span>\n @if (state() === 'running' || state() === 'awaiting-approval') {\n <span class=\"count\">{{ 'nh-assistant.tool-group.progress' | translate: { finished: finished(), total: total() } }}</span>\n } @else if (failed() > 0) {\n <span class=\"count failed\">{{ 'nh-assistant.tool-group.failed' | translate: { count: failed() } }}</span>\n }\n <nh-assistant-icon class=\"chevron\" name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n\n <div class=\"calls\" [id]=\"callsId\" [hidden]=\"!expanded()\">\n @if (expanded()) {\n @for (call of calls(); track call.invocationId) {\n <nh-assistant-tool-call-card [part]=\"call\" />\n }\n }\n </div>\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success)}:host([data-status=failed]){--nha-status-color: var(--nha-danger)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning)}.group{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);color:var(--nha-text);background:var(--nha-background)}.summary{display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:40px;border:0;border-radius:var(--nha-radius-control);padding:8px 10px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.summary:hover{background:var(--nha-surface)}.status-icon{display:inline-flex;flex:none;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.count{flex:none;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.count.failed{border-radius:999px;padding:2px 8px;color:var(--nha-danger);background:var(--nha-danger-soft);font-size:11px;font-weight:700}.chevron{flex:none;color:var(--nha-text-muted)}.rotated{transform:rotate(180deg)}.calls{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--nha-border);padding:8px}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}.chevron{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantToolCallCardComponent, selector: "nh-assistant-tool-call-card", inputs: ["part"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3352
|
+
}
|
|
3353
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantToolCallGroupComponent, decorators: [{
|
|
3354
|
+
type: Component,
|
|
3355
|
+
args: [{ selector: 'nh-assistant-tool-call-group', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent, NhAssistantToolCallCardComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
3356
|
+
'[attr.data-status]': 'state()'
|
|
3357
|
+
}, template: "<section class=\"group\">\n <button\n class=\"summary\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"callsId\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-group.hide-calls' : 'nh-assistant.tool-group.show-calls') | translate\"\n (click)=\"toggle()\">\n <span class=\"status-icon\" [class.spinning]=\"state() === 'running'\">\n <nh-assistant-icon [name]=\"stateIcon()\" />\n </span>\n <span class=\"title\">\n @switch (state()) {\n @case ('running') {\n {{ 'nh-assistant.tool-group.running' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-approval') {\n {{ 'nh-assistant.tool-group.awaiting-approval' | translate: { name: current()?.displayName } }}\n }\n @default {\n {{ (total() === 1 ? 'nh-assistant.tool-group.used-one' : 'nh-assistant.tool-group.used-many') | translate: { count: total() } }}\n }\n }\n </span>\n @if (state() === 'running' || state() === 'awaiting-approval') {\n <span class=\"count\">{{ 'nh-assistant.tool-group.progress' | translate: { finished: finished(), total: total() } }}</span>\n } @else if (failed() > 0) {\n <span class=\"count failed\">{{ 'nh-assistant.tool-group.failed' | translate: { count: failed() } }}</span>\n }\n <nh-assistant-icon class=\"chevron\" name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n\n <div class=\"calls\" [id]=\"callsId\" [hidden]=\"!expanded()\">\n @if (expanded()) {\n @for (call of calls(); track call.invocationId) {\n <nh-assistant-tool-call-card [part]=\"call\" />\n }\n }\n </div>\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success)}:host([data-status=failed]){--nha-status-color: var(--nha-danger)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning)}.group{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);color:var(--nha-text);background:var(--nha-background)}.summary{display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:40px;border:0;border-radius:var(--nha-radius-control);padding:8px 10px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.summary:hover{background:var(--nha-surface)}.status-icon{display:inline-flex;flex:none;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.count{flex:none;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.count.failed{border-radius:999px;padding:2px 8px;color:var(--nha-danger);background:var(--nha-danger-soft);font-size:11px;font-weight:700}.chevron{flex:none;color:var(--nha-text-muted)}.rotated{transform:rotate(180deg)}.calls{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--nha-border);padding:8px}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}.chevron{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"] }]
|
|
3358
|
+
}], propDecorators: { calls: [{ type: i0.Input, args: [{ isSignal: true, alias: "calls", required: true }] }] } });
|
|
3359
|
+
function isActive(call) {
|
|
3360
|
+
return call.status === 'running' || call.status === 'awaiting-approval';
|
|
3361
|
+
}
|
|
3362
|
+
function findLast(calls, predicate) {
|
|
3363
|
+
for (let index = calls.length - 1; index >= 0; index--) {
|
|
3364
|
+
if (predicate(calls[index])) {
|
|
3365
|
+
return calls[index];
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
return undefined;
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3198
3371
|
/** Above this number of messages the thread renders through CDK virtual scrolling. */
|
|
3199
3372
|
const NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD = 200;
|
|
3200
3373
|
/** Distance from the bottom, in pixels, within which new content keeps the thread pinned to the end. */
|
|
3201
3374
|
const stickToBottomDistance = 120;
|
|
3202
3375
|
/**
|
|
3203
3376
|
* The messages of a conversation as a live log. Assistant text renders as sanitized
|
|
3204
|
-
* Markdown, tool calls
|
|
3205
|
-
*
|
|
3377
|
+
* Markdown, consecutive tool calls as one collapsible group that counts along, and
|
|
3378
|
+
* approvals as cards. While a turn runs without visible progress, a working indicator
|
|
3379
|
+
* shows the elapsed time. The thread follows new content while the user is at the bottom.
|
|
3206
3380
|
*/
|
|
3207
3381
|
class NhAssistantThreadComponent {
|
|
3208
3382
|
constructor() {
|
|
@@ -3214,15 +3388,48 @@ class NhAssistantThreadComponent {
|
|
|
3214
3388
|
this.approvalDecision = output();
|
|
3215
3389
|
this.virtualThreshold = NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD;
|
|
3216
3390
|
this.virtual = computed(() => this.messages().length > NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD, ...(ngDevMode ? [{ debugName: "virtual" }] : []));
|
|
3391
|
+
/**
|
|
3392
|
+
* True while the turn runs and nothing else shows progress: before the first part and
|
|
3393
|
+
* between tool calls while the model decides what to do next. Streaming text and a
|
|
3394
|
+
* running tool group show their own progress; an approval waits for the user.
|
|
3395
|
+
*/
|
|
3217
3396
|
this.working = computed(() => {
|
|
3218
3397
|
if (!this.streaming()) {
|
|
3219
3398
|
return false;
|
|
3220
3399
|
}
|
|
3221
3400
|
const last = this.messages()[this.messages().length - 1];
|
|
3222
|
-
|
|
3401
|
+
if (!last || last.role === 'user' || last.parts.length === 0) {
|
|
3402
|
+
return true;
|
|
3403
|
+
}
|
|
3404
|
+
const lastPart = last.parts[last.parts.length - 1];
|
|
3405
|
+
return lastPart.type === 'tool-call'
|
|
3406
|
+
&& lastPart.status !== 'running'
|
|
3407
|
+
&& lastPart.status !== 'awaiting-approval';
|
|
3223
3408
|
}, ...(ngDevMode ? [{ debugName: "working" }] : []));
|
|
3409
|
+
/** Whole seconds since the running turn started. */
|
|
3410
|
+
this.elapsedSeconds = computed(() => {
|
|
3411
|
+
const startedAt = this.turnStartedAt();
|
|
3412
|
+
return startedAt === null ? 0 : Math.max(0, Math.floor((this.now() - startedAt) / 1000));
|
|
3413
|
+
}, ...(ngDevMode ? [{ debugName: "elapsedSeconds" }] : []));
|
|
3414
|
+
this.turnStartedAt = signal(null, ...(ngDevMode ? [{ debugName: "turnStartedAt" }] : []));
|
|
3415
|
+
this.now = signal(Date.now(), ...(ngDevMode ? [{ debugName: "now" }] : []));
|
|
3224
3416
|
this.scroller = viewChild('scroller', ...(ngDevMode ? [{ debugName: "scroller" }] : []));
|
|
3225
3417
|
this.viewport = viewChild(CdkVirtualScrollViewport, ...(ngDevMode ? [{ debugName: "viewport" }] : []));
|
|
3418
|
+
effect(onCleanup => {
|
|
3419
|
+
if (!this.streaming()) {
|
|
3420
|
+
this.turnStartedAt.set(null);
|
|
3421
|
+
return;
|
|
3422
|
+
}
|
|
3423
|
+
untracked(() => {
|
|
3424
|
+
const now = Date.now();
|
|
3425
|
+
this.now.set(now);
|
|
3426
|
+
if (this.turnStartedAt() === null) {
|
|
3427
|
+
this.turnStartedAt.set(now);
|
|
3428
|
+
}
|
|
3429
|
+
});
|
|
3430
|
+
const timer = setInterval(() => this.now.set(Date.now()), 1000);
|
|
3431
|
+
onCleanup(() => clearInterval(timer));
|
|
3432
|
+
});
|
|
3226
3433
|
effect(() => {
|
|
3227
3434
|
this.messages();
|
|
3228
3435
|
this.working();
|
|
@@ -3252,7 +3459,7 @@ class NhAssistantThreadComponent {
|
|
|
3252
3459
|
}
|
|
3253
3460
|
}
|
|
3254
3461
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantThreadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3255
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: NhAssistantThreadComponent, isStandalone: true, selector: "nh-assistant-thread", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, markdown: { classPropertyName: "markdown", publicName: "markdown", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalDecision: "approvalDecision" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true, isSignal: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n }\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article class=\"message\" [attr.data-role]=\"message.role\">\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n @for (part of message.parts; track $index) {\n @switch (part.type) {\n @case ('text') {\n @if (message.role === 'assistant' && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ part.text }}</div>\n }\n }\n @case ('tool-call') {\n <nh-assistant-tool-call-card class=\"part\" [part]=\"part\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card class=\"part\" [approval]=\"part\" [deciding]=\"deciding()\" (decide)=\"approvalDecision.emit($event)\" />\n }\n }\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:14px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{border:1px solid var(--nha-border);background:var(--nha-surface)}.part{width:100%}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: NhAssistantToolCallCardComponent, selector: "nh-assistant-tool-call-card", inputs: ["part"] }, { kind: "component", type: NhAssistantApprovalCardComponent, selector: "nh-assistant-approval-card", inputs: ["approval", "deciding"], outputs: ["decide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantMarkdownPipe, name: "nhAssistantMarkdown" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3462
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: NhAssistantThreadComponent, isStandalone: true, selector: "nh-assistant-thread", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, markdown: { classPropertyName: "markdown", publicName: "markdown", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalDecision: "approvalDecision" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true, isSignal: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n }\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article class=\"message\" [attr.data-role]=\"message.role\">\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if (message.role === 'assistant' && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card class=\"part\" [approval]=\"group.part\" [deciding]=\"deciding()\" (decide)=\"approvalDecision.emit($event)\" />\n }\n }\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:14px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{border:1px solid var(--nha-border);background:var(--nha-surface)}.part{width:100%}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: NhAssistantToolCallGroupComponent, selector: "nh-assistant-tool-call-group", inputs: ["calls"] }, { kind: "component", type: NhAssistantApprovalCardComponent, selector: "nh-assistant-approval-card", inputs: ["approval", "deciding"], outputs: ["decide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantMarkdownPipe, name: "nhAssistantMarkdown" }, { kind: "pipe", type: NhAssistantPartGroupsPipe, name: "nhAssistantPartGroups" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3256
3463
|
}
|
|
3257
3464
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantThreadComponent, decorators: [{
|
|
3258
3465
|
type: Component,
|
|
@@ -3261,9 +3468,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
3261
3468
|
ScrollingModule,
|
|
3262
3469
|
TranslatePipe,
|
|
3263
3470
|
NhAssistantMarkdownPipe,
|
|
3264
|
-
|
|
3471
|
+
NhAssistantPartGroupsPipe,
|
|
3472
|
+
NhAssistantToolCallGroupComponent,
|
|
3265
3473
|
NhAssistantApprovalCardComponent
|
|
3266
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n }\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article class=\"message\" [attr.data-role]=\"message.role\">\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n @for (
|
|
3474
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n }\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article class=\"message\" [attr.data-role]=\"message.role\">\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if (message.role === 'assistant' && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card class=\"part\" [approval]=\"group.part\" [deciding]=\"deciding()\" (decide)=\"approvalDecision.emit($event)\" />\n }\n }\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:14px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{border:1px solid var(--nha-border);background:var(--nha-surface)}.part{width:100%}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}\n"] }]
|
|
3267
3475
|
}], ctorParameters: () => [], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], markdown: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdown", required: false }] }], approvalDecision: [{ type: i0.Output, args: ["approvalDecision"] }], scroller: [{ type: i0.ViewChild, args: ['scroller', { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }] } });
|
|
3268
3476
|
|
|
3269
3477
|
let nextId = 0;
|
|
@@ -3303,6 +3511,10 @@ class NhAssistantPanelComponent {
|
|
|
3303
3511
|
const error = this.store.error();
|
|
3304
3512
|
return error ? [error.messageKey, `nh-assistant.errors.${error.code}`, 'nh-assistant.errors.generic'] : [];
|
|
3305
3513
|
}, ...(ngDevMode ? [{ debugName: "errorKeys" }] : []));
|
|
3514
|
+
this.noticeKeys = computed(() => {
|
|
3515
|
+
const notice = this.store.notice();
|
|
3516
|
+
return notice ? [notice.messageKey, `nh-assistant.errors.${notice.code}`, 'nh-assistant.errors.generic'] : [];
|
|
3517
|
+
}, ...(ngDevMode ? [{ debugName: "noticeKeys" }] : []));
|
|
3306
3518
|
// Opening, creating or leaving a conversation returns from the list to the thread.
|
|
3307
3519
|
effect(() => {
|
|
3308
3520
|
if (this.conversationId() !== undefined) {
|
|
@@ -3374,7 +3586,7 @@ class NhAssistantPanelComponent {
|
|
|
3374
3586
|
void this.store.cancel();
|
|
3375
3587
|
}
|
|
3376
3588
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3377
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: NhAssistantPanelComponent, isStandalone: true, selector: "nh-assistant-panel", viewQueries: [{ propertyName: "drawer", first: true, predicate: ["drawer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #drawer>\n <section class=\"drawer\" role=\"dialog\" aria-modal=\"false\" [attr.aria-labelledby]=\"titleId\">\n <header class=\"header\">\n <div class=\"heading\">\n <h2 [id]=\"titleId\">{{ 'nh-assistant.panel.title' | translate }}</h2>\n @if (store.enabled()) {\n <nh-assistant-agent-picker\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n [disabled]=\"store.streaming()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showConversations()\"\n [attr.aria-expanded]=\"showConversations()\"\n [attr.aria-label]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n [attr.title]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n (click)=\"toggleConversations()\">\n <nh-assistant-icon name=\"list\" />\n </button>\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showPreferences()\"\n [attr.aria-expanded]=\"showPreferences()\"\n [attr.aria-label]=\"'nh-assistant.panel.open-preferences' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-preferences' | translate\"\n (click)=\"togglePreferences()\">\n <nh-assistant-icon name=\"settings\" />\n </button>\n @if (adminRoute && store.canAdminister()) {\n <a\n class=\"icon-button\"\n [routerLink]=\"adminRoute\"\n [attr.aria-label]=\"'nh-assistant.panel.open-admin' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-admin' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"admin\" />\n </a>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [disabled]=\"store.streaming()\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"newConversation()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.close' | translate\"\n [attr.title]=\"'nh-assistant.panel.close' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n </header>\n\n <div class=\"body\">\n @if (store.statusLoading() && !store.enabled()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.panel.loading' | translate }}</p>\n </div>\n } @else if (!store.enabled()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"warning\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.unavailable-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.unavailable-description' | translate }}</p>\n </div>\n } @else {\n @if (showPreferences()) {\n <nh-assistant-preferences class=\"overlay-view\" (closed)=\"showPreferences.set(false)\" />\n }\n\n @if (showConversations()) {\n <nh-assistant-conversation-list\n class=\"overlay-view\"\n [conversations]=\"store.conversations()\"\n [total]=\"store.conversationsTotal()\"\n [activeConversationId]=\"conversation()?.id ?? null\"\n [loading]=\"store.conversationsLoading()\"\n [disabled]=\"store.streaming()\"\n (conversationSelect)=\"openConversation($event)\"\n (conversationDelete)=\"deleteConversation($event)\"\n (conversationCreate)=\"newConversation()\" />\n }\n\n @if (store.conversationLoading()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.thread.loading' | translate }}</p>\n </div>\n } @else if (messages().length === 0 && !store.streaming()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"assistant\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.empty-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.empty-description' | translate }}</p>\n </div>\n } @else {\n <nh-assistant-thread\n class=\"thread\"\n [messages]=\"messages()\"\n [streaming]=\"store.streaming()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n (approvalDecision)=\"decide($event)\" />\n }\n }\n </div>\n\n @if (store.error(); as error) {\n <div class=\"error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ errorKeys() | nhAssistantTranslate: error.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearError()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n }\n\n @if (store.enabled() && !showPreferences()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n }\n @if (store.pageContext(); as context) {\n <div class=\"context-chip\" [class.excluded]=\"store.pageContextExcluded()\" [attr.title]=\"context.route\">\n <nh-assistant-icon name=\"page\" />\n <span class=\"context-text\">\n {{ (store.pageContextExcluded() ? 'nh-assistant.page-context.excluded' : 'nh-assistant.page-context.included') | translate: { page: describeContext(context) } }}\n </span>\n <button\n class=\"icon-button small\"\n type=\"button\"\n [attr.aria-pressed]=\"store.pageContextExcluded()\"\n [attr.aria-label]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n [attr.title]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n (click)=\"store.setPageContextExcluded(!store.pageContextExcluded())\">\n <nh-assistant-icon [name]=\"store.pageContextExcluded() ? 'plus' : 'x'\" />\n </button>\n </div>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [status]=\"composerStatus()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\" />\n </footer>\n }\n </section>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}.drawer{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){.drawer{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:contents}.drawer{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;border-left:1px solid var(--nha-border);color:var(--nha-text);background:var(--nha-background);box-shadow:var(--nha-shadow);font-family:var(--nha-font);font-size:14px}.drawer *,.drawer *:before,.drawer *:after{box-sizing:border-box}.header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px 12px;border-bottom:1px solid var(--nha-border);padding:12px 12px 12px 16px}.heading{display:contents}nh-assistant-agent-picker{grid-column:1/-1;grid-row:2}h2{grid-row:1;min-width:0;margin:0;overflow:hidden;font-size:16px;font-weight:750;letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap}.header-actions{display:flex;flex:none;grid-column:2;grid-row:1;gap:4px}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;text-decoration:none}.icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.icon-button:disabled{cursor:not-allowed;opacity:.5}.icon-button.active{color:var(--nha-highlight);background:var(--nha-surface-strong)}.body{position:relative;display:flex;flex:1;flex-direction:column;min-height:0;background:var(--nha-background)}.thread{flex:1;min-height:0}.overlay-view{position:absolute;z-index:1;inset:0;border-bottom:1px solid var(--nha-border);background:var(--nha-background)}.state{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:24px;color:var(--nha-text-muted);text-align:center}.state p{max-width:32ch;margin:0;font-size:13px}.state-icon{margin-bottom:8px;color:var(--nha-highlight);font-size:28px}.state .state-title{color:var(--nha-text);font-size:15px;font-weight:700}.error{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-danger);background:var(--nha-danger-soft)}.error p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.footer{border-top:1px solid var(--nha-border);padding:12px 16px 14px}.context-chip{display:flex;align-items:center;gap:6px;max-width:100%;margin:0 0 8px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;width:fit-content;color:var(--nha-text-muted);background:var(--nha-surface);font-size:12px}.context-chip.excluded .context-text{text-decoration:line-through}.context-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-button.small{flex:none;width:26px;height:26px;border-radius:999px}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAgentPickerComponent, selector: "nh-assistant-agent-picker", inputs: ["agents", "selectedAgentId", "disabled"], outputs: ["agentChange"] }, { kind: "component", type: NhAssistantComposerComponent, selector: "nh-assistant-composer", inputs: ["disabled", "sendDisabled", "busy", "status", "maxLength", "restore"], outputs: ["send", "cancel", "restored"] }, { kind: "component", type: NhAssistantConversationListComponent, selector: "nh-assistant-conversation-list", inputs: ["conversations", "total", "activeConversationId", "loading", "disabled"], outputs: ["conversationSelect", "conversationDelete", "conversationCreate"] }, { kind: "component", type: NhAssistantPreferencesComponent, selector: "nh-assistant-preferences", outputs: ["closed", "saved"] }, { kind: "component", type: NhAssistantThreadComponent, selector: "nh-assistant-thread", inputs: ["messages", "streaming", "deciding", "markdown"], outputs: ["approvalDecision"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3589
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: NhAssistantPanelComponent, isStandalone: true, selector: "nh-assistant-panel", viewQueries: [{ propertyName: "drawer", first: true, predicate: ["drawer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #drawer>\n <section class=\"drawer\" role=\"dialog\" aria-modal=\"false\" [attr.aria-labelledby]=\"titleId\">\n <header class=\"header\">\n <div class=\"heading\">\n <h2 [id]=\"titleId\">{{ 'nh-assistant.panel.title' | translate }}</h2>\n @if (store.enabled()) {\n <nh-assistant-agent-picker\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n [disabled]=\"store.streaming()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showConversations()\"\n [attr.aria-expanded]=\"showConversations()\"\n [attr.aria-label]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n [attr.title]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n (click)=\"toggleConversations()\">\n <nh-assistant-icon name=\"list\" />\n </button>\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showPreferences()\"\n [attr.aria-expanded]=\"showPreferences()\"\n [attr.aria-label]=\"'nh-assistant.panel.open-preferences' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-preferences' | translate\"\n (click)=\"togglePreferences()\">\n <nh-assistant-icon name=\"settings\" />\n </button>\n @if (adminRoute && store.canAdminister()) {\n <a\n class=\"icon-button\"\n [routerLink]=\"adminRoute\"\n [attr.aria-label]=\"'nh-assistant.panel.open-admin' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-admin' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"admin\" />\n </a>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [disabled]=\"store.streaming()\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"newConversation()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.close' | translate\"\n [attr.title]=\"'nh-assistant.panel.close' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n </header>\n\n <div class=\"body\">\n @if (store.statusLoading() && !store.enabled()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.panel.loading' | translate }}</p>\n </div>\n } @else if (!store.enabled()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"warning\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.unavailable-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.unavailable-description' | translate }}</p>\n </div>\n } @else {\n @if (showPreferences()) {\n <nh-assistant-preferences class=\"overlay-view\" (closed)=\"showPreferences.set(false)\" />\n }\n\n @if (showConversations()) {\n <nh-assistant-conversation-list\n class=\"overlay-view\"\n [conversations]=\"store.conversations()\"\n [total]=\"store.conversationsTotal()\"\n [activeConversationId]=\"conversation()?.id ?? null\"\n [loading]=\"store.conversationsLoading()\"\n [disabled]=\"store.streaming()\"\n (conversationSelect)=\"openConversation($event)\"\n (conversationDelete)=\"deleteConversation($event)\"\n (conversationCreate)=\"newConversation()\" />\n }\n\n @if (store.conversationLoading()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.thread.loading' | translate }}</p>\n </div>\n } @else if (messages().length === 0 && !store.streaming()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"assistant\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.empty-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.empty-description' | translate }}</p>\n </div>\n } @else {\n <nh-assistant-thread\n class=\"thread\"\n [messages]=\"messages()\"\n [streaming]=\"store.streaming()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n (approvalDecision)=\"decide($event)\" />\n }\n }\n </div>\n\n @if (store.error(); as error) {\n <div class=\"error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ errorKeys() | nhAssistantTranslate: error.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearError()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n } @else if (store.notice(); as notice) {\n <div class=\"turn-notice\" role=\"status\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ noticeKeys() | nhAssistantTranslate: notice.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearNotice()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n }\n\n @if (store.enabled() && !showPreferences()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n }\n @if (store.pageContext(); as context) {\n <div class=\"context-chip\" [class.excluded]=\"store.pageContextExcluded()\" [attr.title]=\"context.route\">\n <nh-assistant-icon name=\"page\" />\n <span class=\"context-text\">\n {{ (store.pageContextExcluded() ? 'nh-assistant.page-context.excluded' : 'nh-assistant.page-context.included') | translate: { page: describeContext(context) } }}\n </span>\n <button\n class=\"icon-button small\"\n type=\"button\"\n [attr.aria-pressed]=\"store.pageContextExcluded()\"\n [attr.aria-label]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n [attr.title]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n (click)=\"store.setPageContextExcluded(!store.pageContextExcluded())\">\n <nh-assistant-icon [name]=\"store.pageContextExcluded() ? 'plus' : 'x'\" />\n </button>\n </div>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [status]=\"composerStatus()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\" />\n </footer>\n }\n </section>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}.drawer{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){.drawer{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:contents}.drawer{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;border-left:1px solid var(--nha-border);color:var(--nha-text);background:var(--nha-background);box-shadow:var(--nha-shadow);font-family:var(--nha-font);font-size:14px}.drawer *,.drawer *:before,.drawer *:after{box-sizing:border-box}.header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px 12px;border-bottom:1px solid var(--nha-border);padding:12px 12px 12px 16px}.heading{display:contents}nh-assistant-agent-picker{grid-column:1/-1;grid-row:2}h2{grid-row:1;min-width:0;margin:0;overflow:hidden;font-size:16px;font-weight:750;letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap}.header-actions{display:flex;flex:none;grid-column:2;grid-row:1;gap:4px}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;text-decoration:none}.icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.icon-button:disabled{cursor:not-allowed;opacity:.5}.icon-button.active{color:var(--nha-highlight);background:var(--nha-surface-strong)}.body{position:relative;display:flex;flex:1;flex-direction:column;min-height:0;background:var(--nha-background)}.thread{flex:1;min-height:0}.overlay-view{position:absolute;z-index:1;inset:0;border-bottom:1px solid var(--nha-border);background:var(--nha-background)}.state{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:24px;color:var(--nha-text-muted);text-align:center}.state p{max-width:32ch;margin:0;font-size:13px}.state-icon{margin-bottom:8px;color:var(--nha-highlight);font-size:28px}.state .state-title{color:var(--nha-text);font-size:15px;font-weight:700}.error{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-danger);background:var(--nha-danger-soft)}.error p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.turn-notice{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-warning);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-warning);background:var(--nha-warning-soft)}.turn-notice p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.footer{border-top:1px solid var(--nha-border);padding:12px 16px 14px}.context-chip{display:flex;align-items:center;gap:6px;max-width:100%;margin:0 0 8px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;width:fit-content;color:var(--nha-text-muted);background:var(--nha-surface);font-size:12px}.context-chip.excluded .context-text{text-decoration:line-through}.context-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-button.small{flex:none;width:26px;height:26px;border-radius:999px}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAgentPickerComponent, selector: "nh-assistant-agent-picker", inputs: ["agents", "selectedAgentId", "disabled"], outputs: ["agentChange"] }, { kind: "component", type: NhAssistantComposerComponent, selector: "nh-assistant-composer", inputs: ["disabled", "sendDisabled", "busy", "status", "maxLength", "restore"], outputs: ["send", "cancel", "restored"] }, { kind: "component", type: NhAssistantConversationListComponent, selector: "nh-assistant-conversation-list", inputs: ["conversations", "total", "activeConversationId", "loading", "disabled"], outputs: ["conversationSelect", "conversationDelete", "conversationCreate"] }, { kind: "component", type: NhAssistantPreferencesComponent, selector: "nh-assistant-preferences", outputs: ["closed", "saved"] }, { kind: "component", type: NhAssistantThreadComponent, selector: "nh-assistant-thread", inputs: ["messages", "streaming", "deciding", "markdown"], outputs: ["approvalDecision"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3378
3590
|
}
|
|
3379
3591
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhAssistantPanelComponent, decorators: [{
|
|
3380
3592
|
type: Component,
|
|
@@ -3388,7 +3600,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
3388
3600
|
NhAssistantConversationListComponent,
|
|
3389
3601
|
NhAssistantPreferencesComponent,
|
|
3390
3602
|
NhAssistantThreadComponent
|
|
3391
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #drawer>\n <section class=\"drawer\" role=\"dialog\" aria-modal=\"false\" [attr.aria-labelledby]=\"titleId\">\n <header class=\"header\">\n <div class=\"heading\">\n <h2 [id]=\"titleId\">{{ 'nh-assistant.panel.title' | translate }}</h2>\n @if (store.enabled()) {\n <nh-assistant-agent-picker\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n [disabled]=\"store.streaming()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showConversations()\"\n [attr.aria-expanded]=\"showConversations()\"\n [attr.aria-label]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n [attr.title]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n (click)=\"toggleConversations()\">\n <nh-assistant-icon name=\"list\" />\n </button>\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showPreferences()\"\n [attr.aria-expanded]=\"showPreferences()\"\n [attr.aria-label]=\"'nh-assistant.panel.open-preferences' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-preferences' | translate\"\n (click)=\"togglePreferences()\">\n <nh-assistant-icon name=\"settings\" />\n </button>\n @if (adminRoute && store.canAdminister()) {\n <a\n class=\"icon-button\"\n [routerLink]=\"adminRoute\"\n [attr.aria-label]=\"'nh-assistant.panel.open-admin' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-admin' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"admin\" />\n </a>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [disabled]=\"store.streaming()\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"newConversation()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.close' | translate\"\n [attr.title]=\"'nh-assistant.panel.close' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n </header>\n\n <div class=\"body\">\n @if (store.statusLoading() && !store.enabled()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.panel.loading' | translate }}</p>\n </div>\n } @else if (!store.enabled()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"warning\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.unavailable-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.unavailable-description' | translate }}</p>\n </div>\n } @else {\n @if (showPreferences()) {\n <nh-assistant-preferences class=\"overlay-view\" (closed)=\"showPreferences.set(false)\" />\n }\n\n @if (showConversations()) {\n <nh-assistant-conversation-list\n class=\"overlay-view\"\n [conversations]=\"store.conversations()\"\n [total]=\"store.conversationsTotal()\"\n [activeConversationId]=\"conversation()?.id ?? null\"\n [loading]=\"store.conversationsLoading()\"\n [disabled]=\"store.streaming()\"\n (conversationSelect)=\"openConversation($event)\"\n (conversationDelete)=\"deleteConversation($event)\"\n (conversationCreate)=\"newConversation()\" />\n }\n\n @if (store.conversationLoading()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.thread.loading' | translate }}</p>\n </div>\n } @else if (messages().length === 0 && !store.streaming()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"assistant\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.empty-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.empty-description' | translate }}</p>\n </div>\n } @else {\n <nh-assistant-thread\n class=\"thread\"\n [messages]=\"messages()\"\n [streaming]=\"store.streaming()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n (approvalDecision)=\"decide($event)\" />\n }\n }\n </div>\n\n @if (store.error(); as error) {\n <div class=\"error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ errorKeys() | nhAssistantTranslate: error.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearError()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n }\n\n @if (store.enabled() && !showPreferences()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n }\n @if (store.pageContext(); as context) {\n <div class=\"context-chip\" [class.excluded]=\"store.pageContextExcluded()\" [attr.title]=\"context.route\">\n <nh-assistant-icon name=\"page\" />\n <span class=\"context-text\">\n {{ (store.pageContextExcluded() ? 'nh-assistant.page-context.excluded' : 'nh-assistant.page-context.included') | translate: { page: describeContext(context) } }}\n </span>\n <button\n class=\"icon-button small\"\n type=\"button\"\n [attr.aria-pressed]=\"store.pageContextExcluded()\"\n [attr.aria-label]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n [attr.title]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n (click)=\"store.setPageContextExcluded(!store.pageContextExcluded())\">\n <nh-assistant-icon [name]=\"store.pageContextExcluded() ? 'plus' : 'x'\" />\n </button>\n </div>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [status]=\"composerStatus()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\" />\n </footer>\n }\n </section>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}.drawer{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){.drawer{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:contents}.drawer{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;border-left:1px solid var(--nha-border);color:var(--nha-text);background:var(--nha-background);box-shadow:var(--nha-shadow);font-family:var(--nha-font);font-size:14px}.drawer *,.drawer *:before,.drawer *:after{box-sizing:border-box}.header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px 12px;border-bottom:1px solid var(--nha-border);padding:12px 12px 12px 16px}.heading{display:contents}nh-assistant-agent-picker{grid-column:1/-1;grid-row:2}h2{grid-row:1;min-width:0;margin:0;overflow:hidden;font-size:16px;font-weight:750;letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap}.header-actions{display:flex;flex:none;grid-column:2;grid-row:1;gap:4px}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;text-decoration:none}.icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.icon-button:disabled{cursor:not-allowed;opacity:.5}.icon-button.active{color:var(--nha-highlight);background:var(--nha-surface-strong)}.body{position:relative;display:flex;flex:1;flex-direction:column;min-height:0;background:var(--nha-background)}.thread{flex:1;min-height:0}.overlay-view{position:absolute;z-index:1;inset:0;border-bottom:1px solid var(--nha-border);background:var(--nha-background)}.state{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:24px;color:var(--nha-text-muted);text-align:center}.state p{max-width:32ch;margin:0;font-size:13px}.state-icon{margin-bottom:8px;color:var(--nha-highlight);font-size:28px}.state .state-title{color:var(--nha-text);font-size:15px;font-weight:700}.error{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-danger);background:var(--nha-danger-soft)}.error p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.footer{border-top:1px solid var(--nha-border);padding:12px 16px 14px}.context-chip{display:flex;align-items:center;gap:6px;max-width:100%;margin:0 0 8px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;width:fit-content;color:var(--nha-text-muted);background:var(--nha-surface);font-size:12px}.context-chip.excluded .context-text{text-decoration:line-through}.context-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-button.small{flex:none;width:26px;height:26px;border-radius:999px}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"] }]
|
|
3603
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #drawer>\n <section class=\"drawer\" role=\"dialog\" aria-modal=\"false\" [attr.aria-labelledby]=\"titleId\">\n <header class=\"header\">\n <div class=\"heading\">\n <h2 [id]=\"titleId\">{{ 'nh-assistant.panel.title' | translate }}</h2>\n @if (store.enabled()) {\n <nh-assistant-agent-picker\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n [disabled]=\"store.streaming()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showConversations()\"\n [attr.aria-expanded]=\"showConversations()\"\n [attr.aria-label]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n [attr.title]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n (click)=\"toggleConversations()\">\n <nh-assistant-icon name=\"list\" />\n </button>\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showPreferences()\"\n [attr.aria-expanded]=\"showPreferences()\"\n [attr.aria-label]=\"'nh-assistant.panel.open-preferences' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-preferences' | translate\"\n (click)=\"togglePreferences()\">\n <nh-assistant-icon name=\"settings\" />\n </button>\n @if (adminRoute && store.canAdminister()) {\n <a\n class=\"icon-button\"\n [routerLink]=\"adminRoute\"\n [attr.aria-label]=\"'nh-assistant.panel.open-admin' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-admin' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"admin\" />\n </a>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [disabled]=\"store.streaming()\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"newConversation()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.close' | translate\"\n [attr.title]=\"'nh-assistant.panel.close' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n </header>\n\n <div class=\"body\">\n @if (store.statusLoading() && !store.enabled()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.panel.loading' | translate }}</p>\n </div>\n } @else if (!store.enabled()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"warning\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.unavailable-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.unavailable-description' | translate }}</p>\n </div>\n } @else {\n @if (showPreferences()) {\n <nh-assistant-preferences class=\"overlay-view\" (closed)=\"showPreferences.set(false)\" />\n }\n\n @if (showConversations()) {\n <nh-assistant-conversation-list\n class=\"overlay-view\"\n [conversations]=\"store.conversations()\"\n [total]=\"store.conversationsTotal()\"\n [activeConversationId]=\"conversation()?.id ?? null\"\n [loading]=\"store.conversationsLoading()\"\n [disabled]=\"store.streaming()\"\n (conversationSelect)=\"openConversation($event)\"\n (conversationDelete)=\"deleteConversation($event)\"\n (conversationCreate)=\"newConversation()\" />\n }\n\n @if (store.conversationLoading()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.thread.loading' | translate }}</p>\n </div>\n } @else if (messages().length === 0 && !store.streaming()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"assistant\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.empty-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.empty-description' | translate }}</p>\n </div>\n } @else {\n <nh-assistant-thread\n class=\"thread\"\n [messages]=\"messages()\"\n [streaming]=\"store.streaming()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n (approvalDecision)=\"decide($event)\" />\n }\n }\n </div>\n\n @if (store.error(); as error) {\n <div class=\"error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ errorKeys() | nhAssistantTranslate: error.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearError()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n } @else if (store.notice(); as notice) {\n <div class=\"turn-notice\" role=\"status\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ noticeKeys() | nhAssistantTranslate: notice.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearNotice()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n }\n\n @if (store.enabled() && !showPreferences()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n }\n @if (store.pageContext(); as context) {\n <div class=\"context-chip\" [class.excluded]=\"store.pageContextExcluded()\" [attr.title]=\"context.route\">\n <nh-assistant-icon name=\"page\" />\n <span class=\"context-text\">\n {{ (store.pageContextExcluded() ? 'nh-assistant.page-context.excluded' : 'nh-assistant.page-context.included') | translate: { page: describeContext(context) } }}\n </span>\n <button\n class=\"icon-button small\"\n type=\"button\"\n [attr.aria-pressed]=\"store.pageContextExcluded()\"\n [attr.aria-label]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n [attr.title]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n (click)=\"store.setPageContextExcluded(!store.pageContextExcluded())\">\n <nh-assistant-icon [name]=\"store.pageContextExcluded() ? 'plus' : 'x'\" />\n </button>\n </div>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [status]=\"composerStatus()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\" />\n </footer>\n }\n </section>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}.drawer{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){.drawer{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:contents}.drawer{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;border-left:1px solid var(--nha-border);color:var(--nha-text);background:var(--nha-background);box-shadow:var(--nha-shadow);font-family:var(--nha-font);font-size:14px}.drawer *,.drawer *:before,.drawer *:after{box-sizing:border-box}.header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px 12px;border-bottom:1px solid var(--nha-border);padding:12px 12px 12px 16px}.heading{display:contents}nh-assistant-agent-picker{grid-column:1/-1;grid-row:2}h2{grid-row:1;min-width:0;margin:0;overflow:hidden;font-size:16px;font-weight:750;letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap}.header-actions{display:flex;flex:none;grid-column:2;grid-row:1;gap:4px}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;text-decoration:none}.icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.icon-button:disabled{cursor:not-allowed;opacity:.5}.icon-button.active{color:var(--nha-highlight);background:var(--nha-surface-strong)}.body{position:relative;display:flex;flex:1;flex-direction:column;min-height:0;background:var(--nha-background)}.thread{flex:1;min-height:0}.overlay-view{position:absolute;z-index:1;inset:0;border-bottom:1px solid var(--nha-border);background:var(--nha-background)}.state{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:24px;color:var(--nha-text-muted);text-align:center}.state p{max-width:32ch;margin:0;font-size:13px}.state-icon{margin-bottom:8px;color:var(--nha-highlight);font-size:28px}.state .state-title{color:var(--nha-text);font-size:15px;font-weight:700}.error{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-danger);background:var(--nha-danger-soft)}.error p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.turn-notice{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-warning);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-warning);background:var(--nha-warning-soft)}.turn-notice p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.footer{border-top:1px solid var(--nha-border);padding:12px 16px 14px}.context-chip{display:flex;align-items:center;gap:6px;max-width:100%;margin:0 0 8px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;width:fit-content;color:var(--nha-text-muted);background:var(--nha-surface);font-size:12px}.context-chip.excluded .context-text{text-decoration:line-through}.context-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-button.small{flex:none;width:26px;height:26px;border-radius:999px}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"] }]
|
|
3392
3604
|
}], ctorParameters: () => [], propDecorators: { drawer: [{ type: i0.ViewChild, args: ['drawer', { isSignal: true }] }] } });
|
|
3393
3605
|
|
|
3394
3606
|
/** Converts any failure into a user-facing code and translation key, never raw text. */
|
|
@@ -3413,5 +3625,5 @@ const NH_ASSISTANT_DASH_CASE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
|
3413
3625
|
* Generated bundle index. Do not edit.
|
|
3414
3626
|
*/
|
|
3415
3627
|
|
|
3416
|
-
export { NH_ASSISTANT_ACCESS_POLICY, NH_ASSISTANT_CONFIG, NH_ASSISTANT_FETCH, NH_ASSISTANT_ICONS, NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS, NH_ASSISTANT_PAGE_CONTEXT_LIMITS, NH_ASSISTANT_PANEL_MOBILE_QUERY, NH_ASSISTANT_PANEL_WIDTH, NH_ASSISTANT_SSE_EVENT_TYPES, NH_ASSISTANT_TRANSLATIONS, NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD, NhAssistantAdminApiService, NhAssistantAgentPickerComponent, NhAssistantAllowAllAccessPolicy, NhAssistantApiError, NhAssistantApiService, NhAssistantApprovalCardComponent, NhAssistantClientErrorCodes, NhAssistantComposerComponent, NhAssistantConversationListComponent, NhAssistantLauncherComponent, NhAssistantPanelComponent, NhAssistantPanelService, NhAssistantPreferencesComponent, NhAssistantSseParser, NhAssistantStore, NhAssistantThreadComponent, NhAssistantToolCallCardComponent, NhAssistantTranslationMerger, applyNhAssistantApprovalDecision, applyNhAssistantEvent, describeNhAssistantClientContext, formatNhAssistantCountdown, nhAssistantCodeForStatus, nhAssistantErrorMessageKey, normalizeNhAssistantClientContext, provideNhAssistant, NH_ASSISTANT_DASH_CASE as ɵNH_ASSISTANT_DASH_CASE, NhAssistantIconComponent as ɵNhAssistantIconComponent, NhAssistantTranslatePipe as ɵNhAssistantTranslatePipe, nhAssistantErrorKeys as ɵnhAssistantErrorKeys, toNhAssistantError as ɵtoNhAssistantError };
|
|
3628
|
+
export { NH_ASSISTANT_ACCESS_POLICY, NH_ASSISTANT_CONFIG, NH_ASSISTANT_FETCH, NH_ASSISTANT_ICONS, NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS, NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, NH_ASSISTANT_PAGE_CONTEXT_LIMITS, NH_ASSISTANT_PANEL_MOBILE_QUERY, NH_ASSISTANT_PANEL_WIDTH, NH_ASSISTANT_SSE_EVENT_TYPES, NH_ASSISTANT_TRANSLATIONS, NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD, NhAssistantAdminApiService, NhAssistantAgentPickerComponent, NhAssistantAllowAllAccessPolicy, NhAssistantApiError, NhAssistantApiService, NhAssistantApprovalCardComponent, NhAssistantClientErrorCodes, NhAssistantComposerComponent, NhAssistantConversationListComponent, NhAssistantLauncherComponent, NhAssistantPanelComponent, NhAssistantPanelService, NhAssistantPreferencesComponent, NhAssistantSseParser, NhAssistantStore, NhAssistantThreadComponent, NhAssistantToolCallCardComponent, NhAssistantToolCallGroupComponent, NhAssistantTranslationMerger, applyNhAssistantApprovalDecision, applyNhAssistantEvent, describeNhAssistantClientContext, formatNhAssistantCountdown, nhAssistantCodeForStatus, nhAssistantErrorMessageKey, nhAssistantLatestTurnHasText, normalizeNhAssistantClientContext, provideNhAssistant, NH_ASSISTANT_DASH_CASE as ɵNH_ASSISTANT_DASH_CASE, NhAssistantIconComponent as ɵNhAssistantIconComponent, NhAssistantTranslatePipe as ɵNhAssistantTranslatePipe, nhAssistantErrorKeys as ɵnhAssistantErrorKeys, toNhAssistantError as ɵtoNhAssistantError };
|
|
3417
3629
|
//# sourceMappingURL=newheap-platform-ai-chat.mjs.map
|