@newheap/platform-ai-chat 0.12.0 → 0.14.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.
@@ -123,6 +123,7 @@ var en = {
123
123
  "empty-title": "How can I help?",
124
124
  "empty-description": "Ask a question or describe a task. Actions that change data always ask for your approval first.",
125
125
  "conversation-closed": "This conversation cannot continue. Start a new conversation.",
126
+ "last-turn-failed": "The last answer could not be completed. Send your message again to continue.",
126
127
  "dismiss-error": "Dismiss message",
127
128
  usage: "{{inputTokens}} input tokens, {{outputTokens}} output tokens, {{toolCalls}} tool calls",
128
129
  "open-preferences": "Your assistant preferences",
@@ -223,7 +224,9 @@ var en = {
223
224
  "delegated-read": "Read with a person's rights",
224
225
  "delegated-hint": "The agent used the rights of the person who started it.",
225
226
  "agent-hint": "The agent used a right it was granted itself, beyond the rights of the people involved.",
226
- "delegated-read-hint": "The agent read this through the application's data gateway with the rights of the person who started it, or else of the person it works for. Only that person sees the result."
227
+ "delegated-read-hint": "The agent read this through the application's data gateway with the rights of the person who started it, or else of the person it works for. Only that person sees the result.",
228
+ accountable: "Rights of whom it works for",
229
+ "accountable-hint": "The agent used the rights of the person or technical account it works for. Only people with the same rights see the result."
227
230
  },
228
231
  restricted: "Shielded: the agent obtained this with rights you do not have."
229
232
  },
@@ -444,7 +447,19 @@ var en = {
444
447
  "assistant-consult-limit-reached": "You reached the daily number of consultations.",
445
448
  "assistant-consult-timeout": "The agent did not answer in time.",
446
449
  "assistant-consult-failed": "The agent could not answer.",
447
- "assistant-consult-read-only": "A consultation cannot change anything."
450
+ "assistant-consult-read-only": "A consultation cannot change anything.",
451
+ "assistant-moved-to-shadow": "The work went to the agent's shadow thread, where a run in shadow takes it.",
452
+ "assistant-shadow-variant": "A shadow variant always works in shadow.",
453
+ "assistant-service-account-not-used": "This agent does not answer to a technical account.",
454
+ "assistant-service-account-not-found": "No account that may sign in exists with this id.",
455
+ "assistant-skill-in-code": "This skill is part of the code and cannot change here.",
456
+ "assistant-trigger-in-code": "This trigger is part of the code and cannot change here.",
457
+ "assistant-skill-in-use": "A trigger still starts this skill. Change or remove the trigger first.",
458
+ "assistant-configuration-limit": "This agent already has as many skills or triggers as allowed.",
459
+ "assistant-run-settings-in-code": "This agent is part of the code; its runs are configured there.",
460
+ "assistant-run-settings-in-use": "Skills or triggers still belong to this agent. Remove them first.",
461
+ "assistant-skill-candidate-not-found": "This skill has no version being evaluated in shadow.",
462
+ "assistant-skill-version-gone": "The skill version this run was for is no longer evaluated."
448
463
  },
449
464
  notices: {
450
465
  "no-answer": "The assistant finished without an answer. Try again or rephrase your question.",
@@ -597,7 +612,51 @@ var en = {
597
612
  paused: "The skill {{skill}} starts no new runs: its events wait, triage no longer chooses it and running work finishes. The other skills keep working.",
598
613
  stopped: "The runs of the skill {{skill}} are cancelled and its waiting events dropped; its triggers are refused. The other skills keep working."
599
614
  }
600
- }
615
+ },
616
+ shadow: {
617
+ badge: "Shadow",
618
+ hint: "Its work goes to shadow threads that only administrators see.",
619
+ changed: "Shadow mode set by {{user}} on {{date}}.",
620
+ locked: "A shadow variant always works in shadow.",
621
+ action: {
622
+ shadow: "Put in shadow",
623
+ live: "Put live",
624
+ code: "Follow the code"
625
+ },
626
+ explain: {
627
+ shadow: "New runs work in shadow threads that only administrators see: nobody is notified and nothing proposed there executes. Running work finishes as it started; the live threads and their open proposals stay.",
628
+ live: "New runs work live: people see them, are notified and decide their proposals.",
629
+ code: "The mode in code decides again."
630
+ },
631
+ "skill-explain": {
632
+ shadow: "Work that reaches the skill {{skill}} goes to the shadow threads; the other skills keep their mode.",
633
+ live: "The skill {{skill}} works live again, unless its agent works in shadow.",
634
+ code: "The mode in code decides again for the skill {{skill}}."
635
+ },
636
+ confirm: {
637
+ shadow: "Confirm shadow",
638
+ live: "Confirm live",
639
+ code: "Confirm"
640
+ }
641
+ },
642
+ "service-account": {
643
+ label: "Technical account: {{account}}",
644
+ configured: "In code: {{account}}",
645
+ "input-label": "Account id",
646
+ action: {
647
+ set: "Change technical account",
648
+ code: "Use the account in code"
649
+ },
650
+ explain: {
651
+ set: "New runs answer to this account and use its rights. Runs that started and their proposals keep their account.",
652
+ code: "New runs answer to the account in code again: {{account}}."
653
+ },
654
+ confirm: {
655
+ set: "Confirm account",
656
+ code: "Confirm"
657
+ }
658
+ },
659
+ "run-config": "Run configuration"
601
660
  },
602
661
  "agent-editor": {
603
662
  "new-title": "New agent",
@@ -835,6 +894,180 @@ var en = {
835
894
  stopped: "Stopped"
836
895
  },
837
896
  "replay-progress": "{{replayed}} of at most {{max}} runs replayed, {{skipped}} skipped"
897
+ },
898
+ "run-config": {
899
+ back: "Back to agents",
900
+ title: "Run configuration of {{name}}",
901
+ description: "Skills and triggers that the administration adds without a deploy, made of the building blocks the application registers. New skills and triggers start in shadow, where nobody is notified and nothing executes.",
902
+ problems: {
903
+ title: "Some settings no longer fit the application and are out of effect:",
904
+ kind: {
905
+ agent: "Run settings:",
906
+ skill: "Skill {{id}}:",
907
+ candidate: "Candidate of skill {{id}}:",
908
+ trigger: "Trigger {{id}}:"
909
+ },
910
+ code: {
911
+ "unknown-agent": "the agent can no longer run on its own.",
912
+ "conflicts-with-code": "the application now declares one with the same id.",
913
+ "too-many-skills": "the agent has more skills than allowed.",
914
+ "tool-not-covered": "a tool is outside the agent's own tools.",
915
+ "unknown-profile": "the model profile no longer exists.",
916
+ "unknown-policy": "the approval policy no longer exists.",
917
+ "unknown-rule-handler": "the rules no longer exist.",
918
+ "unknown-event": "the event no longer exists.",
919
+ "unknown-subject-set": "the set of subjects no longer exists.",
920
+ "unknown-skill": "the skill no longer exists.",
921
+ "invalid-schedule": "the schedule or its time zone is not valid.",
922
+ invalid: "a value is not valid."
923
+ }
924
+ },
925
+ "field-errors": {
926
+ required: "Required.",
927
+ invalid: "Not valid here.",
928
+ "too-long": "Too long.",
929
+ "not-found": "The application does not know this name."
930
+ },
931
+ settings: {
932
+ title: "Run settings",
933
+ empty: "This agent only chats. Give it run settings to let it work on its own, with skills and triggers.",
934
+ rights: "It has no rights of its own: in runs without a person it uses what the account it answers to may use, within its tools.",
935
+ add: "Add run settings",
936
+ edit: "Change run settings",
937
+ remove: "Remove run settings",
938
+ "remove-explain": "The agent then only chats. Remove its skills and triggers first.",
939
+ saved: "The run settings are saved.",
940
+ removed: "The agent only chats again.",
941
+ "accountability-label": "Answers to",
942
+ accountability: {
943
+ agent: "The agent itself",
944
+ "subject-responsible": "The person responsible for the subject",
945
+ "service-account": "A technical account"
946
+ },
947
+ "accountability-hint": "The agent acts with this account's rights. An agent that answers to itself has none and can only propose.",
948
+ "service-account": "Technical account",
949
+ triage: "Triage profile",
950
+ "triage-hint": "A cheap model that chooses the skill of a run that no trigger or rule routed.",
951
+ retries: "Retries after a failure",
952
+ "max-concurrent": "Runs at the same time",
953
+ "max-per-subject": "Runs per subject per day",
954
+ "elevated-reads": "Reads with the account's rights",
955
+ elevated: {
956
+ restricted: "Shield from readers without the right",
957
+ deny: "Refuse"
958
+ },
959
+ "gateway-reads": "Read through the application's data gateway with the account's rights",
960
+ delegate: "Also use what the person who starts a run may use"
961
+ },
962
+ "rule-handler": "Rules",
963
+ "rule-handler-value": "Rules: {{name}}",
964
+ "policy-value": "Approval: {{name}}",
965
+ "profile-value": "Model: {{name}}",
966
+ "approval-policy": "Approval policy",
967
+ model: "The model, no rules",
968
+ none: "None",
969
+ choose: "Choose…",
970
+ "max-tokens": "Tokens per run",
971
+ "daily-tool-calls": "Tool calls per day",
972
+ "daily-tokens": "Tokens per day",
973
+ "budget-hint": "Leave empty for no limit. A daily budget needs both tool calls and tokens.",
974
+ "out-of-effect": "Out of effect",
975
+ changed: "Changed by {{user}} on {{date}}.",
976
+ "needs-settings": "Give the agent run settings before you add skills and triggers.",
977
+ skills: {
978
+ description: "Skills in code come from the application. Skills added here have versions; a change goes live at once or runs in shadow next to the live version first.",
979
+ add: "Add skill",
980
+ added: "The skill is added. It starts in shadow; put it live from the agent's list.",
981
+ saved: "The new version of the skill is live.",
982
+ "saved-candidate": "The new version runs in shadow next to the live version.",
983
+ removed: "The skill is removed; its versions stay as history.",
984
+ empty: "The agent has no skills yet.",
985
+ "new-title": "New skill",
986
+ "edit-title": "Change skill {{skill}} (version {{version}})",
987
+ id: "Skill id",
988
+ "id-hint": "Lowercase letters, digits and dashes, such as progress-note.",
989
+ "description-label": "What the skill is for",
990
+ "description-hint": "Triage and the model choose the skill by this description.",
991
+ instructions: "Instructions",
992
+ "instructions-hint": "Read after the agent's own instructions while it works in the skill.",
993
+ tools: "Tools",
994
+ "tools-hint": "Narrow the agent's tools for this skill. None selected: the agent's tools.",
995
+ profile: "Model profile",
996
+ "agent-profile": "The agent's profile",
997
+ "agent-policy": "The agent's policy",
998
+ apply: "How the change takes effect",
999
+ "apply-shadow": "Evaluate in shadow next to the live version first",
1000
+ "apply-live": "Put live at once",
1001
+ "starts-in-shadow": "A new skill starts in shadow.",
1002
+ versions: "Versions",
1003
+ "remove-explain": "Its versions stay as history. A trigger that starts it must go first."
1004
+ },
1005
+ candidate: {
1006
+ badge: "Candidate v{{version}}",
1007
+ explain: "Version {{version}} runs in shadow next to the live version on the same events: {{description}}",
1008
+ compare: "Compare",
1009
+ promote: "Promote",
1010
+ "confirm-promote": "Confirm promote",
1011
+ discard: "Discard",
1012
+ "confirm-discard": "Confirm discard",
1013
+ promoted: "The candidate is the live version now.",
1014
+ discarded: "The candidate is discarded; it stays as history.",
1015
+ comparison: "Live version and candidate of {{skill}}",
1016
+ "live-column": "Live (v{{version}})",
1017
+ "candidate-column": "Candidate (v{{version}})",
1018
+ runs: "Runs",
1019
+ completed: "Completed",
1020
+ failed: "Failed",
1021
+ proposals: "Proposals",
1022
+ tokens: "Tokens",
1023
+ paired: "Both handled {{count}} of the same events since {{date}}."
1024
+ },
1025
+ status: {
1026
+ live: "Live",
1027
+ candidate: "Candidate",
1028
+ superseded: "Earlier",
1029
+ discarded: "Discarded"
1030
+ },
1031
+ triggers: {
1032
+ title: "Triggers",
1033
+ description: "Triggers in code come from the application. Triggers added here start the agent on the application's events or on a schedule.",
1034
+ add: "Add trigger",
1035
+ added: "The trigger is added. It starts in shadow.",
1036
+ saved: "The trigger is saved.",
1037
+ removed: "The trigger is removed.",
1038
+ live: "The trigger works live.",
1039
+ "in-shadow": "The trigger works in shadow.",
1040
+ empty: "No triggers start the agent yet.",
1041
+ "new-title": "New trigger",
1042
+ "edit-title": "Change trigger {{trigger}}",
1043
+ id: "Trigger id",
1044
+ source: "Starts on",
1045
+ "source-event": "An event of the application",
1046
+ "source-schedule": "A schedule",
1047
+ event: "Event",
1048
+ debounce: "Wait for more events (seconds)",
1049
+ cron: "Schedule (cron)",
1050
+ "cron-hint": "Five fields, such as 0 7 * * 1 for Mondays at seven.",
1051
+ "time-zone": "Time zone",
1052
+ "subject-set": "Subjects",
1053
+ message: "Message to every run",
1054
+ skill: "Skill",
1055
+ "agent-routes": "The agent chooses the skill",
1056
+ "skill-value": "Skill: {{skill}}",
1057
+ conflict: "While a run is busy",
1058
+ conflicts: {
1059
+ coalesce: "Merge into the waiting run",
1060
+ queue: "Wait for the run",
1061
+ supersede: "Replace the run",
1062
+ ignore: "Skip"
1063
+ },
1064
+ sources: {
1065
+ event: "Event",
1066
+ schedule: "Schedule",
1067
+ webhook: "Webhook"
1068
+ },
1069
+ "starts-in-shadow": "A new trigger starts in shadow."
1070
+ }
838
1071
  }
839
1072
  },
840
1073
  "page-context": {
@@ -917,7 +1150,8 @@ var en = {
917
1150
  ignored: "The agent is busy; nothing was started.",
918
1151
  deduplicated: "This was already started.",
919
1152
  rejected: "The agent could not be started."
920
- }
1153
+ },
1154
+ shadow: "Shadow thread: only administrators see it, and nothing proposed here executes."
921
1155
  },
922
1156
  subject: {
923
1157
  title: "Agent suggestions",
@@ -1075,6 +1309,7 @@ var nl = {
1075
1309
  "empty-title": "Waarmee kan ik helpen?",
1076
1310
  "empty-description": "Stel een vraag of beschrijf een taak. Acties die gegevens wijzigen vragen altijd eerst om je goedkeuring.",
1077
1311
  "conversation-closed": "Dit gesprek kan niet verder. Begin een nieuw gesprek.",
1312
+ "last-turn-failed": "Het laatste antwoord kon niet worden afgemaakt. Stuur je bericht opnieuw om verder te gaan.",
1078
1313
  "dismiss-error": "Melding sluiten",
1079
1314
  usage: "{{inputTokens}} invoertokens, {{outputTokens}} uitvoertokens, {{toolCalls}} toolaanroepen",
1080
1315
  "open-preferences": "Je assistentvoorkeuren",
@@ -1175,7 +1410,9 @@ var nl = {
1175
1410
  "delegated-read": "Gelezen met rechten van een persoon",
1176
1411
  "delegated-hint": "De agent gebruikte de rechten van de persoon die hem startte.",
1177
1412
  "agent-hint": "De agent gebruikte een recht dat hij zelf heeft gekregen, boven de rechten van de betrokkenen uit.",
1178
- "delegated-read-hint": "De agent las dit via de datagateway van de applicatie met de rechten van wie hem startte, of anders van degene voor wie hij werkt. Alleen die persoon ziet het resultaat."
1413
+ "delegated-read-hint": "De agent las dit via de datagateway van de applicatie met de rechten van wie hem startte, of anders van degene voor wie hij werkt. Alleen die persoon ziet het resultaat.",
1414
+ accountable: "Rechten van wie hij voor werkt",
1415
+ "accountable-hint": "De agent gebruikte de rechten van de persoon of het technische account voor wie hij werkt. Alleen mensen met dezelfde rechten zien het resultaat."
1179
1416
  },
1180
1417
  restricted: "Afgeschermd: de agent kreeg dit met rechten die jij niet hebt."
1181
1418
  },
@@ -1396,7 +1633,19 @@ var nl = {
1396
1633
  "assistant-consult-limit-reached": "Je hebt het aantal raadplegingen voor vandaag bereikt.",
1397
1634
  "assistant-consult-timeout": "De agent antwoordde niet op tijd.",
1398
1635
  "assistant-consult-failed": "De agent kon niet antwoorden.",
1399
- "assistant-consult-read-only": "Een raadpleging kan niets wijzigen."
1636
+ "assistant-consult-read-only": "Een raadpleging kan niets wijzigen.",
1637
+ "assistant-moved-to-shadow": "Het werk is naar de schaduwthread van de agent gegaan, waar een run in schaduw het oppakt.",
1638
+ "assistant-shadow-variant": "Een schaduwvariant werkt altijd in schaduw.",
1639
+ "assistant-service-account-not-used": "Deze agent werkt niet onder een technisch account.",
1640
+ "assistant-service-account-not-found": "Er bestaat geen account met deze id dat mag inloggen.",
1641
+ "assistant-skill-in-code": "Deze vaardigheid staat in de code en kan hier niet veranderen.",
1642
+ "assistant-trigger-in-code": "Deze trigger staat in de code en kan hier niet veranderen.",
1643
+ "assistant-skill-in-use": "Een trigger start deze vaardigheid nog. Pas de trigger eerst aan of verwijder hem.",
1644
+ "assistant-configuration-limit": "Deze agent heeft al zoveel vaardigheden of triggers als is toegestaan.",
1645
+ "assistant-run-settings-in-code": "Deze agent staat in de code; daar is ingesteld hoe hij werkt.",
1646
+ "assistant-run-settings-in-use": "Er horen nog vaardigheden of triggers bij deze agent. Verwijder die eerst.",
1647
+ "assistant-skill-candidate-not-found": "Van deze vaardigheid wordt geen versie in schaduw beoordeeld.",
1648
+ "assistant-skill-version-gone": "De versie van de vaardigheid waarvoor deze run was, wordt niet meer beoordeeld."
1400
1649
  },
1401
1650
  notices: {
1402
1651
  "no-answer": "De assistent is klaar zonder antwoord. Probeer het opnieuw of stel je vraag anders.",
@@ -1549,7 +1798,51 @@ var nl = {
1549
1798
  paused: "De vaardigheid {{skill}} start geen nieuwe runs: haar gebeurtenissen wachten, triage kiest haar niet meer en lopend werk wordt afgemaakt. De andere vaardigheden werken door.",
1550
1799
  stopped: "De runs van de vaardigheid {{skill}} worden geannuleerd en haar wachtende gebeurtenissen vervallen; haar triggers worden geweigerd. De andere vaardigheden werken door."
1551
1800
  }
1552
- }
1801
+ },
1802
+ shadow: {
1803
+ badge: "Schaduw",
1804
+ hint: "Het werk gaat naar schaduwthreads die alleen beheerders zien.",
1805
+ changed: "Schaduwmodus ingesteld door {{user}} op {{date}}.",
1806
+ locked: "Een schaduwvariant werkt altijd in schaduw.",
1807
+ action: {
1808
+ shadow: "In schaduw zetten",
1809
+ live: "Live zetten",
1810
+ code: "Code laten beslissen"
1811
+ },
1812
+ explain: {
1813
+ shadow: "Nieuwe runs werken in schaduwthreads die alleen beheerders zien: niemand krijgt een melding en niets wat daar wordt voorgesteld, wordt uitgevoerd. Lopend werk wordt afgemaakt zoals het begon; de live threads en hun open voorstellen blijven.",
1814
+ live: "Nieuwe runs werken live: mensen zien ze, krijgen meldingen en beslissen over de voorstellen.",
1815
+ code: "De modus in de code beslist weer."
1816
+ },
1817
+ "skill-explain": {
1818
+ shadow: "Werk dat bij de vaardigheid {{skill}} komt, gaat naar de schaduwthreads; de andere vaardigheden houden hun modus.",
1819
+ live: "De vaardigheid {{skill}} werkt weer live, tenzij haar agent in schaduw werkt.",
1820
+ code: "De modus in de code beslist weer voor de vaardigheid {{skill}}."
1821
+ },
1822
+ confirm: {
1823
+ shadow: "Schaduw bevestigen",
1824
+ live: "Live bevestigen",
1825
+ code: "Bevestigen"
1826
+ }
1827
+ },
1828
+ "service-account": {
1829
+ label: "Technisch account: {{account}}",
1830
+ configured: "In de code: {{account}}",
1831
+ "input-label": "Account-id",
1832
+ action: {
1833
+ set: "Technisch account wijzigen",
1834
+ code: "Account uit de code gebruiken"
1835
+ },
1836
+ explain: {
1837
+ set: "Nieuwe runs werken onder dit account en met zijn rechten. Runs die al begonnen en hun voorstellen houden hun account.",
1838
+ code: "Nieuwe runs werken weer onder het account uit de code: {{account}}."
1839
+ },
1840
+ confirm: {
1841
+ set: "Account bevestigen",
1842
+ code: "Bevestigen"
1843
+ }
1844
+ },
1845
+ "run-config": "Runconfiguratie"
1553
1846
  },
1554
1847
  "agent-editor": {
1555
1848
  "new-title": "Nieuwe agent",
@@ -1787,6 +2080,180 @@ var nl = {
1787
2080
  stopped: "Gestopt"
1788
2081
  },
1789
2082
  "replay-progress": "{{replayed}} van hoogstens {{max}} runs herhaald, {{skipped}} overgeslagen"
2083
+ },
2084
+ "run-config": {
2085
+ back: "Terug naar agents",
2086
+ title: "Runconfiguratie van {{name}}",
2087
+ description: "Vaardigheden en triggers die het beheer zonder deploy toevoegt, gemaakt van de bouwstenen die de applicatie registreert. Nieuwe vaardigheden en triggers starten in schaduw, waar niemand een melding krijgt en niets wordt uitgevoerd.",
2088
+ problems: {
2089
+ title: "Sommige instellingen passen niet meer bij de applicatie en werken niet:",
2090
+ kind: {
2091
+ agent: "Runinstellingen:",
2092
+ skill: "Vaardigheid {{id}}:",
2093
+ candidate: "Kandidaat van vaardigheid {{id}}:",
2094
+ trigger: "Trigger {{id}}:"
2095
+ },
2096
+ code: {
2097
+ "unknown-agent": "de agent kan niet meer zelfstandig werken.",
2098
+ "conflicts-with-code": "de applicatie declareert er nu een met dezelfde id.",
2099
+ "too-many-skills": "de agent heeft meer vaardigheden dan toegestaan.",
2100
+ "tool-not-covered": "een tool valt buiten de eigen tools van de agent.",
2101
+ "unknown-profile": "het modelprofiel bestaat niet meer.",
2102
+ "unknown-policy": "het goedkeuringsbeleid bestaat niet meer.",
2103
+ "unknown-rule-handler": "de regels bestaan niet meer.",
2104
+ "unknown-event": "de gebeurtenis bestaat niet meer.",
2105
+ "unknown-subject-set": "de set onderwerpen bestaat niet meer.",
2106
+ "unknown-skill": "de vaardigheid bestaat niet meer.",
2107
+ "invalid-schedule": "het schema of de tijdzone is niet geldig.",
2108
+ invalid: "een waarde is niet geldig."
2109
+ }
2110
+ },
2111
+ "field-errors": {
2112
+ required: "Verplicht.",
2113
+ invalid: "Hier niet geldig.",
2114
+ "too-long": "Te lang.",
2115
+ "not-found": "De applicatie kent deze naam niet."
2116
+ },
2117
+ settings: {
2118
+ title: "Runinstellingen",
2119
+ empty: "Deze agent chat alleen. Geef hem runinstellingen om hem zelfstandig te laten werken, met vaardigheden en triggers.",
2120
+ rights: "Hij heeft geen eigen rechten: in runs zonder persoon gebruikt hij wat het account waaraan hij verantwoording aflegt mag, binnen zijn tools.",
2121
+ add: "Runinstellingen toevoegen",
2122
+ edit: "Runinstellingen wijzigen",
2123
+ remove: "Runinstellingen verwijderen",
2124
+ "remove-explain": "De agent chat daarna alleen. Verwijder eerst zijn vaardigheden en triggers.",
2125
+ saved: "De runinstellingen zijn opgeslagen.",
2126
+ removed: "De agent chat weer alleen.",
2127
+ "accountability-label": "Legt verantwoording af aan",
2128
+ accountability: {
2129
+ agent: "De agent zelf",
2130
+ "subject-responsible": "De verantwoordelijke van het onderwerp",
2131
+ "service-account": "Een technisch account"
2132
+ },
2133
+ "accountability-hint": "De agent handelt met de rechten van dit account. Een agent die aan zichzelf verantwoording aflegt heeft er geen en kan alleen voorstellen.",
2134
+ "service-account": "Technisch account",
2135
+ triage: "Triageprofiel",
2136
+ "triage-hint": "Een goedkoop model dat de vaardigheid kiest van een run die geen trigger of regel heeft gerouteerd.",
2137
+ retries: "Nieuwe pogingen na een fout",
2138
+ "max-concurrent": "Runs tegelijk",
2139
+ "max-per-subject": "Runs per onderwerp per dag",
2140
+ "elevated-reads": "Lezen met de rechten van het account",
2141
+ elevated: {
2142
+ restricted: "Afschermen voor lezers zonder het recht",
2143
+ deny: "Weigeren"
2144
+ },
2145
+ "gateway-reads": "Lezen via de datagateway van de applicatie met de rechten van het account",
2146
+ delegate: "Ook gebruiken wat de persoon die een run start mag"
2147
+ },
2148
+ "rule-handler": "Regels",
2149
+ "rule-handler-value": "Regels: {{name}}",
2150
+ "policy-value": "Goedkeuring: {{name}}",
2151
+ "profile-value": "Model: {{name}}",
2152
+ "approval-policy": "Goedkeuringsbeleid",
2153
+ model: "Het model, geen regels",
2154
+ none: "Geen",
2155
+ choose: "Kies…",
2156
+ "max-tokens": "Tokens per run",
2157
+ "daily-tool-calls": "Toolaanroepen per dag",
2158
+ "daily-tokens": "Tokens per dag",
2159
+ "budget-hint": "Laat leeg voor geen limiet. Een dagbudget vraagt zowel toolaanroepen als tokens.",
2160
+ "out-of-effect": "Werkt niet",
2161
+ changed: "Gewijzigd door {{user}} op {{date}}.",
2162
+ "needs-settings": "Geef de agent runinstellingen voordat je vaardigheden en triggers toevoegt.",
2163
+ skills: {
2164
+ description: "Vaardigheden in code komen uit de applicatie. Vaardigheden die je hier toevoegt hebben versies; een wijziging gaat direct live of draait eerst in schaduw naast de live versie.",
2165
+ add: "Vaardigheid toevoegen",
2166
+ added: "De vaardigheid is toegevoegd. Ze start in schaduw; zet haar live vanuit de lijst van de agent.",
2167
+ saved: "De nieuwe versie van de vaardigheid is live.",
2168
+ "saved-candidate": "De nieuwe versie draait in schaduw naast de live versie.",
2169
+ removed: "De vaardigheid is verwijderd; haar versies blijven bewaard.",
2170
+ empty: "De agent heeft nog geen vaardigheden.",
2171
+ "new-title": "Nieuwe vaardigheid",
2172
+ "edit-title": "Vaardigheid {{skill}} wijzigen (versie {{version}})",
2173
+ id: "Id van de vaardigheid",
2174
+ "id-hint": "Kleine letters, cijfers en streepjes, zoals progress-note.",
2175
+ "description-label": "Waarvoor de vaardigheid dient",
2176
+ "description-hint": "Triage en het model kiezen de vaardigheid op deze omschrijving.",
2177
+ instructions: "Instructies",
2178
+ "instructions-hint": "Gelezen na de eigen instructies van de agent zolang hij in de vaardigheid werkt.",
2179
+ tools: "Tools",
2180
+ "tools-hint": "Beperk de tools van de agent voor deze vaardigheid. Niets gekozen: de tools van de agent.",
2181
+ profile: "Modelprofiel",
2182
+ "agent-profile": "Het profiel van de agent",
2183
+ "agent-policy": "Het beleid van de agent",
2184
+ apply: "Hoe de wijziging ingaat",
2185
+ "apply-shadow": "Eerst in schaduw beoordelen naast de live versie",
2186
+ "apply-live": "Direct live zetten",
2187
+ "starts-in-shadow": "Een nieuwe vaardigheid start in schaduw.",
2188
+ versions: "Versies",
2189
+ "remove-explain": "Haar versies blijven bewaard. Een trigger die haar start moet eerst weg."
2190
+ },
2191
+ candidate: {
2192
+ badge: "Kandidaat v{{version}}",
2193
+ explain: "Versie {{version}} draait in schaduw naast de live versie op dezelfde gebeurtenissen: {{description}}",
2194
+ compare: "Vergelijken",
2195
+ promote: "Promoveren",
2196
+ "confirm-promote": "Promoveren bevestigen",
2197
+ discard: "Verwerpen",
2198
+ "confirm-discard": "Verwerpen bevestigen",
2199
+ promoted: "De kandidaat is nu de live versie.",
2200
+ discarded: "De kandidaat is verworpen; hij blijft bewaard.",
2201
+ comparison: "Live versie en kandidaat van {{skill}}",
2202
+ "live-column": "Live (v{{version}})",
2203
+ "candidate-column": "Kandidaat (v{{version}})",
2204
+ runs: "Runs",
2205
+ completed: "Afgerond",
2206
+ failed: "Mislukt",
2207
+ proposals: "Voorstellen",
2208
+ tokens: "Tokens",
2209
+ paired: "Beide behandelden {{count}} dezelfde gebeurtenissen sinds {{date}}."
2210
+ },
2211
+ status: {
2212
+ live: "Live",
2213
+ candidate: "Kandidaat",
2214
+ superseded: "Eerder",
2215
+ discarded: "Verworpen"
2216
+ },
2217
+ triggers: {
2218
+ title: "Triggers",
2219
+ description: "Triggers in code komen uit de applicatie. Triggers die je hier toevoegt starten de agent op gebeurtenissen van de applicatie of volgens een schema.",
2220
+ add: "Trigger toevoegen",
2221
+ added: "De trigger is toegevoegd. Hij start in schaduw.",
2222
+ saved: "De trigger is opgeslagen.",
2223
+ removed: "De trigger is verwijderd.",
2224
+ live: "De trigger werkt live.",
2225
+ "in-shadow": "De trigger werkt in schaduw.",
2226
+ empty: "Nog geen triggers starten de agent.",
2227
+ "new-title": "Nieuwe trigger",
2228
+ "edit-title": "Trigger {{trigger}} wijzigen",
2229
+ id: "Id van de trigger",
2230
+ source: "Start bij",
2231
+ "source-event": "Een gebeurtenis van de applicatie",
2232
+ "source-schedule": "Een schema",
2233
+ event: "Gebeurtenis",
2234
+ debounce: "Wachten op meer gebeurtenissen (seconden)",
2235
+ cron: "Schema (cron)",
2236
+ "cron-hint": "Vijf velden, zoals 0 7 * * 1 voor maandag om zeven uur.",
2237
+ "time-zone": "Tijdzone",
2238
+ "subject-set": "Onderwerpen",
2239
+ message: "Bericht aan elke run",
2240
+ skill: "Vaardigheid",
2241
+ "agent-routes": "De agent kiest de vaardigheid",
2242
+ "skill-value": "Vaardigheid: {{skill}}",
2243
+ conflict: "Terwijl een run bezig is",
2244
+ conflicts: {
2245
+ coalesce: "Samenvoegen met de wachtende run",
2246
+ queue: "Wachten op de run",
2247
+ supersede: "De run vervangen",
2248
+ ignore: "Overslaan"
2249
+ },
2250
+ sources: {
2251
+ event: "Gebeurtenis",
2252
+ schedule: "Schema",
2253
+ webhook: "Webhook"
2254
+ },
2255
+ "starts-in-shadow": "Een nieuwe trigger start in schaduw."
2256
+ }
1790
2257
  }
1791
2258
  },
1792
2259
  "page-context": {
@@ -1869,7 +2336,8 @@ var nl = {
1869
2336
  ignored: "De agent is bezig; er is niets gestart.",
1870
2337
  deduplicated: "Dit was al gestart.",
1871
2338
  rejected: "De agent kon niet starten."
1872
- }
2339
+ },
2340
+ shadow: "Schaduwthread: alleen beheerders zien hem, en niets wat hier wordt voorgesteld, wordt uitgevoerd."
1873
2341
  },
1874
2342
  subject: {
1875
2343
  title: "Voorstellen van agents",
@@ -2083,11 +2551,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
2083
2551
 
2084
2552
  /** A failed JSON request of the assistant API. Carries a stable code, never response text. */
2085
2553
  class NhAssistantApiError extends Error {
2086
- constructor(status, code, messageKey) {
2554
+ constructor(status, code, messageKey,
2555
+ /**
2556
+ * The field errors of an `assistant-validation` response: camelCase field names with stable
2557
+ * values such as `required`, `invalid`, `too-long` or `not-found`. Empty otherwise.
2558
+ */
2559
+ fieldErrors = {}) {
2087
2560
  super(code);
2088
2561
  this.status = status;
2089
2562
  this.code = code;
2090
2563
  this.messageKey = messageKey;
2564
+ this.fieldErrors = fieldErrors;
2091
2565
  this.name = 'NhAssistantApiError';
2092
2566
  }
2093
2567
  }
@@ -2118,6 +2592,7 @@ function nhAssistantCodeForStatus(status) {
2118
2592
  return NhAssistantClientErrorCodes.server;
2119
2593
  }
2120
2594
  const safeCode = /^[a-z0-9][a-z0-9.-]{0,79}$/;
2595
+ const safeField = /^[a-zA-Z][a-zA-Z0-9.]{0,63}$/;
2121
2596
  /**
2122
2597
  * Shared transport of the assistant services: `fetch` with the host's token, the current
2123
2598
  * language and stable failure codes. Internal to the library.
@@ -2146,18 +2621,36 @@ class NhAssistantTransport {
2146
2621
  * endpoint's status mapping, then the generic mapping. Response text is never used.
2147
2622
  */
2148
2623
  async failureCode(response, statusCodes = {}) {
2624
+ return (await this.failure(response, statusCodes)).code;
2625
+ }
2626
+ /**
2627
+ * The failure code of a response and the field errors of its body, both checked against safe
2628
+ * patterns. Response text is never used.
2629
+ */
2630
+ async failure(response, statusCodes) {
2631
+ const fieldErrors = {};
2149
2632
  try {
2150
2633
  const text = await response.text();
2151
2634
  const body = text.length > 0 ? JSON.parse(text) : null;
2152
- const code = body && typeof body === 'object' ? body['code'] : null;
2635
+ const record = body && typeof body === 'object' ? body : null;
2636
+ const errors = record?.['errors'];
2637
+ if (errors && typeof errors === 'object' && !Array.isArray(errors)) {
2638
+ for (const [field, values] of Object.entries(errors)) {
2639
+ const safe = Array.isArray(values) ? values.filter((value) => typeof value === 'string' && safeCode.test(value)) : [];
2640
+ if (safeField.test(field) && safe.length > 0) {
2641
+ fieldErrors[field] = safe;
2642
+ }
2643
+ }
2644
+ }
2645
+ const code = record?.['code'];
2153
2646
  if (typeof code === 'string' && safeCode.test(code)) {
2154
- return code;
2647
+ return { code, fieldErrors };
2155
2648
  }
2156
2649
  }
2157
2650
  catch {
2158
2651
  // A non-JSON error body carries no code.
2159
2652
  }
2160
- return statusCodes[response.status] ?? nhAssistantCodeForStatus(response.status);
2653
+ return { code: statusCodes[response.status] ?? nhAssistantCodeForStatus(response.status), fieldErrors };
2161
2654
  }
2162
2655
  async executeJson(method, path, body, statusCodes, signal, subscriber) {
2163
2656
  let response;
@@ -2171,8 +2664,8 @@ class NhAssistantTransport {
2171
2664
  return;
2172
2665
  }
2173
2666
  if (!response.ok) {
2174
- const code = await this.failureCode(response, statusCodes);
2175
- subscriber.error(createApiError(response.status, code));
2667
+ const failure = await this.failure(response, statusCodes);
2668
+ subscriber.error(createApiError(response.status, failure.code, failure.fieldErrors));
2176
2669
  return;
2177
2670
  }
2178
2671
  try {
@@ -2218,8 +2711,8 @@ class NhAssistantTransport {
2218
2711
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: NhAssistantTransport, decorators: [{
2219
2712
  type: Injectable
2220
2713
  }] });
2221
- function createApiError(status, code) {
2222
- return new NhAssistantApiError(status, code, nhAssistantErrorMessageKey(code));
2714
+ function createApiError(status, code, fieldErrors = {}) {
2715
+ return new NhAssistantApiError(status, code, nhAssistantErrorMessageKey(code), fieldErrors);
2223
2716
  }
2224
2717
  const reservedRequestHeaders = new Set(['authorization', 'accept', 'accept-language', 'content-type']);
2225
2718
  /**
@@ -2297,6 +2790,25 @@ class NhAssistantAdminApiService {
2297
2790
  setSkillState(agentId, skillId, request) {
2298
2791
  return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/skills/${encodeURIComponent(skillId)}/state`, request);
2299
2792
  }
2793
+ /**
2794
+ * Puts an agent in shadow, live, or back to the mode in code. A shadow variant cannot change
2795
+ * (`assistant-shadow-variant`).
2796
+ */
2797
+ setAgentShadow(agentId, request) {
2798
+ return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/shadow`, request);
2799
+ }
2800
+ /** Puts one skill of an agent in shadow, live, or back to the mode in code. */
2801
+ setSkillShadow(agentId, skillId, request) {
2802
+ return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/skills/${encodeURIComponent(skillId)}/shadow`, request);
2803
+ }
2804
+ /**
2805
+ * Changes the technical account that answers for the agent's new runs, or with `actorId: null`
2806
+ * uses the account in code again. Fails with `assistant-service-account-not-found` for an
2807
+ * account that does not exist or may not sign in.
2808
+ */
2809
+ setServiceAccount(agentId, request) {
2810
+ return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/service-account`, request);
2811
+ }
2300
2812
  /** Deletes an admin agent. Code agents cannot be deleted; stop them instead. */
2301
2813
  deleteAgent(agentId) {
2302
2814
  return this.request('DELETE', `admin/agents/${encodeURIComponent(agentId)}`);
@@ -2371,6 +2883,67 @@ class NhAssistantAdminApiService {
2371
2883
  getAgentReplays(variantId) {
2372
2884
  return this.request('GET', `${agentPath(variantId)}/replays`);
2373
2885
  }
2886
+ /** The building blocks in code that run settings, skills and triggers defined as data can name. */
2887
+ getRunCatalog() {
2888
+ return this.request('GET', 'admin/run-catalog');
2889
+ }
2890
+ /**
2891
+ * The agent's run settings, skills and triggers, in code and as data, and the data that no longer
2892
+ * fits the code. An agent in code without a run configuration answers `assistant-agent-not-found`.
2893
+ */
2894
+ getAgentConfiguration(agentId) {
2895
+ return this.request('GET', `${agentPath(agentId)}/configuration`);
2896
+ }
2897
+ /**
2898
+ * Adds or changes the run settings of an agent created in the administration. An agent in code
2899
+ * fails with `assistant-run-settings-in-code`; an unknown technical account with
2900
+ * `assistant-service-account-not-found`.
2901
+ */
2902
+ saveRunSettings(agentId, request) {
2903
+ return this.request('PUT', `${agentPath(agentId)}/run-settings`, request);
2904
+ }
2905
+ /** Removes the run settings; while data skills or triggers belong to the agent, `assistant-run-settings-in-use`. */
2906
+ removeRunSettings(agentId, removal = {}) {
2907
+ return this.request('DELETE', withQuery(`${agentPath(agentId)}/run-settings`, removal));
2908
+ }
2909
+ /**
2910
+ * Adds a skill defined as data, which starts in shadow, or stores its next version: with `apply`
2911
+ * `live` at once, with `shadow` as the candidate that runs in shadow next to the live version.
2912
+ */
2913
+ saveDataSkill(agentId, skillId, request) {
2914
+ return this.request('PUT', skillPath(agentId, skillId), request);
2915
+ }
2916
+ /** Takes a skill defined as data out of effect; while a data trigger names it, `assistant-skill-in-use`. */
2917
+ removeDataSkill(agentId, skillId, removal = {}) {
2918
+ return this.request('DELETE', withQuery(skillPath(agentId, skillId), removal));
2919
+ }
2920
+ /** Every version of a skill defined as data, newest first. */
2921
+ getDataSkillVersions(agentId, skillId) {
2922
+ return this.request('GET', `${skillPath(agentId, skillId)}/versions`);
2923
+ }
2924
+ /** Makes the candidate the live version of its skill. */
2925
+ promoteSkillCandidate(agentId, skillId, request) {
2926
+ return this.request('POST', `${skillPath(agentId, skillId)}/candidate/promote`, request);
2927
+ }
2928
+ /** Discards the candidate; it stays as history. */
2929
+ discardSkillCandidate(agentId, skillId, request) {
2930
+ return this.request('POST', `${skillPath(agentId, skillId)}/candidate/discard`, request);
2931
+ }
2932
+ /** Compares the candidate with the live version on the runs they made in the period. */
2933
+ compareSkillCandidate(agentId, skillId, filter = {}) {
2934
+ return this.request('GET', withQuery(`${skillPath(agentId, skillId)}/candidate/comparison`, filter));
2935
+ }
2936
+ /** Adds a trigger defined as data, which starts in shadow, or changes one in the mode it has. */
2937
+ saveDataTrigger(agentId, triggerId, request) {
2938
+ return this.request('PUT', triggerPath(agentId, triggerId), request);
2939
+ }
2940
+ removeDataTrigger(agentId, triggerId, removal = {}) {
2941
+ return this.request('DELETE', withQuery(triggerPath(agentId, triggerId), removal));
2942
+ }
2943
+ /** Puts a trigger defined as data in shadow or live. */
2944
+ setDataTriggerShadow(agentId, triggerId, request) {
2945
+ return this.request('POST', `${triggerPath(agentId, triggerId)}/shadow`, request);
2946
+ }
2374
2947
  async download(path) {
2375
2948
  let response;
2376
2949
  try {
@@ -2401,6 +2974,12 @@ function feedbackPath(agentId) {
2401
2974
  function agentPath(agentId) {
2402
2975
  return `admin/agents/${encodeURIComponent(agentId)}`;
2403
2976
  }
2977
+ function skillPath(agentId, skillId) {
2978
+ return `${agentPath(agentId)}/skills/${encodeURIComponent(skillId)}`;
2979
+ }
2980
+ function triggerPath(agentId, triggerId) {
2981
+ return `${agentPath(agentId)}/triggers/${encodeURIComponent(triggerId)}`;
2982
+ }
2404
2983
  /** Appends the filter values that are set as query parameters. */
2405
2984
  function withQuery(path, filter) {
2406
2985
  const query = new URLSearchParams();
@@ -3674,6 +4253,13 @@ function nhAssistantIsUnread(summary) {
3674
4253
  }
3675
4254
  return (summary.lastMessageSequence ?? 0) > summary.lastReadSequence;
3676
4255
  }
4256
+ /**
4257
+ * True when the server accepts a new message in a conversation with this status. A failed turn
4258
+ * leaves the conversation open: the person can ask again in the same conversation or agent thread.
4259
+ */
4260
+ function acceptsMessage(status) {
4261
+ return status === 'idle' || status === 'failed';
4262
+ }
3677
4263
  const conversationPageSize = 50;
3678
4264
  const cancelGracePeriodMs = 5_000;
3679
4265
  const maxSessions = 20;
@@ -3776,10 +4362,13 @@ class NhAssistantStore {
3776
4362
  this.pageContextExcluded = this.pageContextExcludedState.asReadonly();
3777
4363
  /** Whether the drawer was open when this account last left the application. */
3778
4364
  this.restorePanelOpen = this.restorePanelOpenState.asReadonly();
3779
- /** True while the user can send: enabled, an agent is chosen and no turn runs or waits. */
4365
+ /**
4366
+ * True while the user can send: enabled, an agent is chosen and no turn runs or waits. A
4367
+ * conversation whose last turn failed accepts a new message; an archived one does not.
4368
+ */
3780
4369
  this.canSend = computed(() => {
3781
4370
  const conversation = this.activeConversation();
3782
- const blocked = conversation !== null && conversation.status !== 'idle';
4371
+ const blocked = conversation !== null && !acceptsMessage(conversation.status);
3783
4372
  return this.enabled() && this.selectedAgentIdState() !== null && !this.streaming() && !this.conversationLoadingState() && !blocked;
3784
4373
  }, ...(ngDevMode ? [{ debugName: "canSend" }] : []));
3785
4374
  /** Messages not yet accepted by the server, for the open conversation. Never persisted. */
@@ -3787,7 +4376,7 @@ class NhAssistantStore {
3787
4376
  /** Sending or queueing is available during a turn and while an approval waits. */
3788
4377
  this.canSubmit = computed(() => (this.canSend() && !this.submittingState()) || (this.enabled()
3789
4378
  && !this.conversationLoading() && this.activeConversation() !== null
3790
- && ['idle', 'running', 'waiting-for-approval'].includes(this.activeConversation().status)), ...(ngDevMode ? [{ debugName: "canSubmit" }] : []));
4379
+ && ['idle', 'failed', 'running', 'waiting-for-approval'].includes(this.activeConversation().status)), ...(ngDevMode ? [{ debugName: "canSubmit" }] : []));
3791
4380
  this.queuePaused = computed(() => this.pausedQueuesState().has(this.activeIdState() ?? '') || this.error() !== null, ...(ngDevMode ? [{ debugName: "queuePaused" }] : []));
3792
4381
  /** Steering cancels the active turn before sending the selected correction. */
3793
4382
  this.canSteer = computed(() => {
@@ -3919,7 +4508,7 @@ class NhAssistantStore {
3919
4508
  const session = sessions.get(item.conversationId);
3920
4509
  return item.state === 'queued' && !paused.has(item.conversationId)
3921
4510
  && !queued.slice(0, index).some(previous => previous.conversationId === item.conversationId)
3922
- && session?.conversation.status === 'idle' && !session.streaming && !session.deciding && !session.error;
4511
+ && acceptsMessage(session?.conversation.status) && !session?.streaming && !session?.deciding && !session?.error;
3923
4512
  });
3924
4513
  if (next) {
3925
4514
  untracked(() => void this.dispatchQueued(next));
@@ -4094,9 +4683,15 @@ class NhAssistantStore {
4094
4683
  void this.push.onUserGesture().catch(() => undefined);
4095
4684
  return this.sendMessage(text);
4096
4685
  }
4097
- /** Sends immediately when idle, otherwise appends to the conversation's FIFO queue. */
4686
+ /**
4687
+ * Sends immediately when the conversation accepts a message, otherwise appends to the
4688
+ * conversation's FIFO queue. A shown error alone does not hold a message back while nothing is
4689
+ * queued: the person asks again, for example after a failed turn. Queued messages still wait
4690
+ * for an explicit `resumeQueue` after Stop or a failure.
4691
+ */
4098
4692
  async submit(text) {
4099
- if (this.canSend() && this.queuedMessages().length === 0 && !this.queuePaused() && !this.submittingState()) {
4693
+ const stopped = this.pausedQueuesState().has(this.activeIdState() ?? newConversationKey);
4694
+ if (this.canSend() && this.queuedMessages().length === 0 && !stopped && !this.submittingState()) {
4100
4695
  const revision = this.accountRevision;
4101
4696
  this.submittingState.set(true);
4102
4697
  try {
@@ -4201,7 +4796,7 @@ class NhAssistantStore {
4201
4796
  let conversation = queued ? this.sessionsState().get(queued.conversationId)?.conversation ?? null : this.activeConversation();
4202
4797
  const session = queued ? this.sessionsState().get(queued.conversationId) : null;
4203
4798
  const available = queued ? this.enabled() && !this.pausedQueuesState().has(queued.conversationId)
4204
- && conversation?.status === 'idle' && !session?.streaming
4799
+ && acceptsMessage(conversation?.status) && !session?.streaming
4205
4800
  && !session?.deciding && this.agents().some(agent => agent.id === conversation?.agentId) : this.canSend();
4206
4801
  const maxChars = this.limits()?.maxMessageChars ?? Number.MAX_SAFE_INTEGER;
4207
4802
  if (trimmed.length === 0 || trimmed.length > maxChars || !available) {
@@ -6585,7 +7180,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
6585
7180
  /** Converts any failure into a user-facing code and translation key, never raw text. */
6586
7181
  function toNhAssistantError(error) {
6587
7182
  if (error instanceof NhAssistantApiError) {
6588
- return { code: error.code, messageKey: error.messageKey };
7183
+ return Object.keys(error.fieldErrors).length > 0
7184
+ ? { code: error.code, messageKey: error.messageKey, fieldErrors: error.fieldErrors }
7185
+ : { code: error.code, messageKey: error.messageKey };
6589
7186
  }
6590
7187
  return { code: NhAssistantClientErrorCodes.server, messageKey: nhAssistantErrorMessageKey(NhAssistantClientErrorCodes.server) };
6591
7188
  }
@@ -7132,11 +7729,15 @@ class NhAssistantPanelComponent {
7132
7729
  this.conversation = this.store.activeConversation;
7133
7730
  this.conversationId = computed(() => this.conversation()?.id ?? null, ...(ngDevMode ? [{ debugName: "conversationId" }] : []));
7134
7731
  this.messages = computed(() => this.conversation()?.messages ?? [], ...(ngDevMode ? [{ debugName: "messages" }] : []));
7135
- this.closed = computed(() => {
7136
- const status = this.conversation()?.status;
7137
- return status === 'failed' || status === 'archived';
7138
- }, ...(ngDevMode ? [{ debugName: "closed" }] : []));
7732
+ /** An archived conversation takes no new messages. A failed one does: the person asks again. */
7733
+ this.closed = computed(() => this.conversation()?.status === 'archived', ...(ngDevMode ? [{ debugName: "closed" }] : []));
7139
7734
  this.busy = computed(() => this.store.streaming() || this.conversation()?.status === 'running', ...(ngDevMode ? [{ debugName: "busy" }] : []));
7735
+ /**
7736
+ * The last turn failed and no error bar explains it, for example after the conversation was
7737
+ * reopened. The panel then says so, while the composer stays available.
7738
+ */
7739
+ this.lastTurnFailed = computed(() => this.conversation()?.status === 'failed'
7740
+ && !this.busy() && this.store.error() === null, ...(ngDevMode ? [{ debugName: "lastTurnFailed" }] : []));
7140
7741
  this.composerDisabled = computed(() => !this.store.canSubmit(), ...(ngDevMode ? [{ debugName: "composerDisabled" }] : []));
7141
7742
  this.editingQueuedId = signal(null, ...(ngDevMode ? [{ debugName: "editingQueuedId" }] : []));
7142
7743
  this.queuedDraft = signal('', ...(ngDevMode ? [{ debugName: "queuedDraft" }] : []));
@@ -7323,7 +7924,7 @@ class NhAssistantPanelComponent {
7323
7924
  void this.store.cancel();
7324
7925
  }
7325
7926
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: NhAssistantPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7326
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", 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 </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n @if (push.state() !== 'unavailable') {\n <button\n class=\"icon-button notification-button\"\n type=\"button\"\n [class.active]=\"push.state() === 'on'\"\n [class.off]=\"!push.settings()?.pushEnabled\"\n [class.blocked]=\"push.state() === 'blocked'\"\n [disabled]=\"push.busy()\"\n [attr.aria-pressed]=\"push.settings()?.pushEnabled === true\"\n [attr.aria-label]=\"notificationsLabel() | translate\"\n [attr.title]=\"('nh-assistant.preferences.notifications-state.' + push.state() | translate) + ' \u00B7 ' + (notificationsLabel() | translate)\"\n (click)=\"toggleNotifications()\">\n <nh-assistant-icon name=\"bell\" />\n </button>\n }\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 [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 @if (store.enabled()) {\n <nh-assistant-activity [items]=\"store.activity()\" (conversationSelect)=\"openConversation($event)\" />\n }\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 (showShare()) {\n <nh-assistant-share class=\"overlay-view\" [section]=\"shareSection()\" (closed)=\"showShare.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 (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 [attr.inert]=\"showPreferences() || showShare() || showConversations() ? '' : null\"\n [messages]=\"messages()\"\n [streaming]=\"busy()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n [members]=\"store.members()\"\n [currentActorId]=\"conversation()?.currentActorId ?? null\"\n [canDecide]=\"store.canDecide()\"\n [decisionOwner]=\"activeMemberName()\"\n [approvalRights]=\"store.approvalRights()\"\n (approvalChoice)=\"decideApproval($event)\" />\n }\n }\n </div>\n\n @if (notificationError() ?? 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(); notificationError.set(null)\">\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() && !showShare()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n }\n @if (store.collaboration() || store.pageContext()) {\n <div class=\"conversation-actions\">\n @if (store.collaboration()) {\n @if (!conversation() || store.isOwner()) {\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [attr.aria-label]=\"'nh-assistant.panel.share' | translate\"\n [attr.title]=\"'nh-assistant.panel.share' | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'link'\"\n (click)=\"toggleShare('link')\">\n <nh-assistant-icon name=\"link\" />\n </button>\n }\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [class.active]=\"shared()\"\n [attr.aria-label]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.title]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'members'\"\n (click)=\"toggleShare('members')\">\n <nh-assistant-icon name=\"users\" />\n </button>\n }\n @if (store.pageContext(); as context) {\n <button\n class=\"icon-button page-context-button\"\n [class.active]=\"!store.pageContextExcluded()\"\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=\"page\" />\n </button>\n }\n </div>\n }\n @if (store.queuedMessages().length > 0) {\n <section class=\"message-queue\" [attr.aria-label]=\"'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length }\">\n <div class=\"queue-heading\">\n <span aria-live=\"polite\">{{ 'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length } }}</span>\n @if (store.queuePaused()) {\n <button type=\"button\" class=\"queue-resume\" [disabled]=\"editingQueuedId() !== null\" (click)=\"store.resumeQueue()\">\n {{ 'nh-assistant.queue.resume' | translate }}\n </button>\n }\n </div>\n <ol class=\"queue-items\">\n @for (item of store.queuedMessages(); track item.id) {\n <li class=\"queue-item\" [class.failed]=\"item.state === 'failed'\">\n @if (editingQueuedId() === item.id && item.state !== 'sending') {\n <div class=\"queue-edit\">\n <textarea rows=\"2\" [value]=\"queuedDraft()\" (input)=\"changeQueuedDraft($event)\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\"></textarea>\n <div class=\"queue-buttons\">\n <button type=\"button\" class=\"icon-button\" [disabled]=\"!validQueuedDraft()\"\n [attr.aria-label]=\"'nh-assistant.queue.save' | translate\" [attr.title]=\"'nh-assistant.queue.save' | translate\"\n (click)=\"saveQueuedMessage(item.id)\"><nh-assistant-icon name=\"check\" /></button>\n <button type=\"button\" class=\"icon-button\" [attr.aria-label]=\"'nh-assistant.queue.cancel-edit' | translate\"\n [attr.title]=\"'nh-assistant.queue.cancel-edit' | translate\"\n (click)=\"cancelQueueEdit()\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n </div>\n } @else {\n <div class=\"queue-message\">\n <p [title]=\"item.text\">{{ item.text }}</p>\n @if (item.state !== 'queued') {\n <span class=\"queue-state\">{{ 'nh-assistant.queue.state.' + item.state | translate }}</span>\n }\n </div>\n <div class=\"queue-buttons\">\n @if (store.canSteer() && item.state === 'queued') {\n <button type=\"button\" class=\"queue-steer\" [disabled]=\"editingQueuedId() !== null\"\n [attr.title]=\"'nh-assistant.queue.steer-hint' | translate\"\n (click)=\"store.steerQueuedMessage(item.id)\">{{ 'nh-assistant.queue.steer' | translate }}</button>\n }\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\" [attr.title]=\"'nh-assistant.queue.edit' | translate\"\n (click)=\"editQueuedMessage(item.id, item.text)\"><nh-assistant-icon name=\"edit\" /></button>\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.remove' | translate\" [attr.title]=\"'nh-assistant.queue.remove' | translate\"\n (click)=\"store.removeQueuedMessage(item.id)\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n }\n </li>\n }\n </ol>\n </section>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [queueWhileBusy]=\"true\"\n [status]=\"composerStatus()\"\n [statusActor]=\"activeMemberName()\"\n [canStop]=\"canStop()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\">\n @if (store.agents().length > 1) {\n <nh-assistant-agent-picker\n nhAssistantComposerControls\n [compact]=\"true\"\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </nh-assistant-composer>\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}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:2px;min-width:0}.header-actions .icon-button{width:32px;height:32px}.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{padding:12px 16px 14px}.conversation-actions{display:flex;align-items:center;gap:4px;margin:0 -4px 6px}.page-context-button{margin-left:auto}.message-queue{margin-bottom:10px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);background:var(--nha-background);overflow:hidden;font-size:12px}.queue-heading{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px;color:var(--nha-text-muted)}.queue-items{max-height:180px;overflow-y:auto;margin:0;padding:0;list-style:none}.queue-item{display:flex;align-items:center;gap:8px;border-top:1px solid var(--nha-border);padding:6px 8px 6px 10px}.queue-item.failed{border-left:2px solid var(--nha-danger)}.queue-message{flex:1;min-width:0}.queue-message p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;margin:0}.queue-state{color:var(--nha-text-muted);font-size:11px}.queue-buttons{display:flex;flex-shrink:0;align-items:center;gap:2px}.queue-buttons .icon-button{width:28px;height:30px}.queue-resume,.queue-steer{border:0;border-radius:6px;padding:6px;color:var(--nha-highlight);background:transparent;font:inherit;cursor:pointer}.queue-resume:hover,.queue-steer:hover{background:var(--nha-surface)}.queue-resume:focus-visible,.queue-steer:focus-visible{outline:2px solid var(--nha-focus)}.queue-resume:disabled,.queue-steer:disabled{cursor:not-allowed;opacity:.5}.queue-edit{width:100%}.queue-edit textarea{box-sizing:border-box;width:100%;border:1px solid var(--nha-border);border-radius:6px;padding:8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;resize:vertical}.queue-edit .queue-buttons{justify-content:flex-end}.notification-button{position:relative}.notification-button.off:after{content:\"\";position:absolute;width:18px;height:2px;border-radius:1px;background:currentColor;transform:rotate(-45deg)}.notification-button.blocked{color:var(--nha-warning)}@media(max-width:359px){.header{gap:6px;padding-inline:12px}.header-actions .icon-button{width:28px;height:32px}}.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: NhAssistantActivityComponent, selector: "nh-assistant-activity", inputs: ["items"], outputs: ["conversationSelect"] }, { kind: "component", type: NhAssistantAgentPickerComponent, selector: "nh-assistant-agent-picker", inputs: ["agents", "selectedAgentId", "disabled", "compact"], outputs: ["agentChange"] }, { kind: "component", type: NhAssistantComposerComponent, selector: "nh-assistant-composer", inputs: ["disabled", "sendDisabled", "busy", "queueWhileBusy", "status", "statusActor", "canStop", "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: NhAssistantShareComponent, selector: "nh-assistant-share", inputs: ["section"], outputs: ["closed"] }, { kind: "component", type: NhAssistantThreadComponent, selector: "nh-assistant-thread", inputs: ["messages", "streaming", "deciding", "markdown", "members", "currentActorId", "canDecide", "decisionOwner", "approvalRights"], outputs: ["approvalDecision", "approvalChoice"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7927
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", 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 </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n @if (push.state() !== 'unavailable') {\n <button\n class=\"icon-button notification-button\"\n type=\"button\"\n [class.active]=\"push.state() === 'on'\"\n [class.off]=\"!push.settings()?.pushEnabled\"\n [class.blocked]=\"push.state() === 'blocked'\"\n [disabled]=\"push.busy()\"\n [attr.aria-pressed]=\"push.settings()?.pushEnabled === true\"\n [attr.aria-label]=\"notificationsLabel() | translate\"\n [attr.title]=\"('nh-assistant.preferences.notifications-state.' + push.state() | translate) + ' \u00B7 ' + (notificationsLabel() | translate)\"\n (click)=\"toggleNotifications()\">\n <nh-assistant-icon name=\"bell\" />\n </button>\n }\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 [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 @if (store.enabled()) {\n <nh-assistant-activity [items]=\"store.activity()\" (conversationSelect)=\"openConversation($event)\" />\n }\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 (showShare()) {\n <nh-assistant-share class=\"overlay-view\" [section]=\"shareSection()\" (closed)=\"showShare.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 (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 [attr.inert]=\"showPreferences() || showShare() || showConversations() ? '' : null\"\n [messages]=\"messages()\"\n [streaming]=\"busy()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n [members]=\"store.members()\"\n [currentActorId]=\"conversation()?.currentActorId ?? null\"\n [canDecide]=\"store.canDecide()\"\n [decisionOwner]=\"activeMemberName()\"\n [approvalRights]=\"store.approvalRights()\"\n (approvalChoice)=\"decideApproval($event)\" />\n }\n }\n </div>\n\n @if (notificationError() ?? 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(); notificationError.set(null)\">\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() && !showShare()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n } @else if (lastTurnFailed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.last-turn-failed' | translate }}</p>\n }\n @if (store.collaboration() || store.pageContext()) {\n <div class=\"conversation-actions\">\n @if (store.collaboration()) {\n @if (!conversation() || store.isOwner()) {\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [attr.aria-label]=\"'nh-assistant.panel.share' | translate\"\n [attr.title]=\"'nh-assistant.panel.share' | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'link'\"\n (click)=\"toggleShare('link')\">\n <nh-assistant-icon name=\"link\" />\n </button>\n }\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [class.active]=\"shared()\"\n [attr.aria-label]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.title]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'members'\"\n (click)=\"toggleShare('members')\">\n <nh-assistant-icon name=\"users\" />\n </button>\n }\n @if (store.pageContext(); as context) {\n <button\n class=\"icon-button page-context-button\"\n [class.active]=\"!store.pageContextExcluded()\"\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=\"page\" />\n </button>\n }\n </div>\n }\n @if (store.queuedMessages().length > 0) {\n <section class=\"message-queue\" [attr.aria-label]=\"'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length }\">\n <div class=\"queue-heading\">\n <span aria-live=\"polite\">{{ 'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length } }}</span>\n @if (store.queuePaused()) {\n <button type=\"button\" class=\"queue-resume\" [disabled]=\"editingQueuedId() !== null\" (click)=\"store.resumeQueue()\">\n {{ 'nh-assistant.queue.resume' | translate }}\n </button>\n }\n </div>\n <ol class=\"queue-items\">\n @for (item of store.queuedMessages(); track item.id) {\n <li class=\"queue-item\" [class.failed]=\"item.state === 'failed'\">\n @if (editingQueuedId() === item.id && item.state !== 'sending') {\n <div class=\"queue-edit\">\n <textarea rows=\"2\" [value]=\"queuedDraft()\" (input)=\"changeQueuedDraft($event)\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\"></textarea>\n <div class=\"queue-buttons\">\n <button type=\"button\" class=\"icon-button\" [disabled]=\"!validQueuedDraft()\"\n [attr.aria-label]=\"'nh-assistant.queue.save' | translate\" [attr.title]=\"'nh-assistant.queue.save' | translate\"\n (click)=\"saveQueuedMessage(item.id)\"><nh-assistant-icon name=\"check\" /></button>\n <button type=\"button\" class=\"icon-button\" [attr.aria-label]=\"'nh-assistant.queue.cancel-edit' | translate\"\n [attr.title]=\"'nh-assistant.queue.cancel-edit' | translate\"\n (click)=\"cancelQueueEdit()\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n </div>\n } @else {\n <div class=\"queue-message\">\n <p [title]=\"item.text\">{{ item.text }}</p>\n @if (item.state !== 'queued') {\n <span class=\"queue-state\">{{ 'nh-assistant.queue.state.' + item.state | translate }}</span>\n }\n </div>\n <div class=\"queue-buttons\">\n @if (store.canSteer() && item.state === 'queued') {\n <button type=\"button\" class=\"queue-steer\" [disabled]=\"editingQueuedId() !== null\"\n [attr.title]=\"'nh-assistant.queue.steer-hint' | translate\"\n (click)=\"store.steerQueuedMessage(item.id)\">{{ 'nh-assistant.queue.steer' | translate }}</button>\n }\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\" [attr.title]=\"'nh-assistant.queue.edit' | translate\"\n (click)=\"editQueuedMessage(item.id, item.text)\"><nh-assistant-icon name=\"edit\" /></button>\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.remove' | translate\" [attr.title]=\"'nh-assistant.queue.remove' | translate\"\n (click)=\"store.removeQueuedMessage(item.id)\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n }\n </li>\n }\n </ol>\n </section>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [queueWhileBusy]=\"true\"\n [status]=\"composerStatus()\"\n [statusActor]=\"activeMemberName()\"\n [canStop]=\"canStop()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\">\n @if (store.agents().length > 1) {\n <nh-assistant-agent-picker\n nhAssistantComposerControls\n [compact]=\"true\"\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </nh-assistant-composer>\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}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:2px;min-width:0}.header-actions .icon-button{width:32px;height:32px}.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{padding:12px 16px 14px}.conversation-actions{display:flex;align-items:center;gap:4px;margin:0 -4px 6px}.page-context-button{margin-left:auto}.message-queue{margin-bottom:10px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);background:var(--nha-background);overflow:hidden;font-size:12px}.queue-heading{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px;color:var(--nha-text-muted)}.queue-items{max-height:180px;overflow-y:auto;margin:0;padding:0;list-style:none}.queue-item{display:flex;align-items:center;gap:8px;border-top:1px solid var(--nha-border);padding:6px 8px 6px 10px}.queue-item.failed{border-left:2px solid var(--nha-danger)}.queue-message{flex:1;min-width:0}.queue-message p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;margin:0}.queue-state{color:var(--nha-text-muted);font-size:11px}.queue-buttons{display:flex;flex-shrink:0;align-items:center;gap:2px}.queue-buttons .icon-button{width:28px;height:30px}.queue-resume,.queue-steer{border:0;border-radius:6px;padding:6px;color:var(--nha-highlight);background:transparent;font:inherit;cursor:pointer}.queue-resume:hover,.queue-steer:hover{background:var(--nha-surface)}.queue-resume:focus-visible,.queue-steer:focus-visible{outline:2px solid var(--nha-focus)}.queue-resume:disabled,.queue-steer:disabled{cursor:not-allowed;opacity:.5}.queue-edit{width:100%}.queue-edit textarea{box-sizing:border-box;width:100%;border:1px solid var(--nha-border);border-radius:6px;padding:8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;resize:vertical}.queue-edit .queue-buttons{justify-content:flex-end}.notification-button{position:relative}.notification-button.off:after{content:\"\";position:absolute;width:18px;height:2px;border-radius:1px;background:currentColor;transform:rotate(-45deg)}.notification-button.blocked{color:var(--nha-warning)}@media(max-width:359px){.header{gap:6px;padding-inline:12px}.header-actions .icon-button{width:28px;height:32px}}.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: NhAssistantActivityComponent, selector: "nh-assistant-activity", inputs: ["items"], outputs: ["conversationSelect"] }, { kind: "component", type: NhAssistantAgentPickerComponent, selector: "nh-assistant-agent-picker", inputs: ["agents", "selectedAgentId", "disabled", "compact"], outputs: ["agentChange"] }, { kind: "component", type: NhAssistantComposerComponent, selector: "nh-assistant-composer", inputs: ["disabled", "sendDisabled", "busy", "queueWhileBusy", "status", "statusActor", "canStop", "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: NhAssistantShareComponent, selector: "nh-assistant-share", inputs: ["section"], outputs: ["closed"] }, { kind: "component", type: NhAssistantThreadComponent, selector: "nh-assistant-thread", inputs: ["messages", "streaming", "deciding", "markdown", "members", "currentActorId", "canDecide", "decisionOwner", "approvalRights"], outputs: ["approvalDecision", "approvalChoice"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7327
7928
  }
7328
7929
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: NhAssistantPanelComponent, decorators: [{
7329
7930
  type: Component,
@@ -7339,7 +7940,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
7339
7940
  NhAssistantPreferencesComponent,
7340
7941
  NhAssistantShareComponent,
7341
7942
  NhAssistantThreadComponent
7342
- ], 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 </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n @if (push.state() !== 'unavailable') {\n <button\n class=\"icon-button notification-button\"\n type=\"button\"\n [class.active]=\"push.state() === 'on'\"\n [class.off]=\"!push.settings()?.pushEnabled\"\n [class.blocked]=\"push.state() === 'blocked'\"\n [disabled]=\"push.busy()\"\n [attr.aria-pressed]=\"push.settings()?.pushEnabled === true\"\n [attr.aria-label]=\"notificationsLabel() | translate\"\n [attr.title]=\"('nh-assistant.preferences.notifications-state.' + push.state() | translate) + ' \u00B7 ' + (notificationsLabel() | translate)\"\n (click)=\"toggleNotifications()\">\n <nh-assistant-icon name=\"bell\" />\n </button>\n }\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 [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 @if (store.enabled()) {\n <nh-assistant-activity [items]=\"store.activity()\" (conversationSelect)=\"openConversation($event)\" />\n }\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 (showShare()) {\n <nh-assistant-share class=\"overlay-view\" [section]=\"shareSection()\" (closed)=\"showShare.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 (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 [attr.inert]=\"showPreferences() || showShare() || showConversations() ? '' : null\"\n [messages]=\"messages()\"\n [streaming]=\"busy()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n [members]=\"store.members()\"\n [currentActorId]=\"conversation()?.currentActorId ?? null\"\n [canDecide]=\"store.canDecide()\"\n [decisionOwner]=\"activeMemberName()\"\n [approvalRights]=\"store.approvalRights()\"\n (approvalChoice)=\"decideApproval($event)\" />\n }\n }\n </div>\n\n @if (notificationError() ?? 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(); notificationError.set(null)\">\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() && !showShare()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n }\n @if (store.collaboration() || store.pageContext()) {\n <div class=\"conversation-actions\">\n @if (store.collaboration()) {\n @if (!conversation() || store.isOwner()) {\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [attr.aria-label]=\"'nh-assistant.panel.share' | translate\"\n [attr.title]=\"'nh-assistant.panel.share' | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'link'\"\n (click)=\"toggleShare('link')\">\n <nh-assistant-icon name=\"link\" />\n </button>\n }\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [class.active]=\"shared()\"\n [attr.aria-label]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.title]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'members'\"\n (click)=\"toggleShare('members')\">\n <nh-assistant-icon name=\"users\" />\n </button>\n }\n @if (store.pageContext(); as context) {\n <button\n class=\"icon-button page-context-button\"\n [class.active]=\"!store.pageContextExcluded()\"\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=\"page\" />\n </button>\n }\n </div>\n }\n @if (store.queuedMessages().length > 0) {\n <section class=\"message-queue\" [attr.aria-label]=\"'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length }\">\n <div class=\"queue-heading\">\n <span aria-live=\"polite\">{{ 'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length } }}</span>\n @if (store.queuePaused()) {\n <button type=\"button\" class=\"queue-resume\" [disabled]=\"editingQueuedId() !== null\" (click)=\"store.resumeQueue()\">\n {{ 'nh-assistant.queue.resume' | translate }}\n </button>\n }\n </div>\n <ol class=\"queue-items\">\n @for (item of store.queuedMessages(); track item.id) {\n <li class=\"queue-item\" [class.failed]=\"item.state === 'failed'\">\n @if (editingQueuedId() === item.id && item.state !== 'sending') {\n <div class=\"queue-edit\">\n <textarea rows=\"2\" [value]=\"queuedDraft()\" (input)=\"changeQueuedDraft($event)\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\"></textarea>\n <div class=\"queue-buttons\">\n <button type=\"button\" class=\"icon-button\" [disabled]=\"!validQueuedDraft()\"\n [attr.aria-label]=\"'nh-assistant.queue.save' | translate\" [attr.title]=\"'nh-assistant.queue.save' | translate\"\n (click)=\"saveQueuedMessage(item.id)\"><nh-assistant-icon name=\"check\" /></button>\n <button type=\"button\" class=\"icon-button\" [attr.aria-label]=\"'nh-assistant.queue.cancel-edit' | translate\"\n [attr.title]=\"'nh-assistant.queue.cancel-edit' | translate\"\n (click)=\"cancelQueueEdit()\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n </div>\n } @else {\n <div class=\"queue-message\">\n <p [title]=\"item.text\">{{ item.text }}</p>\n @if (item.state !== 'queued') {\n <span class=\"queue-state\">{{ 'nh-assistant.queue.state.' + item.state | translate }}</span>\n }\n </div>\n <div class=\"queue-buttons\">\n @if (store.canSteer() && item.state === 'queued') {\n <button type=\"button\" class=\"queue-steer\" [disabled]=\"editingQueuedId() !== null\"\n [attr.title]=\"'nh-assistant.queue.steer-hint' | translate\"\n (click)=\"store.steerQueuedMessage(item.id)\">{{ 'nh-assistant.queue.steer' | translate }}</button>\n }\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\" [attr.title]=\"'nh-assistant.queue.edit' | translate\"\n (click)=\"editQueuedMessage(item.id, item.text)\"><nh-assistant-icon name=\"edit\" /></button>\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.remove' | translate\" [attr.title]=\"'nh-assistant.queue.remove' | translate\"\n (click)=\"store.removeQueuedMessage(item.id)\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n }\n </li>\n }\n </ol>\n </section>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [queueWhileBusy]=\"true\"\n [status]=\"composerStatus()\"\n [statusActor]=\"activeMemberName()\"\n [canStop]=\"canStop()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\">\n @if (store.agents().length > 1) {\n <nh-assistant-agent-picker\n nhAssistantComposerControls\n [compact]=\"true\"\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </nh-assistant-composer>\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}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:2px;min-width:0}.header-actions .icon-button{width:32px;height:32px}.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{padding:12px 16px 14px}.conversation-actions{display:flex;align-items:center;gap:4px;margin:0 -4px 6px}.page-context-button{margin-left:auto}.message-queue{margin-bottom:10px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);background:var(--nha-background);overflow:hidden;font-size:12px}.queue-heading{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px;color:var(--nha-text-muted)}.queue-items{max-height:180px;overflow-y:auto;margin:0;padding:0;list-style:none}.queue-item{display:flex;align-items:center;gap:8px;border-top:1px solid var(--nha-border);padding:6px 8px 6px 10px}.queue-item.failed{border-left:2px solid var(--nha-danger)}.queue-message{flex:1;min-width:0}.queue-message p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;margin:0}.queue-state{color:var(--nha-text-muted);font-size:11px}.queue-buttons{display:flex;flex-shrink:0;align-items:center;gap:2px}.queue-buttons .icon-button{width:28px;height:30px}.queue-resume,.queue-steer{border:0;border-radius:6px;padding:6px;color:var(--nha-highlight);background:transparent;font:inherit;cursor:pointer}.queue-resume:hover,.queue-steer:hover{background:var(--nha-surface)}.queue-resume:focus-visible,.queue-steer:focus-visible{outline:2px solid var(--nha-focus)}.queue-resume:disabled,.queue-steer:disabled{cursor:not-allowed;opacity:.5}.queue-edit{width:100%}.queue-edit textarea{box-sizing:border-box;width:100%;border:1px solid var(--nha-border);border-radius:6px;padding:8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;resize:vertical}.queue-edit .queue-buttons{justify-content:flex-end}.notification-button{position:relative}.notification-button.off:after{content:\"\";position:absolute;width:18px;height:2px;border-radius:1px;background:currentColor;transform:rotate(-45deg)}.notification-button.blocked{color:var(--nha-warning)}@media(max-width:359px){.header{gap:6px;padding-inline:12px}.header-actions .icon-button{width:28px;height:32px}}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"] }]
7943
+ ], 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 </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n @if (push.state() !== 'unavailable') {\n <button\n class=\"icon-button notification-button\"\n type=\"button\"\n [class.active]=\"push.state() === 'on'\"\n [class.off]=\"!push.settings()?.pushEnabled\"\n [class.blocked]=\"push.state() === 'blocked'\"\n [disabled]=\"push.busy()\"\n [attr.aria-pressed]=\"push.settings()?.pushEnabled === true\"\n [attr.aria-label]=\"notificationsLabel() | translate\"\n [attr.title]=\"('nh-assistant.preferences.notifications-state.' + push.state() | translate) + ' \u00B7 ' + (notificationsLabel() | translate)\"\n (click)=\"toggleNotifications()\">\n <nh-assistant-icon name=\"bell\" />\n </button>\n }\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 [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 @if (store.enabled()) {\n <nh-assistant-activity [items]=\"store.activity()\" (conversationSelect)=\"openConversation($event)\" />\n }\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 (showShare()) {\n <nh-assistant-share class=\"overlay-view\" [section]=\"shareSection()\" (closed)=\"showShare.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 (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 [attr.inert]=\"showPreferences() || showShare() || showConversations() ? '' : null\"\n [messages]=\"messages()\"\n [streaming]=\"busy()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n [members]=\"store.members()\"\n [currentActorId]=\"conversation()?.currentActorId ?? null\"\n [canDecide]=\"store.canDecide()\"\n [decisionOwner]=\"activeMemberName()\"\n [approvalRights]=\"store.approvalRights()\"\n (approvalChoice)=\"decideApproval($event)\" />\n }\n }\n </div>\n\n @if (notificationError() ?? 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(); notificationError.set(null)\">\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() && !showShare()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n } @else if (lastTurnFailed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.last-turn-failed' | translate }}</p>\n }\n @if (store.collaboration() || store.pageContext()) {\n <div class=\"conversation-actions\">\n @if (store.collaboration()) {\n @if (!conversation() || store.isOwner()) {\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [attr.aria-label]=\"'nh-assistant.panel.share' | translate\"\n [attr.title]=\"'nh-assistant.panel.share' | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'link'\"\n (click)=\"toggleShare('link')\">\n <nh-assistant-icon name=\"link\" />\n </button>\n }\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [class.active]=\"shared()\"\n [attr.aria-label]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.title]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'members'\"\n (click)=\"toggleShare('members')\">\n <nh-assistant-icon name=\"users\" />\n </button>\n }\n @if (store.pageContext(); as context) {\n <button\n class=\"icon-button page-context-button\"\n [class.active]=\"!store.pageContextExcluded()\"\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=\"page\" />\n </button>\n }\n </div>\n }\n @if (store.queuedMessages().length > 0) {\n <section class=\"message-queue\" [attr.aria-label]=\"'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length }\">\n <div class=\"queue-heading\">\n <span aria-live=\"polite\">{{ 'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length } }}</span>\n @if (store.queuePaused()) {\n <button type=\"button\" class=\"queue-resume\" [disabled]=\"editingQueuedId() !== null\" (click)=\"store.resumeQueue()\">\n {{ 'nh-assistant.queue.resume' | translate }}\n </button>\n }\n </div>\n <ol class=\"queue-items\">\n @for (item of store.queuedMessages(); track item.id) {\n <li class=\"queue-item\" [class.failed]=\"item.state === 'failed'\">\n @if (editingQueuedId() === item.id && item.state !== 'sending') {\n <div class=\"queue-edit\">\n <textarea rows=\"2\" [value]=\"queuedDraft()\" (input)=\"changeQueuedDraft($event)\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\"></textarea>\n <div class=\"queue-buttons\">\n <button type=\"button\" class=\"icon-button\" [disabled]=\"!validQueuedDraft()\"\n [attr.aria-label]=\"'nh-assistant.queue.save' | translate\" [attr.title]=\"'nh-assistant.queue.save' | translate\"\n (click)=\"saveQueuedMessage(item.id)\"><nh-assistant-icon name=\"check\" /></button>\n <button type=\"button\" class=\"icon-button\" [attr.aria-label]=\"'nh-assistant.queue.cancel-edit' | translate\"\n [attr.title]=\"'nh-assistant.queue.cancel-edit' | translate\"\n (click)=\"cancelQueueEdit()\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n </div>\n } @else {\n <div class=\"queue-message\">\n <p [title]=\"item.text\">{{ item.text }}</p>\n @if (item.state !== 'queued') {\n <span class=\"queue-state\">{{ 'nh-assistant.queue.state.' + item.state | translate }}</span>\n }\n </div>\n <div class=\"queue-buttons\">\n @if (store.canSteer() && item.state === 'queued') {\n <button type=\"button\" class=\"queue-steer\" [disabled]=\"editingQueuedId() !== null\"\n [attr.title]=\"'nh-assistant.queue.steer-hint' | translate\"\n (click)=\"store.steerQueuedMessage(item.id)\">{{ 'nh-assistant.queue.steer' | translate }}</button>\n }\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\" [attr.title]=\"'nh-assistant.queue.edit' | translate\"\n (click)=\"editQueuedMessage(item.id, item.text)\"><nh-assistant-icon name=\"edit\" /></button>\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.remove' | translate\" [attr.title]=\"'nh-assistant.queue.remove' | translate\"\n (click)=\"store.removeQueuedMessage(item.id)\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n }\n </li>\n }\n </ol>\n </section>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [queueWhileBusy]=\"true\"\n [status]=\"composerStatus()\"\n [statusActor]=\"activeMemberName()\"\n [canStop]=\"canStop()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (cancel)=\"cancel()\">\n @if (store.agents().length > 1) {\n <nh-assistant-agent-picker\n nhAssistantComposerControls\n [compact]=\"true\"\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </nh-assistant-composer>\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}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:2px;min-width:0}.header-actions .icon-button{width:32px;height:32px}.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{padding:12px 16px 14px}.conversation-actions{display:flex;align-items:center;gap:4px;margin:0 -4px 6px}.page-context-button{margin-left:auto}.message-queue{margin-bottom:10px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);background:var(--nha-background);overflow:hidden;font-size:12px}.queue-heading{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px;color:var(--nha-text-muted)}.queue-items{max-height:180px;overflow-y:auto;margin:0;padding:0;list-style:none}.queue-item{display:flex;align-items:center;gap:8px;border-top:1px solid var(--nha-border);padding:6px 8px 6px 10px}.queue-item.failed{border-left:2px solid var(--nha-danger)}.queue-message{flex:1;min-width:0}.queue-message p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;margin:0}.queue-state{color:var(--nha-text-muted);font-size:11px}.queue-buttons{display:flex;flex-shrink:0;align-items:center;gap:2px}.queue-buttons .icon-button{width:28px;height:30px}.queue-resume,.queue-steer{border:0;border-radius:6px;padding:6px;color:var(--nha-highlight);background:transparent;font:inherit;cursor:pointer}.queue-resume:hover,.queue-steer:hover{background:var(--nha-surface)}.queue-resume:focus-visible,.queue-steer:focus-visible{outline:2px solid var(--nha-focus)}.queue-resume:disabled,.queue-steer:disabled{cursor:not-allowed;opacity:.5}.queue-edit{width:100%}.queue-edit textarea{box-sizing:border-box;width:100%;border:1px solid var(--nha-border);border-radius:6px;padding:8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;resize:vertical}.queue-edit .queue-buttons{justify-content:flex-end}.notification-button{position:relative}.notification-button.off:after{content:\"\";position:absolute;width:18px;height:2px;border-radius:1px;background:currentColor;transform:rotate(-45deg)}.notification-button.blocked{color:var(--nha-warning)}@media(max-width:359px){.header{gap:6px;padding-inline:12px}.header-actions .icon-button{width:28px;height:32px}}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"] }]
7343
7944
  }], ctorParameters: () => [], propDecorators: { drawer: [{ type: i0.ViewChild, args: ['drawer', { isSignal: true }] }] } });
7344
7945
 
7345
7946
  /**