@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.
- package/README.md +5 -0
- package/admin/index.d.ts +194 -5
- package/fesm2022/newheap-platform-ai-chat-admin.mjs +551 -20
- package/fesm2022/newheap-platform-ai-chat-admin.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs +2 -2
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-testing.mjs +703 -6
- package/fesm2022/newheap-platform-ai-chat-testing.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat.mjs +631 -30
- package/fesm2022/newheap-platform-ai-chat.mjs.map +1 -1
- package/i18n/en.json +238 -4
- package/i18n/nl.json +238 -4
- package/index.d.ts +411 -6
- package/package.json +1 -1
- package/testing/index.d.ts +19 -2
|
@@ -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
|
|
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
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
7136
|
-
|
|
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
|
/**
|