@newheap/platform-ai-chat 0.16.0 → 0.18.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 +24 -1
- package/admin/index.d.ts +92 -6
- package/agent-runs/index.d.ts +188 -9
- package/fesm2022/newheap-platform-ai-chat-admin.mjs +885 -157
- package/fesm2022/newheap-platform-ai-chat-admin.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs +392 -40
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-testing.mjs +1044 -61
- package/fesm2022/newheap-platform-ai-chat-testing.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat.mjs +1074 -187
- package/fesm2022/newheap-platform-ai-chat.mjs.map +1 -1
- package/i18n/en.json +257 -13
- package/i18n/nl.json +257 -13
- package/index.d.ts +550 -32
- package/package.json +1 -1
- package/testing/index.d.ts +141 -3
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { InjectionToken, inject, DestroyRef, Injectable, EnvironmentInjector, runInInjectionContext, PLATFORM_ID, signal, computed, effect, untracked, Injector, afterNextRender, makeEnvironmentProviders, provideEnvironmentInitializer, input, ChangeDetectionStrategy, Component, ChangeDetectorRef, Pipe, output, ElementRef, viewChild, HostListener, linkedSignal, ViewContainerRef } from '@angular/core';
|
|
3
3
|
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
|
4
4
|
import { merge, Observable, of, forkJoin, map, Subject, catchError, throwError, switchMap, NEVER, firstValueFrom, Subscription, isObservable, filter, debounceTime, BehaviorSubject } from 'rxjs';
|
|
5
|
-
import { isPlatformBrowser, DOCUMENT, DatePipe,
|
|
5
|
+
import { isPlatformBrowser, DOCUMENT, DatePipe, LocationStrategy, NgTemplateOutlet } from '@angular/common';
|
|
6
6
|
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
7
7
|
import { Overlay } from '@angular/cdk/overlay';
|
|
8
8
|
import { TemplatePortal } from '@angular/cdk/portal';
|
|
@@ -236,7 +236,11 @@ var en = {
|
|
|
236
236
|
trigger: "Event",
|
|
237
237
|
rule: "Automatic rule",
|
|
238
238
|
files: "Attached files",
|
|
239
|
-
"file-meta": "{{type}}, {{size}}"
|
|
239
|
+
"file-meta": "{{type}}, {{size}}",
|
|
240
|
+
application: "Application",
|
|
241
|
+
"application-label": "Message from the application",
|
|
242
|
+
"application-link": "Open",
|
|
243
|
+
"application-trusted": "Instruction for the assistant"
|
|
240
244
|
},
|
|
241
245
|
composer: {
|
|
242
246
|
label: "Message",
|
|
@@ -354,6 +358,7 @@ var en = {
|
|
|
354
358
|
"waiting-for-participant": "Waiting for the participant who started this task to decide.",
|
|
355
359
|
"waiting-for-approver": "Waiting for an approver to decide.",
|
|
356
360
|
"waiting-for-other-approver": "You started this work, so another approver decides.",
|
|
361
|
+
"waiting-for-asker": "Waiting for the person who asked to decide in their own chat.",
|
|
357
362
|
"give-feedback": "What was wrong?",
|
|
358
363
|
"stale-kind": {
|
|
359
364
|
"already-done": "Already done",
|
|
@@ -361,7 +366,20 @@ var en = {
|
|
|
361
366
|
"not-applicable": "No longer needed"
|
|
362
367
|
},
|
|
363
368
|
rationale: "Why: {{rationale}}",
|
|
364
|
-
superseded: "Replaced by a newer proposal"
|
|
369
|
+
superseded: "Replaced by a newer proposal",
|
|
370
|
+
consultation: {
|
|
371
|
+
origin: "{{agent}} proposes this, about {{subject}}",
|
|
372
|
+
answer: "Answer of {{agent}}",
|
|
373
|
+
"own-rights": "Approving runs it right away with your own rights.",
|
|
374
|
+
leave: "Leave for approvers",
|
|
375
|
+
"leave-label": "Leave for approvers: {{summary}}",
|
|
376
|
+
"leave-explain": {
|
|
377
|
+
"subject-agent-rights": "The approvers of {{subject}} decide; it then runs with the agent's own rights.",
|
|
378
|
+
"subject-asker-rights": "The approvers of {{subject}} decide; it then runs with your rights."
|
|
379
|
+
},
|
|
380
|
+
"moved-status": "Left for approvers",
|
|
381
|
+
moved: "It now waits for the approvers of {{subject}}."
|
|
382
|
+
}
|
|
365
383
|
},
|
|
366
384
|
"proposal-feedback": {
|
|
367
385
|
legend: "What was wrong? (optional)",
|
|
@@ -569,16 +587,21 @@ var en = {
|
|
|
569
587
|
"assistant-consult-timeout": "The agent did not answer in time.",
|
|
570
588
|
"assistant-consult-failed": "The agent could not answer.",
|
|
571
589
|
"assistant-consult-read-only": "A consultation cannot change anything.",
|
|
590
|
+
"assistant-consult-proposal-refused": "No route at the subject takes this proposal any more. Approve or reject it here.",
|
|
591
|
+
"assistant-consult-asker-decides": "The person who asked decides this proposal in their own chat.",
|
|
592
|
+
"assistant-consult-route-not-allowed": "None of the agent's consultations allows this route, so it cannot be switched on.",
|
|
593
|
+
"assistant-consult-proposal-moved": "The proposal was left for the subject's approvers.",
|
|
572
594
|
"assistant-moved-to-shadow": "The work went to the agent's shadow thread, where a run in shadow takes it.",
|
|
573
595
|
"assistant-shadow-variant": "A shadow variant always works in shadow.",
|
|
574
596
|
"assistant-service-account-not-used": "This agent does not answer to a technical account.",
|
|
575
597
|
"assistant-service-account-not-found": "No account that may sign in exists with this id.",
|
|
576
598
|
"assistant-skill-in-code": "This skill is part of the code and cannot change here.",
|
|
577
599
|
"assistant-trigger-in-code": "This trigger is part of the code and cannot change here.",
|
|
600
|
+
"assistant-trigger-filter-not-found": "The event has no filter with this name. Choose from the filters the event offers.",
|
|
578
601
|
"assistant-skill-in-use": "A trigger still starts this skill. Change or remove the trigger first.",
|
|
579
|
-
"assistant-configuration-limit": "This agent already has as many skills or
|
|
602
|
+
"assistant-configuration-limit": "This agent already has as many skills, triggers or consultations as allowed.",
|
|
580
603
|
"assistant-run-settings-in-code": "This agent is part of the code; its runs are configured there.",
|
|
581
|
-
"assistant-run-settings-in-use": "Skills or
|
|
604
|
+
"assistant-run-settings-in-use": "Skills, triggers or consultations still belong to this agent. Remove them first.",
|
|
582
605
|
"assistant-skill-candidate-not-found": "This skill has no version being evaluated in shadow.",
|
|
583
606
|
"assistant-skill-version-gone": "The skill version this run was for is no longer evaluated.",
|
|
584
607
|
"assistant-account-search-unavailable": "The application offers no account search; enter the account's id.",
|
|
@@ -606,7 +629,10 @@ var en = {
|
|
|
606
629
|
"assistant-file-type-not-accepted": "This type of file cannot be attached.",
|
|
607
630
|
"assistant-file-upload-refused": "The application refused this file.",
|
|
608
631
|
"assistant-file-upload-failed": "The file could not be stored right now. Try again in a moment.",
|
|
609
|
-
"assistant-file-scan-refused": "The file did not pass the scan for harmful content and was not stored."
|
|
632
|
+
"assistant-file-scan-refused": "The file did not pass the scan for harmful content and was not stored.",
|
|
633
|
+
"assistant-consultation-in-code": "The agent allows consultation about this kind of object in code; it cannot change here.",
|
|
634
|
+
"assistant-consultation-not-found": "The consultation was not found.",
|
|
635
|
+
"assistant-consultations-not-allowed": "The application does not let administrators add consultations to this agent."
|
|
610
636
|
},
|
|
611
637
|
notices: {
|
|
612
638
|
"no-answer": "The assistant finished without an answer. Try again or rephrase your question.",
|
|
@@ -764,6 +790,8 @@ var en = {
|
|
|
764
790
|
changed: "Changed by {{user}} on {{date}}.",
|
|
765
791
|
reason: "Note: {{reason}}",
|
|
766
792
|
waiting: "{{count}} events wait for the resume.",
|
|
793
|
+
"stopped-was-off-hint": "It was off when it stopped: releasing the kill switch switches it back off. Resume switches it on.",
|
|
794
|
+
"stopped-was-on-hint": "It was not off when it stopped: releasing the kill switch makes it work again, as Resume does.",
|
|
767
795
|
action: {
|
|
768
796
|
active: "Resume",
|
|
769
797
|
paused: "Pause",
|
|
@@ -851,6 +879,44 @@ var en = {
|
|
|
851
879
|
},
|
|
852
880
|
"input-label-search": "Account"
|
|
853
881
|
},
|
|
882
|
+
"consultation-routes": {
|
|
883
|
+
title: "Consultation routes",
|
|
884
|
+
description: "Switch a route off for all consultations of this agent at once, in code and in the administration. When another assistant consults this agent and the agent proposes a change, a route decides who decides it and whose rights run it.",
|
|
885
|
+
"load-failed": "The consultation routes could not be read.",
|
|
886
|
+
route: {
|
|
887
|
+
"asker-decides": "The person who asked decides",
|
|
888
|
+
"subject-agent-rights": "Approvers decide, agent's rights",
|
|
889
|
+
"subject-asker-rights": "Approvers decide, asker's rights"
|
|
890
|
+
},
|
|
891
|
+
explain: {
|
|
892
|
+
"asker-decides": "The person who asked decides in their own chat; it runs with their own rights.",
|
|
893
|
+
"subject-agent-rights": "The subject's approvers other than the person who asked decide; it runs with the agent's own rights.",
|
|
894
|
+
"subject-asker-rights": "The subject's approvers decide; it runs later with the rights of the person who asked."
|
|
895
|
+
},
|
|
896
|
+
on: "On",
|
|
897
|
+
off: "Off",
|
|
898
|
+
code: "As the consultations allow",
|
|
899
|
+
overridden: "Overridden",
|
|
900
|
+
"not-allowed": "Not allowed",
|
|
901
|
+
"not-allowed-hint": "No consultation of this agent allows this route, so it stays off and cannot be switched on.",
|
|
902
|
+
"subject-types": "For: {{types}}",
|
|
903
|
+
action: {
|
|
904
|
+
on: "Switch on",
|
|
905
|
+
off: "Switch off",
|
|
906
|
+
code: "Back to what the consultations allow"
|
|
907
|
+
},
|
|
908
|
+
"explain-change": {
|
|
909
|
+
on: "Consultations use this route for new proposals again. Proposals already recorded keep their route.",
|
|
910
|
+
off: "Consultations no longer use this route for new proposals; with every route off, the agent's consultations only read. Proposals already recorded keep their route.",
|
|
911
|
+
"code-on": "The consultations decide again: one of them allows this route, so it is on.",
|
|
912
|
+
"code-off": "The consultations decide again: none of them allows this route, so it stays off."
|
|
913
|
+
},
|
|
914
|
+
confirm: {
|
|
915
|
+
on: "Confirm switching on",
|
|
916
|
+
off: "Confirm switching off",
|
|
917
|
+
code: "Confirm"
|
|
918
|
+
}
|
|
919
|
+
},
|
|
854
920
|
"run-config": "Run configuration",
|
|
855
921
|
"run-now": "Run now",
|
|
856
922
|
runs: "Runs",
|
|
@@ -888,7 +954,7 @@ var en = {
|
|
|
888
954
|
instructions: "Instructions",
|
|
889
955
|
"instructions-hint": "What the agent does and how it answers.",
|
|
890
956
|
autonomy: "Autonomy",
|
|
891
|
-
"autonomy-hint": "Only Execute allows changes, and
|
|
957
|
+
"autonomy-hint": "Only Execute allows changes in the agent's own work. In a consultation that may propose, Propose and Simulate propose changes too. Every change still needs approval.",
|
|
892
958
|
"required-policy": "Required policy",
|
|
893
959
|
"required-policy-hint": "Optional. Only users who pass this policy see the agent.",
|
|
894
960
|
profile: "Model profile",
|
|
@@ -1308,7 +1374,8 @@ var en = {
|
|
|
1308
1374
|
agent: "Run settings:",
|
|
1309
1375
|
skill: "Skill {{id}}:",
|
|
1310
1376
|
candidate: "Candidate of skill {{id}}:",
|
|
1311
|
-
trigger: "Trigger {{id}}:"
|
|
1377
|
+
trigger: "Trigger {{id}}:",
|
|
1378
|
+
consultation: "Consultation about {{id}}:"
|
|
1312
1379
|
},
|
|
1313
1380
|
code: {
|
|
1314
1381
|
"unknown-agent": "the agent can no longer run on its own.",
|
|
@@ -1319,11 +1386,23 @@ var en = {
|
|
|
1319
1386
|
"unknown-policy": "the approval policy no longer exists.",
|
|
1320
1387
|
"unknown-rule-handler": "the rules no longer exist.",
|
|
1321
1388
|
"unknown-event": "the event no longer exists.",
|
|
1389
|
+
"unknown-filter": "a filter of the event no longer exists, so the trigger starts nothing until you remove it.",
|
|
1322
1390
|
"unknown-subject-set": "the set of subjects no longer exists.",
|
|
1323
1391
|
"unknown-skill": "the skill no longer exists.",
|
|
1324
1392
|
"invalid-schedule": "the schedule or its time zone is not valid.",
|
|
1325
1393
|
invalid: "a value is not valid.",
|
|
1326
|
-
"not-worked-on": "it concerns a kind of object, or the whole application, that the agent does not work on."
|
|
1394
|
+
"not-worked-on": "it concerns a kind of object, or the whole application, that the agent does not work on.",
|
|
1395
|
+
"unknown-subject-type": "the kind of object no longer exists.",
|
|
1396
|
+
"unknown-agent-policy": "the policy the people who ask need is no longer listed.",
|
|
1397
|
+
"conflicts-with-tool": "another tool already has the name of its tool.",
|
|
1398
|
+
"not-consultable": "the application no longer lets administrators add consultations to this agent.",
|
|
1399
|
+
"route-not-allowed": "a route is no longer allowed, so it is left out.",
|
|
1400
|
+
"agent-answers-to-person": "the route with the agent's account is left out, because the agent answers to the object's responsible person.",
|
|
1401
|
+
"agent-has-no-rights": "the route with the agent's account is left out, because the agent answers for itself and has no rights of its own.",
|
|
1402
|
+
"no-approver": "the route with the agent's account is left out, because the approval policy lets only the person who caused a proposal decide it.",
|
|
1403
|
+
"limit-above-ceiling": "a limit is above what the application allows, so the application's applies.",
|
|
1404
|
+
"requests-not-allowed": "the application no longer allows requests, so it takes none.",
|
|
1405
|
+
"mcp-not-allowed": "the application no longer offers consultations to MCP clients, so they do not see it."
|
|
1327
1406
|
}
|
|
1328
1407
|
},
|
|
1329
1408
|
"field-errors": {
|
|
@@ -1340,7 +1419,9 @@ var en = {
|
|
|
1340
1419
|
"instructions-for-model": "Without fixed rules the model works from these instructions; describe what it should do.",
|
|
1341
1420
|
"application-not-worked-on": "The agent does not work on the whole application. Choose a set of objects, or let the agent work on the whole application first.",
|
|
1342
1421
|
"megabytes-up-to": "Enter a size above 0 and at most {{max}} MB.",
|
|
1343
|
-
"megabytes-positive": "Enter a size above 0 MB."
|
|
1422
|
+
"megabytes-positive": "Enter a size above 0 MB.",
|
|
1423
|
+
"not-allowed": "The application does not allow this.",
|
|
1424
|
+
"routes-required": "Choose at least one route, or let it only answer."
|
|
1344
1425
|
},
|
|
1345
1426
|
settings: {
|
|
1346
1427
|
title: "Run settings",
|
|
@@ -1551,6 +1632,13 @@ var en = {
|
|
|
1551
1632
|
"source-schedule-hint": "At fixed times, for every subject in a set.",
|
|
1552
1633
|
"source-schedule-application-hint": "At fixed times, for the whole application or for every object in a set.",
|
|
1553
1634
|
"debounce-hint": "Waits this long for more events about the same subject and handles them in one run.",
|
|
1635
|
+
filters: {
|
|
1636
|
+
title: "Filters",
|
|
1637
|
+
hint: "Skip events this trigger should not start the agent on, such as changes the agent made itself. Every filter you select must let an event through.",
|
|
1638
|
+
empty: "This event offers no filters.",
|
|
1639
|
+
missing: "The event no longer offers this filter, so the trigger starts nothing. Clear it to save.",
|
|
1640
|
+
applied: "Filters: {{filters}}"
|
|
1641
|
+
},
|
|
1554
1642
|
"subject-set-hint": "The projects or customers the schedule handles each time.",
|
|
1555
1643
|
"message-hint": "What the agent reads as its task each time.",
|
|
1556
1644
|
examples: "Examples",
|
|
@@ -1711,7 +1799,14 @@ var en = {
|
|
|
1711
1799
|
"configured-off": "Run now: not while the application's code switches the agent off.",
|
|
1712
1800
|
"no-settings": "Run now: only once the agent has run settings.",
|
|
1713
1801
|
"no-catalog": "Run now: not until the run catalog can be read."
|
|
1714
|
-
}
|
|
1802
|
+
},
|
|
1803
|
+
consultations: "When another assistant consults it",
|
|
1804
|
+
"no-consultations": "No other assistant can consult it yet.",
|
|
1805
|
+
"consultation-proposes": "Answers and proposes",
|
|
1806
|
+
"consultation-answers": "Only answers",
|
|
1807
|
+
"asked-by-none": "No agent asks it yet",
|
|
1808
|
+
"asked-by-one": "Asked by 1 agent",
|
|
1809
|
+
"asked-by": "Asked by {{count}} agents"
|
|
1715
1810
|
},
|
|
1716
1811
|
skills: {
|
|
1717
1812
|
"code-rules": "Fixed rules in the application's code",
|
|
@@ -1794,7 +1889,124 @@ var en = {
|
|
|
1794
1889
|
"edit-trigger": "Change the trigger",
|
|
1795
1890
|
"edit-skill": "Change the skill",
|
|
1796
1891
|
"edit-trigger-named": "Edit trigger {{trigger}}",
|
|
1797
|
-
"edit-skill-named": "Edit skill {{skill}}"
|
|
1892
|
+
"edit-skill-named": "Edit skill {{skill}}",
|
|
1893
|
+
"edit-consultation": "Change the consultation",
|
|
1894
|
+
"edit-consultation-named": "Edit the consultation about {{type}}"
|
|
1895
|
+
}
|
|
1896
|
+
},
|
|
1897
|
+
consultations: {
|
|
1898
|
+
title: "Consultations",
|
|
1899
|
+
description: "Other assistants may consult this agent about an object. It answers with the rights of the person who asked and, where allowed, proposes changes. A consultation works only once an agent that asks selects its tool.",
|
|
1900
|
+
add: "Add consultation",
|
|
1901
|
+
empty: "Nobody can consult this agent yet.",
|
|
1902
|
+
closed: {
|
|
1903
|
+
application: "The application does not let administrators add consultations; they come from its code.",
|
|
1904
|
+
agent: "This agent is defined in code and does not let administrators add consultations to it.",
|
|
1905
|
+
"needs-settings": "Give the agent run settings before you add consultations.",
|
|
1906
|
+
limit: "This agent has as many consultations as allowed ({{max}}).",
|
|
1907
|
+
"no-types": "Every kind of object this agent works on already has a consultation."
|
|
1908
|
+
},
|
|
1909
|
+
requests: "Takes requests",
|
|
1910
|
+
mcp: "Offered to MCP clients",
|
|
1911
|
+
"no-description": "No description.",
|
|
1912
|
+
askers: "Asked by:",
|
|
1913
|
+
"open-asker": "Open the editor of {{agent}}",
|
|
1914
|
+
"no-askers": "No agent asks it yet. Select its tool in the tools of an agent that should ask it.",
|
|
1915
|
+
"code-hint": "Allowed in code; here only the route switches below change it.",
|
|
1916
|
+
"limits-value": "At most {{calls}} tool calls, {{seconds}} seconds, {{chars}} characters and {{history}} thread messages",
|
|
1917
|
+
"edit-named": "Edit the consultation about {{type}}",
|
|
1918
|
+
"remove-named": "Delete the consultation about {{type}}",
|
|
1919
|
+
"remove-explain": "Its tools disappear; proposals it made can still be decided.",
|
|
1920
|
+
added: "The consultation was added. It answers once an agent that asks selects its tool.",
|
|
1921
|
+
saved: "The consultation was saved.",
|
|
1922
|
+
removed: "The consultation was removed.",
|
|
1923
|
+
roles: {
|
|
1924
|
+
reader: "Reader",
|
|
1925
|
+
participant: "Participant",
|
|
1926
|
+
approver: "Approver"
|
|
1927
|
+
},
|
|
1928
|
+
"roles-lower": {
|
|
1929
|
+
reader: "reader",
|
|
1930
|
+
participant: "participant",
|
|
1931
|
+
approver: "approver"
|
|
1932
|
+
},
|
|
1933
|
+
summary: {
|
|
1934
|
+
ask: "People who are at least {{role}} of the object may ask.",
|
|
1935
|
+
"asker-policy": "They also need {{policy}}.",
|
|
1936
|
+
"asker-policy-agent": "They also need the policy the agent requires, or else access to the assistant.",
|
|
1937
|
+
"read-only": "The agent only answers and proposes nothing.",
|
|
1938
|
+
proposes: "The agent may propose changes when the person who asked is at least {{role}}: {{routes}}.",
|
|
1939
|
+
"proposes-code": "The agent may propose changes: {{routes}}."
|
|
1940
|
+
},
|
|
1941
|
+
routes: {
|
|
1942
|
+
"asker-decides": "The person who asked decides in their chat",
|
|
1943
|
+
"subject-asker-rights": "The object's approvers decide, with the rights of the person who asked",
|
|
1944
|
+
"subject-agent-rights": "The object's approvers decide, with this agent's technical account"
|
|
1945
|
+
},
|
|
1946
|
+
"routes-hint": {
|
|
1947
|
+
"asker-decides": "Approving runs it at once with that person's own rights.",
|
|
1948
|
+
"subject-asker-rights": "It waits at the object and runs later with the rights of the person who asked.",
|
|
1949
|
+
"subject-agent-rights": "It waits at the object for an approver other than the person who asked and runs with the agent's own rights."
|
|
1950
|
+
},
|
|
1951
|
+
"route-blocks": {
|
|
1952
|
+
"not-in-ceiling": "The application does not allow this route.",
|
|
1953
|
+
system: "Not for the whole application.",
|
|
1954
|
+
"agent-answers-to-person": "Not for an agent that answers to the object's responsible person.",
|
|
1955
|
+
"agent-has-no-rights": "Not for an agent that answers for itself: it has no rights of its own to lend."
|
|
1956
|
+
},
|
|
1957
|
+
limits: {
|
|
1958
|
+
"tool-calls": "Tool calls",
|
|
1959
|
+
"timeout-seconds": "Time limit in seconds",
|
|
1960
|
+
"answer-chars": "Longest answer in characters",
|
|
1961
|
+
"history-messages": "Thread messages it reads"
|
|
1962
|
+
},
|
|
1963
|
+
form: {
|
|
1964
|
+
"new-title": "New consultation",
|
|
1965
|
+
"edit-title": "Consultation about {{type}}, version {{version}}",
|
|
1966
|
+
what: "What may other assistants consult it about?",
|
|
1967
|
+
"subject-type": "Kind of object",
|
|
1968
|
+
"subject-type-hint": "Only kinds of objects the agent works on and has no consultation about yet.",
|
|
1969
|
+
description: "When to consult it",
|
|
1970
|
+
"description-hint": "The assistant that asks reads this to decide when to consult this agent.",
|
|
1971
|
+
instructions: "Instructions when consulted",
|
|
1972
|
+
"instructions-hint": "Optional. What the agent keeps in mind when it answers, after the platform's own rules for consultations.",
|
|
1973
|
+
who: "Who may ask?",
|
|
1974
|
+
"minimum-role": "The person who asks is at least",
|
|
1975
|
+
"role-hint": {
|
|
1976
|
+
reader: "Anyone who may read the object.",
|
|
1977
|
+
participant: "People who work on the object.",
|
|
1978
|
+
approver: "People who approve changes to the object."
|
|
1979
|
+
},
|
|
1980
|
+
"asker-policy": "Policy the person needs",
|
|
1981
|
+
"asker-policy-agent": "The policy the agent requires",
|
|
1982
|
+
"asker-policy-hint": "One of the policies the application lists. Without one, the agent's own policy applies, or else access to the assistant.",
|
|
1983
|
+
"do": "What may it do?",
|
|
1984
|
+
answer: "Only answer",
|
|
1985
|
+
"answer-hint": "It answers with the rights of the person who asked and proposes nothing.",
|
|
1986
|
+
propose: "Answer and propose changes",
|
|
1987
|
+
"propose-hint": "It may also propose changes; the routes below decide who decides them.",
|
|
1988
|
+
"answers-only": "The application lets consultations only answer.",
|
|
1989
|
+
routes: "Who decides its proposals?",
|
|
1990
|
+
"routes-hint": "Choose at least one. Of the two routes at the object, choose one at most.",
|
|
1991
|
+
"proposal-role": "Role needed for proposals",
|
|
1992
|
+
"proposal-role-hint": "The person who asked needs at least this role on the object before the agent may propose; with a lower role they get the answer without proposals.",
|
|
1993
|
+
"agent-policy": "The agent's approval policy",
|
|
1994
|
+
"policy-warning": {
|
|
1995
|
+
"four-eyes": "This approval policy uses four eyes, so the person who asked cannot decide their own proposal in their chat; that route does not apply.",
|
|
1996
|
+
"initiator-only": "This approval policy lets only the person who caused a proposal decide it, so the route with the agent's technical account is refused."
|
|
1997
|
+
},
|
|
1998
|
+
advanced: "Advanced: limits, requests and classification",
|
|
1999
|
+
limits: "Limits of one consultation",
|
|
2000
|
+
"limits-hint": "Empty starts at the default within what the application allows.",
|
|
2001
|
+
"limit-range": "From {{min}} to {{max}}.",
|
|
2002
|
+
requests: "Also take requests",
|
|
2003
|
+
"requests-hint": "The assistant that asks may also ask this agent to start a run, with the person as its initiator.",
|
|
2004
|
+
"requests-closed": "The application does not allow requests.",
|
|
2005
|
+
mcp: "Offer to MCP clients",
|
|
2006
|
+
"mcp-hint": "External MCP clients may consult it too, with the rights of their person.",
|
|
2007
|
+
"mcp-closed": "The application does not offer consultations to MCP clients.",
|
|
2008
|
+
"classification-hint": "How sensitive its answers are in the conversation that asked. Without one, the agent's classification applies.",
|
|
2009
|
+
"in-effect": "A consultation is in effect once saved; it answers once an agent that asks selects its tool."
|
|
1798
2010
|
}
|
|
1799
2011
|
}
|
|
1800
2012
|
},
|
|
@@ -1933,6 +2145,7 @@ var en = {
|
|
|
1933
2145
|
inbox: {
|
|
1934
2146
|
title: "Proposals to decide",
|
|
1935
2147
|
description: "Proposals of agents that wait for your decision, the ones that expire first on top.",
|
|
2148
|
+
"description-grouped": "Proposals of agents that wait for your decision, grouped by object; the group with the proposal that expires first is on top.",
|
|
1936
2149
|
empty: "No proposals wait for you.",
|
|
1937
2150
|
select: "Select this proposal",
|
|
1938
2151
|
"select-all": "Select all",
|
|
@@ -1941,7 +2154,18 @@ var en = {
|
|
|
1941
2154
|
previous: "Previous",
|
|
1942
2155
|
next: "Next",
|
|
1943
2156
|
page: "Page {{page}} of {{pages}}",
|
|
1944
|
-
pages: "Pages"
|
|
2157
|
+
pages: "Pages",
|
|
2158
|
+
"new": "New",
|
|
2159
|
+
"new-label": "New since your last visit",
|
|
2160
|
+
"last-visit": "You last looked here on {{date}}. What came since is marked new.",
|
|
2161
|
+
"first-visit": "Everything here is new for you.",
|
|
2162
|
+
"group-loaded": "{{loaded}} of {{total}} shown",
|
|
2163
|
+
"select-group": "Select the {{count}} shown",
|
|
2164
|
+
"select-group-label": "Select the {{count}} proposals of {{name}} shown on this page",
|
|
2165
|
+
"group-continued": "Continued from the previous page.",
|
|
2166
|
+
"group-continues": "More proposals of this group are on the next page.",
|
|
2167
|
+
run: "One run of {{agent}}, {{date}}",
|
|
2168
|
+
"no-run": "Proposed in a conversation"
|
|
1945
2169
|
},
|
|
1946
2170
|
proposal: {
|
|
1947
2171
|
approve: "Approve",
|
|
@@ -1971,7 +2195,22 @@ var en = {
|
|
|
1971
2195
|
shadow: "Shadow"
|
|
1972
2196
|
},
|
|
1973
2197
|
"from-consultation": "From a consultation",
|
|
1974
|
-
"from-consultation-hint": "Another assistant consulted the agent for
|
|
2198
|
+
"from-consultation-hint": "Another assistant consulted the agent for a person, and the agent proposed this.",
|
|
2199
|
+
consultation: {
|
|
2200
|
+
"asked-by": "Asked by {{name}}",
|
|
2201
|
+
"the-asker": "the person who asked",
|
|
2202
|
+
route: {
|
|
2203
|
+
"asker-decides": "The person who asked decides in their own chat; it runs with their own rights.",
|
|
2204
|
+
"subject-agent-rights": "The subject's approvers other than the person who asked decide; it runs with the agent's own rights.",
|
|
2205
|
+
"subject-asker-rights": "The subject's approvers decide; it runs with the rights of the person who asked."
|
|
2206
|
+
},
|
|
2207
|
+
"waiting-for-asker": "Waiting for {{name}} to decide in their own chat.",
|
|
2208
|
+
"four-eyes": "You asked for this, so another approver decides; it runs with the agent's own rights.",
|
|
2209
|
+
"runs-with": {
|
|
2210
|
+
agent: "Runs with the agent's rights",
|
|
2211
|
+
accountable: "Runs with the technical account's rights"
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
1975
2214
|
"give-feedback": "Give feedback",
|
|
1976
2215
|
"change-feedback": "Change feedback",
|
|
1977
2216
|
"your-feedback": "Your feedback: {{category}}",
|
|
@@ -2050,6 +2289,11 @@ var en = {
|
|
|
2050
2289
|
running: "Running",
|
|
2051
2290
|
completed: "Answered",
|
|
2052
2291
|
failed: "Not answered"
|
|
2292
|
+
},
|
|
2293
|
+
routes: {
|
|
2294
|
+
"asker-decides": "Asker decides: {{count}}",
|
|
2295
|
+
"subject-agent-rights": "Approvers, agent's rights: {{count}}",
|
|
2296
|
+
"subject-asker-rights": "Approvers, asker's rights: {{count}}"
|
|
2053
2297
|
}
|
|
2054
2298
|
},
|
|
2055
2299
|
"object-agents": {
|
|
@@ -2254,7 +2498,11 @@ var nl = {
|
|
|
2254
2498
|
trigger: "Gebeurtenis",
|
|
2255
2499
|
rule: "Automatische regel",
|
|
2256
2500
|
files: "Bijgevoegde bestanden",
|
|
2257
|
-
"file-meta": "{{type}}, {{size}}"
|
|
2501
|
+
"file-meta": "{{type}}, {{size}}",
|
|
2502
|
+
application: "Applicatie",
|
|
2503
|
+
"application-label": "Bericht van de applicatie",
|
|
2504
|
+
"application-link": "Openen",
|
|
2505
|
+
"application-trusted": "Instructie voor de assistent"
|
|
2258
2506
|
},
|
|
2259
2507
|
composer: {
|
|
2260
2508
|
label: "Bericht",
|
|
@@ -2372,6 +2620,7 @@ var nl = {
|
|
|
2372
2620
|
"waiting-for-participant": "Wacht op de beslissing van de deelnemer die deze taak startte.",
|
|
2373
2621
|
"waiting-for-approver": "Wacht tot een beslisser hierover beslist.",
|
|
2374
2622
|
"waiting-for-other-approver": "Jij startte dit werk, dus een andere beslisser beslist hierover.",
|
|
2623
|
+
"waiting-for-asker": "Wacht tot degene die het vroeg, beslist in de eigen chat.",
|
|
2375
2624
|
"give-feedback": "Wat klopte er niet?",
|
|
2376
2625
|
"stale-kind": {
|
|
2377
2626
|
"already-done": "Al gedaan",
|
|
@@ -2379,7 +2628,20 @@ var nl = {
|
|
|
2379
2628
|
"not-applicable": "Niet meer nodig"
|
|
2380
2629
|
},
|
|
2381
2630
|
rationale: "Waarom: {{rationale}}",
|
|
2382
|
-
superseded: "Vervangen door een nieuwer voorstel"
|
|
2631
|
+
superseded: "Vervangen door een nieuwer voorstel",
|
|
2632
|
+
consultation: {
|
|
2633
|
+
origin: "{{agent}} stelt dit voor, over {{subject}}",
|
|
2634
|
+
answer: "Antwoord van {{agent}}",
|
|
2635
|
+
"own-rights": "Goedkeuren voert het meteen uit met je eigen rechten.",
|
|
2636
|
+
leave: "Aan goedkeurders laten",
|
|
2637
|
+
"leave-label": "Aan goedkeurders laten: {{summary}}",
|
|
2638
|
+
"leave-explain": {
|
|
2639
|
+
"subject-agent-rights": "De goedkeurders van {{subject}} beslissen; daarna loopt het met de eigen rechten van de agent.",
|
|
2640
|
+
"subject-asker-rights": "De goedkeurders van {{subject}} beslissen; daarna loopt het met jouw rechten."
|
|
2641
|
+
},
|
|
2642
|
+
"moved-status": "Aan goedkeurders gelaten",
|
|
2643
|
+
moved: "Het wacht nu op de goedkeurders van {{subject}}."
|
|
2644
|
+
}
|
|
2383
2645
|
},
|
|
2384
2646
|
"proposal-feedback": {
|
|
2385
2647
|
legend: "Wat klopte er niet? (optioneel)",
|
|
@@ -2587,16 +2849,21 @@ var nl = {
|
|
|
2587
2849
|
"assistant-consult-timeout": "De agent antwoordde niet op tijd.",
|
|
2588
2850
|
"assistant-consult-failed": "De agent kon niet antwoorden.",
|
|
2589
2851
|
"assistant-consult-read-only": "Een raadpleging kan niets wijzigen.",
|
|
2852
|
+
"assistant-consult-proposal-refused": "Geen route bij het onderwerp neemt dit voorstel nog aan. Keur het hier goed of af.",
|
|
2853
|
+
"assistant-consult-asker-decides": "Degene die het vroeg, beslist over dit voorstel in de eigen chat.",
|
|
2854
|
+
"assistant-consult-route-not-allowed": "Geen van de raadplegingen van de agent staat deze route toe, dus die kan niet aan.",
|
|
2855
|
+
"assistant-consult-proposal-moved": "Het voorstel is aan de goedkeurders van het onderwerp gelaten.",
|
|
2590
2856
|
"assistant-moved-to-shadow": "Het werk is naar de schaduwthread van de agent gegaan, waar een run in schaduw het oppakt.",
|
|
2591
2857
|
"assistant-shadow-variant": "Een schaduwvariant werkt altijd in schaduw.",
|
|
2592
2858
|
"assistant-service-account-not-used": "Deze agent werkt niet onder een technisch account.",
|
|
2593
2859
|
"assistant-service-account-not-found": "Er bestaat geen account met deze id dat mag inloggen.",
|
|
2594
2860
|
"assistant-skill-in-code": "Deze vaardigheid staat in de code en kan hier niet veranderen.",
|
|
2595
2861
|
"assistant-trigger-in-code": "Deze trigger staat in de code en kan hier niet veranderen.",
|
|
2862
|
+
"assistant-trigger-filter-not-found": "De gebeurtenis heeft geen filter met deze naam. Kies uit de filters die de gebeurtenis biedt.",
|
|
2596
2863
|
"assistant-skill-in-use": "Een trigger start deze vaardigheid nog. Pas de trigger eerst aan of verwijder hem.",
|
|
2597
|
-
"assistant-configuration-limit": "Deze agent heeft al zoveel vaardigheden of
|
|
2864
|
+
"assistant-configuration-limit": "Deze agent heeft al zoveel vaardigheden, triggers of raadplegingen als is toegestaan.",
|
|
2598
2865
|
"assistant-run-settings-in-code": "Deze agent staat in de code; daar is ingesteld hoe hij werkt.",
|
|
2599
|
-
"assistant-run-settings-in-use": "Er horen nog vaardigheden of
|
|
2866
|
+
"assistant-run-settings-in-use": "Er horen nog vaardigheden, triggers of raadplegingen bij deze agent. Verwijder die eerst.",
|
|
2600
2867
|
"assistant-skill-candidate-not-found": "Van deze vaardigheid wordt geen versie in schaduw beoordeeld.",
|
|
2601
2868
|
"assistant-skill-version-gone": "De versie van de vaardigheid waarvoor deze run was, wordt niet meer beoordeeld.",
|
|
2602
2869
|
"assistant-account-search-unavailable": "De applicatie biedt geen accountzoeker; vul de id van het account in.",
|
|
@@ -2624,7 +2891,10 @@ var nl = {
|
|
|
2624
2891
|
"assistant-file-type-not-accepted": "Dit type bestand kan niet worden bijgevoegd.",
|
|
2625
2892
|
"assistant-file-upload-refused": "De applicatie heeft dit bestand geweigerd.",
|
|
2626
2893
|
"assistant-file-upload-failed": "Het bestand kon nu niet worden opgeslagen. Probeer het zo opnieuw.",
|
|
2627
|
-
"assistant-file-scan-refused": "Het bestand is niet door de scan op schadelijke inhoud gekomen en is niet opgeslagen."
|
|
2894
|
+
"assistant-file-scan-refused": "Het bestand is niet door de scan op schadelijke inhoud gekomen en is niet opgeslagen.",
|
|
2895
|
+
"assistant-consultation-in-code": "De agent staat raadpleging over deze soort object in code toe; die kan hier niet veranderen.",
|
|
2896
|
+
"assistant-consultation-not-found": "De raadpleging is niet gevonden.",
|
|
2897
|
+
"assistant-consultations-not-allowed": "De applicatie laat beheerders geen raadplegingen aan deze agent toevoegen."
|
|
2628
2898
|
},
|
|
2629
2899
|
notices: {
|
|
2630
2900
|
"no-answer": "De assistent is klaar zonder antwoord. Probeer het opnieuw of stel je vraag anders.",
|
|
@@ -2782,6 +3052,8 @@ var nl = {
|
|
|
2782
3052
|
changed: "Gewijzigd door {{user}} op {{date}}.",
|
|
2783
3053
|
reason: "Notitie: {{reason}}",
|
|
2784
3054
|
waiting: "{{count}} gebeurtenissen wachten op het hervatten.",
|
|
3055
|
+
"stopped-was-off-hint": "Hij stond uit toen hij stopte: de noodstop opheffen zet hem weer uit. Hervatten zet hem aan.",
|
|
3056
|
+
"stopped-was-on-hint": "Hij stond niet uit toen hij stopte: de noodstop opheffen laat hem weer werken, net als Hervatten.",
|
|
2785
3057
|
action: {
|
|
2786
3058
|
active: "Hervatten",
|
|
2787
3059
|
paused: "Pauzeren",
|
|
@@ -2869,6 +3141,44 @@ var nl = {
|
|
|
2869
3141
|
},
|
|
2870
3142
|
"input-label-search": "Account"
|
|
2871
3143
|
},
|
|
3144
|
+
"consultation-routes": {
|
|
3145
|
+
title: "Routes van raadplegingen",
|
|
3146
|
+
description: "Zet een route in één keer uit voor alle raadplegingen van deze agent, in code en in het beheer. Wanneer een andere assistent deze agent raadpleegt en de agent een wijziging voorstelt, bepaalt een route wie erover beslist en met wiens rechten het loopt.",
|
|
3147
|
+
"load-failed": "De routes van raadplegingen konden niet worden gelezen.",
|
|
3148
|
+
route: {
|
|
3149
|
+
"asker-decides": "Degene die het vroeg, beslist",
|
|
3150
|
+
"subject-agent-rights": "Goedkeurders beslissen, rechten van de agent",
|
|
3151
|
+
"subject-asker-rights": "Goedkeurders beslissen, rechten van de vrager"
|
|
3152
|
+
},
|
|
3153
|
+
explain: {
|
|
3154
|
+
"asker-decides": "Degene die het vroeg, beslist in de eigen chat; het loopt met diens eigen rechten.",
|
|
3155
|
+
"subject-agent-rights": "De goedkeurders van het onderwerp, behalve degene die het vroeg, beslissen; het loopt met de eigen rechten van de agent.",
|
|
3156
|
+
"subject-asker-rights": "De goedkeurders van het onderwerp beslissen; het loopt later met de rechten van degene die het vroeg."
|
|
3157
|
+
},
|
|
3158
|
+
on: "Aan",
|
|
3159
|
+
off: "Uit",
|
|
3160
|
+
code: "Zoals de raadplegingen toestaan",
|
|
3161
|
+
overridden: "Overschreven",
|
|
3162
|
+
"not-allowed": "Niet toegestaan",
|
|
3163
|
+
"not-allowed-hint": "Geen raadpleging van deze agent staat deze route toe, dus die blijft uit en kan niet aan.",
|
|
3164
|
+
"subject-types": "Voor: {{types}}",
|
|
3165
|
+
action: {
|
|
3166
|
+
on: "Aanzetten",
|
|
3167
|
+
off: "Uitzetten",
|
|
3168
|
+
code: "Terug naar wat de raadplegingen toestaan"
|
|
3169
|
+
},
|
|
3170
|
+
"explain-change": {
|
|
3171
|
+
on: "Raadplegingen gebruiken deze route weer voor nieuwe voorstellen. Voorstellen die er al zijn, houden hun route.",
|
|
3172
|
+
off: "Raadplegingen gebruiken deze route niet meer voor nieuwe voorstellen; met alle routes uit lezen de raadplegingen van de agent alleen. Voorstellen die er al zijn, houden hun route.",
|
|
3173
|
+
"code-on": "De raadplegingen beslissen weer: een ervan staat deze route toe, dus die staat aan.",
|
|
3174
|
+
"code-off": "De raadplegingen beslissen weer: geen ervan staat deze route toe, dus die blijft uit."
|
|
3175
|
+
},
|
|
3176
|
+
confirm: {
|
|
3177
|
+
on: "Aanzetten bevestigen",
|
|
3178
|
+
off: "Uitzetten bevestigen",
|
|
3179
|
+
code: "Bevestigen"
|
|
3180
|
+
}
|
|
3181
|
+
},
|
|
2872
3182
|
"run-config": "Runconfiguratie",
|
|
2873
3183
|
"run-now": "Nu uitvoeren",
|
|
2874
3184
|
runs: "Runs",
|
|
@@ -2906,7 +3216,7 @@ var nl = {
|
|
|
2906
3216
|
instructions: "Instructies",
|
|
2907
3217
|
"instructions-hint": "Wat de agent doet en hoe hij antwoordt.",
|
|
2908
3218
|
autonomy: "Autonomie",
|
|
2909
|
-
"autonomy-hint": "Alleen Uitvoeren staat wijzigingen toe, en
|
|
3219
|
+
"autonomy-hint": "Alleen Uitvoeren staat wijzigingen toe in het eigen werk van de agent. In een raadpleging die mag voorstellen, stellen Voorstellen en Simuleren ook wijzigingen voor. Elke wijziging vraagt nog steeds om goedkeuring.",
|
|
2910
3220
|
"required-policy": "Vereiste policy",
|
|
2911
3221
|
"required-policy-hint": "Optioneel. Alleen gebruikers die aan deze policy voldoen zien de agent.",
|
|
2912
3222
|
profile: "Modelprofiel",
|
|
@@ -3326,7 +3636,8 @@ var nl = {
|
|
|
3326
3636
|
agent: "Runinstellingen:",
|
|
3327
3637
|
skill: "Vaardigheid {{id}}:",
|
|
3328
3638
|
candidate: "Kandidaat van vaardigheid {{id}}:",
|
|
3329
|
-
trigger: "Trigger {{id}}:"
|
|
3639
|
+
trigger: "Trigger {{id}}:",
|
|
3640
|
+
consultation: "Raadpleging over {{id}}:"
|
|
3330
3641
|
},
|
|
3331
3642
|
code: {
|
|
3332
3643
|
"unknown-agent": "de agent kan niet meer zelfstandig werken.",
|
|
@@ -3337,11 +3648,23 @@ var nl = {
|
|
|
3337
3648
|
"unknown-policy": "het goedkeuringsbeleid bestaat niet meer.",
|
|
3338
3649
|
"unknown-rule-handler": "de regels bestaan niet meer.",
|
|
3339
3650
|
"unknown-event": "de gebeurtenis bestaat niet meer.",
|
|
3651
|
+
"unknown-filter": "een filter van de gebeurtenis bestaat niet meer, dus de trigger start niets totdat je het verwijdert.",
|
|
3340
3652
|
"unknown-subject-set": "de set onderwerpen bestaat niet meer.",
|
|
3341
3653
|
"unknown-skill": "de vaardigheid bestaat niet meer.",
|
|
3342
3654
|
"invalid-schedule": "het schema of de tijdzone is niet geldig.",
|
|
3343
3655
|
invalid: "een waarde is niet geldig.",
|
|
3344
|
-
"not-worked-on": "het gaat over een soort object, of de hele applicatie, waaraan de agent niet werkt."
|
|
3656
|
+
"not-worked-on": "het gaat over een soort object, of de hele applicatie, waaraan de agent niet werkt.",
|
|
3657
|
+
"unknown-subject-type": "de soort object bestaat niet meer.",
|
|
3658
|
+
"unknown-agent-policy": "het beleid dat vragers nodig hebben, wordt niet meer aangeboden.",
|
|
3659
|
+
"conflicts-with-tool": "een andere tool heeft al de naam van haar tool.",
|
|
3660
|
+
"not-consultable": "de applicatie laat beheerders geen raadplegingen meer aan deze agent toevoegen.",
|
|
3661
|
+
"route-not-allowed": "een route is niet meer toegestaan en valt weg.",
|
|
3662
|
+
"agent-answers-to-person": "de route met het account van de agent valt weg, omdat de agent verantwoording aflegt aan de verantwoordelijke van het object.",
|
|
3663
|
+
"agent-has-no-rights": "de route met het account van de agent valt weg, omdat de agent voor zichzelf antwoordt en geen eigen rechten heeft.",
|
|
3664
|
+
"no-approver": "de route met het account van de agent valt weg, omdat het goedkeuringsbeleid alleen degene die een voorstel veroorzaakte laat beslissen.",
|
|
3665
|
+
"limit-above-ceiling": "een grens ligt boven wat de applicatie toestaat, dus die van de applicatie geldt.",
|
|
3666
|
+
"requests-not-allowed": "de applicatie staat geen verzoeken meer toe, dus ze neemt er geen aan.",
|
|
3667
|
+
"mcp-not-allowed": "de applicatie biedt raadplegingen niet meer aan MCP-clients aan, dus die zien haar niet."
|
|
3345
3668
|
}
|
|
3346
3669
|
},
|
|
3347
3670
|
"field-errors": {
|
|
@@ -3358,7 +3681,9 @@ var nl = {
|
|
|
3358
3681
|
"instructions-for-model": "Zonder vaste regels werkt het model met deze instructies; beschrijf wat het moet doen.",
|
|
3359
3682
|
"application-not-worked-on": "De agent werkt niet aan de hele applicatie. Kies een verzameling objecten, of laat de agent eerst aan de hele applicatie werken.",
|
|
3360
3683
|
"megabytes-up-to": "Vul een grootte in boven 0 en hooguit {{max}} MB.",
|
|
3361
|
-
"megabytes-positive": "Vul een grootte in boven 0 MB."
|
|
3684
|
+
"megabytes-positive": "Vul een grootte in boven 0 MB.",
|
|
3685
|
+
"not-allowed": "De applicatie staat dit niet toe.",
|
|
3686
|
+
"routes-required": "Kies minstens één route, of laat hem alleen antwoorden."
|
|
3362
3687
|
},
|
|
3363
3688
|
settings: {
|
|
3364
3689
|
title: "Runinstellingen",
|
|
@@ -3569,6 +3894,13 @@ var nl = {
|
|
|
3569
3894
|
"source-schedule-hint": "Op vaste momenten, voor elk onderwerp in een verzameling.",
|
|
3570
3895
|
"source-schedule-application-hint": "Op vaste momenten, voor de hele applicatie of voor elk object in een verzameling.",
|
|
3571
3896
|
"debounce-hint": "Wacht zo lang op meer gebeurtenissen over hetzelfde onderwerp en behandelt ze in één run.",
|
|
3897
|
+
filters: {
|
|
3898
|
+
title: "Filters",
|
|
3899
|
+
hint: "Sla gebeurtenissen over waarop deze trigger de agent niet moet starten, zoals wijzigingen die de agent zelf deed. Elk filter dat je kiest moet een gebeurtenis doorlaten.",
|
|
3900
|
+
empty: "Deze gebeurtenis biedt geen filters.",
|
|
3901
|
+
missing: "De gebeurtenis biedt dit filter niet meer, dus de trigger start niets. Haal het weg om op te slaan.",
|
|
3902
|
+
applied: "Filters: {{filters}}"
|
|
3903
|
+
},
|
|
3572
3904
|
"subject-set-hint": "De projecten of klanten die het schema telkens behandelt.",
|
|
3573
3905
|
"message-hint": "Wat de agent telkens als opdracht leest.",
|
|
3574
3906
|
examples: "Voorbeelden",
|
|
@@ -3729,7 +4061,14 @@ var nl = {
|
|
|
3729
4061
|
"configured-off": "Nu uitvoeren: niet zolang de code van de applicatie de agent uitschakelt.",
|
|
3730
4062
|
"no-settings": "Nu uitvoeren: pas als de agent runinstellingen heeft.",
|
|
3731
4063
|
"no-catalog": "Nu uitvoeren: pas als de runcatalogus gelezen kan worden."
|
|
3732
|
-
}
|
|
4064
|
+
},
|
|
4065
|
+
consultations: "Als een andere assistent hem raadpleegt",
|
|
4066
|
+
"no-consultations": "Nog geen andere assistent kan hem raadplegen.",
|
|
4067
|
+
"consultation-proposes": "Antwoordt en stelt voor",
|
|
4068
|
+
"consultation-answers": "Antwoordt alleen",
|
|
4069
|
+
"asked-by-none": "Nog geen agent vraagt het",
|
|
4070
|
+
"asked-by-one": "Gevraagd door 1 agent",
|
|
4071
|
+
"asked-by": "Gevraagd door {{count}} agents"
|
|
3733
4072
|
},
|
|
3734
4073
|
skills: {
|
|
3735
4074
|
"code-rules": "Vaste regels in de code van de applicatie",
|
|
@@ -3812,7 +4151,124 @@ var nl = {
|
|
|
3812
4151
|
"edit-trigger": "Trigger wijzigen",
|
|
3813
4152
|
"edit-skill": "Vaardigheid wijzigen",
|
|
3814
4153
|
"edit-trigger-named": "Trigger {{trigger}} bewerken",
|
|
3815
|
-
"edit-skill-named": "Vaardigheid {{skill}} bewerken"
|
|
4154
|
+
"edit-skill-named": "Vaardigheid {{skill}} bewerken",
|
|
4155
|
+
"edit-consultation": "Raadpleging wijzigen",
|
|
4156
|
+
"edit-consultation-named": "De raadpleging over {{type}} bewerken"
|
|
4157
|
+
}
|
|
4158
|
+
},
|
|
4159
|
+
consultations: {
|
|
4160
|
+
title: "Raadplegingen",
|
|
4161
|
+
description: "Andere assistenten mogen deze agent raadplegen over een object. Hij antwoordt met de rechten van degene die het vroeg en stelt, waar dat mag, wijzigingen voor. Een raadpleging werkt pas als een agent die vraagt haar tool selecteert.",
|
|
4162
|
+
add: "Raadpleging toevoegen",
|
|
4163
|
+
empty: "Niemand kan deze agent nog raadplegen.",
|
|
4164
|
+
closed: {
|
|
4165
|
+
application: "De applicatie laat beheerders geen raadplegingen toevoegen; die komen uit haar code.",
|
|
4166
|
+
agent: "Deze agent staat in de code en laat beheerders geen raadplegingen toevoegen.",
|
|
4167
|
+
"needs-settings": "Geef de agent runinstellingen voordat je raadplegingen toevoegt.",
|
|
4168
|
+
limit: "Deze agent heeft al zoveel raadplegingen als is toegestaan ({{max}}).",
|
|
4169
|
+
"no-types": "Elke soort object waaraan deze agent werkt, heeft al een raadpleging."
|
|
4170
|
+
},
|
|
4171
|
+
requests: "Neemt verzoeken aan",
|
|
4172
|
+
mcp: "Aangeboden aan MCP-clients",
|
|
4173
|
+
"no-description": "Geen beschrijving.",
|
|
4174
|
+
askers: "Gevraagd door:",
|
|
4175
|
+
"open-asker": "De editor van {{agent}} openen",
|
|
4176
|
+
"no-askers": "Nog geen agent vraagt het. Selecteer de tool bij de tools van een agent die het moet vragen.",
|
|
4177
|
+
"code-hint": "Toegestaan in code; hier veranderen alleen de routeschakelaars hieronder iets.",
|
|
4178
|
+
"limits-value": "Hooguit {{calls}} toolaanroepen, {{seconds}} seconden, {{chars}} tekens en {{history}} berichten uit de thread",
|
|
4179
|
+
"edit-named": "De raadpleging over {{type}} bewerken",
|
|
4180
|
+
"remove-named": "De raadpleging over {{type}} verwijderen",
|
|
4181
|
+
"remove-explain": "Haar tools verdwijnen; voorstellen die ze deed, kunnen nog worden beslist.",
|
|
4182
|
+
added: "De raadpleging is toegevoegd. Ze antwoordt zodra een agent die vraagt haar tool selecteert.",
|
|
4183
|
+
saved: "De raadpleging is opgeslagen.",
|
|
4184
|
+
removed: "De raadpleging is verwijderd.",
|
|
4185
|
+
roles: {
|
|
4186
|
+
reader: "Lezer",
|
|
4187
|
+
participant: "Deelnemer",
|
|
4188
|
+
approver: "Goedkeurder"
|
|
4189
|
+
},
|
|
4190
|
+
"roles-lower": {
|
|
4191
|
+
reader: "lezer",
|
|
4192
|
+
participant: "deelnemer",
|
|
4193
|
+
approver: "goedkeurder"
|
|
4194
|
+
},
|
|
4195
|
+
summary: {
|
|
4196
|
+
ask: "Mensen die minstens {{role}} van het object zijn, mogen het vragen.",
|
|
4197
|
+
"asker-policy": "Ze hebben ook {{policy}} nodig.",
|
|
4198
|
+
"asker-policy-agent": "Ze hebben ook het beleid nodig dat de agent vereist, of anders toegang tot de assistent.",
|
|
4199
|
+
"read-only": "De agent antwoordt alleen en stelt niets voor.",
|
|
4200
|
+
proposes: "De agent mag wijzigingen voorstellen als degene die het vroeg minstens {{role}} is: {{routes}}.",
|
|
4201
|
+
"proposes-code": "De agent mag wijzigingen voorstellen: {{routes}}."
|
|
4202
|
+
},
|
|
4203
|
+
routes: {
|
|
4204
|
+
"asker-decides": "Degene die het vroeg, beslist in de eigen chat",
|
|
4205
|
+
"subject-asker-rights": "De goedkeurders van het object beslissen, met de rechten van degene die het vroeg",
|
|
4206
|
+
"subject-agent-rights": "De goedkeurders van het object beslissen, met het technische account van deze agent"
|
|
4207
|
+
},
|
|
4208
|
+
"routes-hint": {
|
|
4209
|
+
"asker-decides": "Goedkeuren voert het meteen uit met diens eigen rechten.",
|
|
4210
|
+
"subject-asker-rights": "Het wacht bij het object en loopt later met de rechten van degene die het vroeg.",
|
|
4211
|
+
"subject-agent-rights": "Het wacht bij het object op een goedkeurder anders dan degene die het vroeg en loopt met de eigen rechten van de agent."
|
|
4212
|
+
},
|
|
4213
|
+
"route-blocks": {
|
|
4214
|
+
"not-in-ceiling": "De applicatie staat deze route niet toe.",
|
|
4215
|
+
system: "Niet voor de hele applicatie.",
|
|
4216
|
+
"agent-answers-to-person": "Niet voor een agent die verantwoording aflegt aan de verantwoordelijke van het object.",
|
|
4217
|
+
"agent-has-no-rights": "Niet voor een agent die voor zichzelf antwoordt: hij heeft geen eigen rechten om uit te lenen."
|
|
4218
|
+
},
|
|
4219
|
+
limits: {
|
|
4220
|
+
"tool-calls": "Toolaanroepen",
|
|
4221
|
+
"timeout-seconds": "Tijdslimiet in seconden",
|
|
4222
|
+
"answer-chars": "Langste antwoord in tekens",
|
|
4223
|
+
"history-messages": "Berichten uit de thread die hij leest"
|
|
4224
|
+
},
|
|
4225
|
+
form: {
|
|
4226
|
+
"new-title": "Nieuwe raadpleging",
|
|
4227
|
+
"edit-title": "Raadpleging over {{type}}, versie {{version}}",
|
|
4228
|
+
what: "Waarover mogen andere assistenten hem raadplegen?",
|
|
4229
|
+
"subject-type": "Soort object",
|
|
4230
|
+
"subject-type-hint": "Alleen soorten objecten waaraan de agent werkt en waarover hij nog geen raadpleging heeft.",
|
|
4231
|
+
description: "Wanneer je hem raadpleegt",
|
|
4232
|
+
"description-hint": "De assistent die vraagt, leest dit om te bepalen wanneer hij deze agent raadpleegt.",
|
|
4233
|
+
instructions: "Instructies bij een raadpleging",
|
|
4234
|
+
"instructions-hint": "Optioneel. Waar de agent op let als hij antwoordt, na de eigen regels van het platform voor raadplegingen.",
|
|
4235
|
+
who: "Wie mag het vragen?",
|
|
4236
|
+
"minimum-role": "Degene die het vraagt is minstens",
|
|
4237
|
+
"role-hint": {
|
|
4238
|
+
reader: "Iedereen die het object mag lezen.",
|
|
4239
|
+
participant: "Mensen die aan het object werken.",
|
|
4240
|
+
approver: "Mensen die wijzigingen aan het object goedkeuren."
|
|
4241
|
+
},
|
|
4242
|
+
"asker-policy": "Beleid dat de persoon nodig heeft",
|
|
4243
|
+
"asker-policy-agent": "Het beleid dat de agent vereist",
|
|
4244
|
+
"asker-policy-hint": "Een van de beleidsregels die de applicatie aanbiedt. Zonder geldt het eigen beleid van de agent, of anders toegang tot de assistent.",
|
|
4245
|
+
"do": "Wat mag hij doen?",
|
|
4246
|
+
answer: "Alleen antwoorden",
|
|
4247
|
+
"answer-hint": "Hij antwoordt met de rechten van degene die het vroeg en stelt niets voor.",
|
|
4248
|
+
propose: "Antwoorden en wijzigingen voorstellen",
|
|
4249
|
+
"propose-hint": "Hij mag ook wijzigingen voorstellen; de routes hieronder bepalen wie erover beslist.",
|
|
4250
|
+
"answers-only": "De applicatie laat raadplegingen alleen antwoorden.",
|
|
4251
|
+
routes: "Wie beslist over zijn voorstellen?",
|
|
4252
|
+
"routes-hint": "Kies er minstens één. Van de twee routes bij het object kies je er hooguit één.",
|
|
4253
|
+
"proposal-role": "Rol nodig voor voorstellen",
|
|
4254
|
+
"proposal-role-hint": "Degene die het vroeg heeft minstens deze rol op het object nodig voordat de agent iets mag voorstellen; met een lagere rol krijgt die het antwoord zonder voorstellen.",
|
|
4255
|
+
"agent-policy": "Het goedkeuringsbeleid van de agent",
|
|
4256
|
+
"policy-warning": {
|
|
4257
|
+
"four-eyes": "Dit goedkeuringsbeleid vraagt vier ogen, dus degene die het vroeg kan het eigen voorstel niet in de eigen chat beslissen; die route geldt dan niet.",
|
|
4258
|
+
"initiator-only": "Dit goedkeuringsbeleid laat alleen degene die een voorstel veroorzaakte erover beslissen, dus de route met het technische account van de agent wordt geweigerd."
|
|
4259
|
+
},
|
|
4260
|
+
advanced: "Geavanceerd: grenzen, verzoeken en classificatie",
|
|
4261
|
+
limits: "Grenzen van één raadpleging",
|
|
4262
|
+
"limits-hint": "Leeg begint bij de standaard binnen wat de applicatie toestaat.",
|
|
4263
|
+
"limit-range": "Van {{min}} tot en met {{max}}.",
|
|
4264
|
+
requests: "Ook verzoeken aannemen",
|
|
4265
|
+
"requests-hint": "De assistent die vraagt, mag deze agent ook vragen een run te starten, met de persoon als initiatiefnemer.",
|
|
4266
|
+
"requests-closed": "De applicatie staat geen verzoeken toe.",
|
|
4267
|
+
mcp: "Aanbieden aan MCP-clients",
|
|
4268
|
+
"mcp-hint": "Externe MCP-clients mogen hem ook raadplegen, met de rechten van hun persoon.",
|
|
4269
|
+
"mcp-closed": "De applicatie biedt raadplegingen niet aan MCP-clients aan.",
|
|
4270
|
+
"classification-hint": "Hoe gevoelig zijn antwoorden zijn in het gesprek dat vroeg. Zonder geldt de classificatie van de agent.",
|
|
4271
|
+
"in-effect": "Een raadpleging werkt zodra ze is opgeslagen; ze antwoordt zodra een agent die vraagt haar tool selecteert."
|
|
3816
4272
|
}
|
|
3817
4273
|
}
|
|
3818
4274
|
},
|
|
@@ -3951,6 +4407,7 @@ var nl = {
|
|
|
3951
4407
|
inbox: {
|
|
3952
4408
|
title: "Voorstellen om te beslissen",
|
|
3953
4409
|
description: "Voorstellen van agents die op jouw besluit wachten, de eerst verlopende bovenaan.",
|
|
4410
|
+
"description-grouped": "Voorstellen van agents die op jouw besluit wachten, gegroepeerd per object; de groep met het eerst verlopende voorstel staat bovenaan.",
|
|
3954
4411
|
empty: "Er wachten geen voorstellen op jou.",
|
|
3955
4412
|
select: "Dit voorstel selecteren",
|
|
3956
4413
|
"select-all": "Alles selecteren",
|
|
@@ -3959,7 +4416,18 @@ var nl = {
|
|
|
3959
4416
|
previous: "Vorige",
|
|
3960
4417
|
next: "Volgende",
|
|
3961
4418
|
page: "Pagina {{page}} van {{pages}}",
|
|
3962
|
-
pages: "Pagina's"
|
|
4419
|
+
pages: "Pagina's",
|
|
4420
|
+
"new": "Nieuw",
|
|
4421
|
+
"new-label": "Nieuw sinds je laatste bezoek",
|
|
4422
|
+
"last-visit": "Je keek hier voor het laatst op {{date}}. Wat sindsdien kwam, staat als nieuw gemarkeerd.",
|
|
4423
|
+
"first-visit": "Alles hier is nieuw voor je.",
|
|
4424
|
+
"group-loaded": "{{loaded}} van {{total}} getoond",
|
|
4425
|
+
"select-group": "De {{count}} getoonde selecteren",
|
|
4426
|
+
"select-group-label": "De {{count}} voorstellen van {{name}} op deze pagina selecteren",
|
|
4427
|
+
"group-continued": "Vervolg van de vorige pagina.",
|
|
4428
|
+
"group-continues": "Meer voorstellen van deze groep staan op de volgende pagina.",
|
|
4429
|
+
run: "Eén run van {{agent}}, {{date}}",
|
|
4430
|
+
"no-run": "Voorgesteld in een gesprek"
|
|
3963
4431
|
},
|
|
3964
4432
|
proposal: {
|
|
3965
4433
|
approve: "Goedkeuren",
|
|
@@ -3989,7 +4457,22 @@ var nl = {
|
|
|
3989
4457
|
shadow: "Schaduw"
|
|
3990
4458
|
},
|
|
3991
4459
|
"from-consultation": "Uit een raadpleging",
|
|
3992
|
-
"from-consultation-hint": "Een andere assistent raadpleegde de agent voor
|
|
4460
|
+
"from-consultation-hint": "Een andere assistent raadpleegde de agent voor iemand, en de agent stelde dit voor.",
|
|
4461
|
+
consultation: {
|
|
4462
|
+
"asked-by": "Gevraagd door {{name}}",
|
|
4463
|
+
"the-asker": "degene die het vroeg",
|
|
4464
|
+
route: {
|
|
4465
|
+
"asker-decides": "Degene die het vroeg, beslist in de eigen chat; het loopt met diens eigen rechten.",
|
|
4466
|
+
"subject-agent-rights": "De goedkeurders van het onderwerp, behalve degene die het vroeg, beslissen; het loopt met de eigen rechten van de agent.",
|
|
4467
|
+
"subject-asker-rights": "De goedkeurders van het onderwerp beslissen; het loopt met de rechten van degene die het vroeg."
|
|
4468
|
+
},
|
|
4469
|
+
"waiting-for-asker": "Wacht tot {{name}} beslist in de eigen chat.",
|
|
4470
|
+
"four-eyes": "Jij vroeg hierom, dus een andere goedkeurder beslist; het loopt met de eigen rechten van de agent.",
|
|
4471
|
+
"runs-with": {
|
|
4472
|
+
agent: "Loopt met de rechten van de agent",
|
|
4473
|
+
accountable: "Loopt met de rechten van het technische account"
|
|
4474
|
+
}
|
|
4475
|
+
},
|
|
3993
4476
|
"give-feedback": "Feedback geven",
|
|
3994
4477
|
"change-feedback": "Feedback wijzigen",
|
|
3995
4478
|
"your-feedback": "Jouw feedback: {{category}}",
|
|
@@ -4068,6 +4551,11 @@ var nl = {
|
|
|
4068
4551
|
running: "Bezig",
|
|
4069
4552
|
completed: "Beantwoord",
|
|
4070
4553
|
failed: "Niet beantwoord"
|
|
4554
|
+
},
|
|
4555
|
+
routes: {
|
|
4556
|
+
"asker-decides": "Vrager beslist: {{count}}",
|
|
4557
|
+
"subject-agent-rights": "Goedkeurders, rechten van de agent: {{count}}",
|
|
4558
|
+
"subject-asker-rights": "Goedkeurders, rechten van de vrager: {{count}}"
|
|
4071
4559
|
}
|
|
4072
4560
|
},
|
|
4073
4561
|
"object-agents": {
|
|
@@ -4963,6 +5451,15 @@ class NhAssistantAdminApiService {
|
|
|
4963
5451
|
setServiceAccount(agentId, request) {
|
|
4964
5452
|
return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/service-account`, request);
|
|
4965
5453
|
}
|
|
5454
|
+
/**
|
|
5455
|
+
* Switches the routes of the agent's consultations on, off or back to the setting in code; a route
|
|
5456
|
+
* left out keeps its switch. Code is the ceiling: switching on a route that no consultation in code
|
|
5457
|
+
* allows fails with `assistant-consult-route-not-allowed`. Returns the agent's state with its
|
|
5458
|
+
* `consultationRoutes`.
|
|
5459
|
+
*/
|
|
5460
|
+
setConsultationRoutes(agentId, request) {
|
|
5461
|
+
return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/consultation-routes`, request);
|
|
5462
|
+
}
|
|
4966
5463
|
/**
|
|
4967
5464
|
* Puts an agent, in code or created here, in exactly `groups` of the run catalog's `agentGroups`
|
|
4968
5465
|
* and out of the others. The choice wins over the agent's `InGroup` in code. Fails with a field error
|
|
@@ -5186,6 +5683,27 @@ class NhAssistantAdminApiService {
|
|
|
5186
5683
|
setDataTriggerShadow(agentId, triggerId, request) {
|
|
5187
5684
|
return this.request('POST', `${triggerPath(agentId, triggerId)}/shadow`, request);
|
|
5188
5685
|
}
|
|
5686
|
+
/**
|
|
5687
|
+
* Adds or changes the consultation defined as data of an agent about one subject type, within the
|
|
5688
|
+
* agent's `consultationCeiling`. It is in effect once saved and answers when an asking agent selects
|
|
5689
|
+
* its consult tool. An agent that may get none fails with `assistant-consultations-not-allowed`, an
|
|
5690
|
+
* agent created here without run settings with `assistant-agent-not-configured`, a type the agent
|
|
5691
|
+
* allows consultation about in code with `assistant-consultation-in-code`, more than the ceiling's
|
|
5692
|
+
* `maxConsultations` with `assistant-configuration-limit`, a stale `expectedVersion` with
|
|
5693
|
+
* `assistant-version-conflict` and invalid input with field errors, such as `routes: not-allowed` for
|
|
5694
|
+
* a route outside the ceiling.
|
|
5695
|
+
*/
|
|
5696
|
+
saveDataConsultation(agentId, subjectType, request) {
|
|
5697
|
+
return this.request('PUT', consultationPath(agentId, subjectType), request);
|
|
5698
|
+
}
|
|
5699
|
+
/**
|
|
5700
|
+
* Removes a consultation defined as data: its tools disappear, while its recorded proposals can still
|
|
5701
|
+
* be decided. Fails with `assistant-consultation-not-found` without one and with
|
|
5702
|
+
* `assistant-consultation-in-code` for a consultation in code.
|
|
5703
|
+
*/
|
|
5704
|
+
removeDataConsultation(agentId, subjectType, removal = {}) {
|
|
5705
|
+
return this.request('DELETE', withQuery$1(consultationPath(agentId, subjectType), removal));
|
|
5706
|
+
}
|
|
5189
5707
|
download(path) {
|
|
5190
5708
|
return this.transport.download(path, 'application/x-ndjson', adminStatusCodes);
|
|
5191
5709
|
}
|
|
@@ -5213,6 +5731,9 @@ function skillPath(agentId, skillId) {
|
|
|
5213
5731
|
function triggerPath(agentId, triggerId) {
|
|
5214
5732
|
return `${agentPath(agentId)}/triggers/${encodeURIComponent(triggerId)}`;
|
|
5215
5733
|
}
|
|
5734
|
+
function consultationPath(agentId, subjectType) {
|
|
5735
|
+
return `${agentPath(agentId)}/consultations/${encodeURIComponent(subjectType)}`;
|
|
5736
|
+
}
|
|
5216
5737
|
/** Appends the filter values that are set as query parameters. */
|
|
5217
5738
|
function withQuery$1(path, filter) {
|
|
5218
5739
|
const query = new URLSearchParams();
|
|
@@ -5399,7 +5920,10 @@ class NhAssistantAgentRunApiService {
|
|
|
5399
5920
|
retryRun(runId, mode) {
|
|
5400
5921
|
return this.transport.json('POST', `runs/${encodeURIComponent(runId)}/retry`, { mode });
|
|
5401
5922
|
}
|
|
5402
|
-
/**
|
|
5923
|
+
/**
|
|
5924
|
+
* Pending proposals the caller may decide, sorted by expiry, or with `grouped` by parent and subject,
|
|
5925
|
+
* with what is new since the caller's last visit (`visitInbox`).
|
|
5926
|
+
*/
|
|
5403
5927
|
getInbox(filter = {}) {
|
|
5404
5928
|
const query = new URLSearchParams();
|
|
5405
5929
|
for (const [key, value] of Object.entries(filter)) {
|
|
@@ -5410,6 +5934,15 @@ class NhAssistantAgentRunApiService {
|
|
|
5410
5934
|
const suffix = query.toString();
|
|
5411
5935
|
return this.transport.json('GET', suffix ? `approvals/inbox?${suffix}` : 'approvals/inbox');
|
|
5412
5936
|
}
|
|
5937
|
+
/**
|
|
5938
|
+
* Records that the caller looked at the inbox now, so it marks the proposals made after this visit
|
|
5939
|
+
* as new. `divisionId` records the visit of the inbox of one division the caller may work in;
|
|
5940
|
+
* otherwise of the whole inbox. Fails with `assistant-subject-not-found` for a division the caller
|
|
5941
|
+
* may not work in.
|
|
5942
|
+
*/
|
|
5943
|
+
visitInbox(divisionId) {
|
|
5944
|
+
return this.transport.json('POST', withQuery('approvals/inbox/visit', { divisionId }));
|
|
5945
|
+
}
|
|
5413
5946
|
/**
|
|
5414
5947
|
* Decides one proposal, bound to the proposal hash the person saw; the server checks the approval
|
|
5415
5948
|
* policy and the tool's approve policy again. Accepts an inbox proposal or the approval part of an
|
|
@@ -6246,31 +6779,111 @@ function sameKey(current, expected) {
|
|
|
6246
6779
|
/** The longest file name a file reference takes. */
|
|
6247
6780
|
const NH_ASSISTANT_MAX_FILE_NAME_LENGTH = 256;
|
|
6248
6781
|
const unknownMediaType = 'application/octet-stream';
|
|
6249
|
-
|
|
6782
|
+
const zipAliases = ['application/zip', 'application/x-zip-compressed'];
|
|
6783
|
+
/**
|
|
6784
|
+
* The media types the platform names, with the extensions a file picker offers and a short label.
|
|
6785
|
+
* The extensions are the same as the server's table of upload media types.
|
|
6786
|
+
*/
|
|
6250
6787
|
const knownTypes = {
|
|
6251
6788
|
'application/pdf': { extensions: ['.pdf'], label: 'PDF' },
|
|
6252
6789
|
'image/png': { extensions: ['.png'], label: 'PNG' },
|
|
6253
6790
|
'image/jpeg': { extensions: ['.jpg', '.jpeg'], label: 'JPEG' },
|
|
6791
|
+
'image/gif': { extensions: ['.gif'], label: 'GIF' },
|
|
6792
|
+
'image/webp': { extensions: ['.webp'], label: 'WebP' },
|
|
6254
6793
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': { extensions: ['.docx'], label: 'Word' },
|
|
6255
|
-
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { extensions: ['.xlsx'], label: 'Excel' }
|
|
6794
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { extensions: ['.xlsx'], label: 'Excel' },
|
|
6795
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation': { extensions: ['.pptx'], label: 'PowerPoint' },
|
|
6796
|
+
'application/msword': { extensions: ['.doc'], label: 'Word' },
|
|
6797
|
+
'application/vnd.ms-excel': { extensions: ['.xls'], label: 'Excel' },
|
|
6798
|
+
'text/csv': { extensions: ['.csv'], label: 'CSV' },
|
|
6799
|
+
'text/tab-separated-values': { extensions: ['.tsv'], label: 'TSV' },
|
|
6800
|
+
'text/plain': { extensions: ['.txt'], label: 'Text' },
|
|
6801
|
+
'text/markdown': { extensions: ['.md', '.markdown'], label: 'Markdown' },
|
|
6802
|
+
'application/json': { extensions: ['.json'], label: 'JSON' },
|
|
6803
|
+
'application/xml': { extensions: ['.xml'], label: 'XML' }
|
|
6256
6804
|
};
|
|
6805
|
+
/** Types that say nothing about the content, whatever the file's extension. */
|
|
6806
|
+
const genericTypes = new Set([unknownMediaType, 'binary/octet-stream', 'application/unknown']);
|
|
6257
6807
|
/**
|
|
6258
|
-
* The
|
|
6259
|
-
*
|
|
6260
|
-
*
|
|
6808
|
+
* The types browsers commonly give a file of an extension instead of its own type: the program
|
|
6809
|
+
* that opens it, as Windows does with `application/vnd.ms-excel` for `.csv`, an outdated name or
|
|
6810
|
+
* the container format.
|
|
6261
6811
|
*/
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6812
|
+
const aliasesByExtension = {
|
|
6813
|
+
'.csv': [
|
|
6814
|
+
'application/vnd.ms-excel',
|
|
6815
|
+
'application/csv',
|
|
6816
|
+
'application/x-csv',
|
|
6817
|
+
'text/x-csv',
|
|
6818
|
+
'text/comma-separated-values',
|
|
6819
|
+
'text/x-comma-separated-values'
|
|
6820
|
+
],
|
|
6821
|
+
'.md': ['text/x-markdown'],
|
|
6822
|
+
'.markdown': ['text/x-markdown'],
|
|
6823
|
+
'.jpg': ['image/jpg', 'image/pjpeg'],
|
|
6824
|
+
'.jpeg': ['image/jpg', 'image/pjpeg'],
|
|
6825
|
+
'.png': ['image/x-png'],
|
|
6826
|
+
'.docx': zipAliases,
|
|
6827
|
+
'.xlsx': zipAliases,
|
|
6828
|
+
'.pptx': zipAliases,
|
|
6829
|
+
// Browsers send the older name of XML; an application that accepts only it keeps receiving it.
|
|
6830
|
+
'.xml': ['text/xml']
|
|
6831
|
+
};
|
|
6832
|
+
/** The extension of a file name in lowercase, such as `.csv`; empty without one. */
|
|
6833
|
+
function extensionOf(name) {
|
|
6834
|
+
const base = name.slice(Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')) + 1);
|
|
6835
|
+
const dot = base.lastIndexOf('.');
|
|
6836
|
+
return dot > 0 || (dot === 0 && base.length > 1) ? base.slice(dot).toLowerCase() : '';
|
|
6837
|
+
}
|
|
6838
|
+
/** The application's extensions (`AgentUploads.mappedExtensions`) whose type is accepted, lowercase. */
|
|
6839
|
+
function acceptedMappings(acceptedMediaTypes, mappedExtensions) {
|
|
6840
|
+
return (mappedExtensions ?? [])
|
|
6841
|
+
.map(mapping => ({ extension: mapping.extension.toLowerCase(), mediaType: mapping.mediaType.toLowerCase() }))
|
|
6842
|
+
.filter(mapping => acceptedMediaTypes.includes(mapping.mediaType));
|
|
6843
|
+
}
|
|
6844
|
+
/** The platform's media type of an extension, or `null`. */
|
|
6845
|
+
function knownMediaTypeOf(extension) {
|
|
6268
6846
|
for (const [mediaType, known] of Object.entries(knownTypes)) {
|
|
6269
|
-
if (known.extensions.
|
|
6847
|
+
if (known.extensions.includes(extension)) {
|
|
6270
6848
|
return mediaType;
|
|
6271
6849
|
}
|
|
6272
6850
|
}
|
|
6273
|
-
return
|
|
6851
|
+
return null;
|
|
6852
|
+
}
|
|
6853
|
+
/**
|
|
6854
|
+
* The accepted type an extension names: the application's mapping, otherwise the platform's table;
|
|
6855
|
+
* `null` when neither names an accepted type.
|
|
6856
|
+
*/
|
|
6857
|
+
function mediaTypeOfExtension(extension, acceptedMediaTypes, mappings) {
|
|
6858
|
+
if (extension.length === 0) {
|
|
6859
|
+
return null;
|
|
6860
|
+
}
|
|
6861
|
+
const mapped = mappings.find(mapping => mapping.extension === extension);
|
|
6862
|
+
if (mapped) {
|
|
6863
|
+
return mapped.mediaType;
|
|
6864
|
+
}
|
|
6865
|
+
const known = knownMediaTypeOf(extension);
|
|
6866
|
+
return known && acceptedMediaTypes.includes(known) ? known : null;
|
|
6867
|
+
}
|
|
6868
|
+
/**
|
|
6869
|
+
* The media type a chosen file uploads as, lowercase and without parameters, by the same rule as the
|
|
6870
|
+
* server. A browser gives no type, or a generic one, for a file its system does not know, and some
|
|
6871
|
+
* systems name an extension after the program that opens it, such as `application/vnd.ms-excel` for
|
|
6872
|
+
* a `.csv` file; the file name's extension then names the type, but only a type of
|
|
6873
|
+
* `acceptedMediaTypes`: the type the application mapped the extension to (`mappedExtensions`),
|
|
6874
|
+
* otherwise the platform's. A specific type stays as it is, so a type that is not accepted is refused
|
|
6875
|
+
* whatever the extension. Without a type and an accepted extension, `application/octet-stream`.
|
|
6876
|
+
*/
|
|
6877
|
+
function nhAssistantMediaTypeOf(file, acceptedMediaTypes, mappedExtensions) {
|
|
6878
|
+
const declared = file.type.split(';')[0].trim().toLowerCase();
|
|
6879
|
+
const extension = extensionOf(file.name);
|
|
6880
|
+
if (declared.length === 0 || genericTypes.has(declared) || (aliasesByExtension[extension] ?? []).includes(declared)) {
|
|
6881
|
+
const derived = mediaTypeOfExtension(extension, acceptedMediaTypes, acceptedMappings(acceptedMediaTypes, mappedExtensions));
|
|
6882
|
+
if (derived) {
|
|
6883
|
+
return derived;
|
|
6884
|
+
}
|
|
6885
|
+
}
|
|
6886
|
+
return declared.length > 0 ? declared : unknownMediaType;
|
|
6274
6887
|
}
|
|
6275
6888
|
/**
|
|
6276
6889
|
* The failure code of a file before it is uploaded, or `null` when it may be: the most files of one
|
|
@@ -6292,11 +6905,19 @@ function nhAssistantFileProblem(file, mediaType, uploads, attached) {
|
|
|
6292
6905
|
}
|
|
6293
6906
|
return null;
|
|
6294
6907
|
}
|
|
6295
|
-
/**
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6908
|
+
/**
|
|
6909
|
+
* The `accept` attribute of a file input for these accepted media types: each type and the extensions
|
|
6910
|
+
* that name it, those the application mapped to it (`mappedExtensions`) and those of the platform's
|
|
6911
|
+
* table that the application did not map to another accepted type.
|
|
6912
|
+
*/
|
|
6913
|
+
function nhAssistantAcceptAttribute(mediaTypes, mappedExtensions) {
|
|
6914
|
+
const mappings = acceptedMappings(mediaTypes, mappedExtensions);
|
|
6915
|
+
const values = mediaTypes.flatMap(mediaType => [
|
|
6916
|
+
mediaType,
|
|
6917
|
+
...mappings.filter(mapping => mapping.mediaType === mediaType).map(mapping => mapping.extension),
|
|
6918
|
+
...(knownTypes[mediaType]?.extensions ?? []).filter(extension => !mappings.some(mapping => mapping.extension === extension))
|
|
6919
|
+
]);
|
|
6920
|
+
return [...new Set(values)].join(',');
|
|
6300
6921
|
}
|
|
6301
6922
|
/** A short name of a media type, such as `PDF` or `Word`; otherwise its subtype in capitals. */
|
|
6302
6923
|
function nhAssistantFileTypeLabel(mediaType) {
|
|
@@ -6421,7 +7042,11 @@ function applyNhAssistantEvent(conversation, event, clientMessageId) {
|
|
|
6421
7042
|
};
|
|
6422
7043
|
}
|
|
6423
7044
|
}
|
|
6424
|
-
/**
|
|
7045
|
+
/**
|
|
7046
|
+
* Records the user's approval decision locally until the server state is reloaded. A consulted
|
|
7047
|
+
* agent's proposal that the user left for the subject's approvers (`leave`) closes here as the server
|
|
7048
|
+
* closes it, rejected in this conversation, and can no longer be left; the waiting tool call goes on.
|
|
7049
|
+
*/
|
|
6425
7050
|
function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
|
|
6426
7051
|
const approval = conversation.messages
|
|
6427
7052
|
.flatMap(message => message.parts)
|
|
@@ -6431,7 +7056,7 @@ function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
|
|
|
6431
7056
|
const messages = conversation.messages.map(message => ({
|
|
6432
7057
|
...message,
|
|
6433
7058
|
parts: message.parts.map(part => part.type === 'approval' && part.approvalId === approvalId
|
|
6434
|
-
?
|
|
7059
|
+
? decidedApproval(part, decision)
|
|
6435
7060
|
: part)
|
|
6436
7061
|
}));
|
|
6437
7062
|
let updated = {
|
|
@@ -6445,15 +7070,24 @@ function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
|
|
|
6445
7070
|
if (awaiting) {
|
|
6446
7071
|
updated = updateToolCall(updated, awaiting.invocationId, part => ({
|
|
6447
7072
|
...part,
|
|
6448
|
-
status: decision === '
|
|
7073
|
+
status: decision === 'reject' ? 'rejected' : 'running'
|
|
6449
7074
|
}));
|
|
6450
7075
|
}
|
|
6451
7076
|
}
|
|
6452
7077
|
return updated;
|
|
6453
7078
|
}
|
|
7079
|
+
/** An approval part after the user's decision. */
|
|
7080
|
+
function decidedApproval(part, decision) {
|
|
7081
|
+
const decided = { ...part, status: decision === 'approve' ? 'approved' : 'rejected' };
|
|
7082
|
+
if (decision === 'leave' && part.consultation) {
|
|
7083
|
+
decided.consultation = { ...part.consultation, leaveRoute: null };
|
|
7084
|
+
}
|
|
7085
|
+
return decided;
|
|
7086
|
+
}
|
|
6454
7087
|
/**
|
|
6455
|
-
* Applies a live update of another session: `message.created` adds a participant's
|
|
6456
|
-
*
|
|
7088
|
+
* Applies a live update of another session: `message.created` adds a participant's or the
|
|
7089
|
+
* application's message once, where its sequence number puts it; the turn events behave exactly
|
|
7090
|
+
* like the starting request's stream. Unknown types are ignored.
|
|
6457
7091
|
*/
|
|
6458
7092
|
function applyNhAssistantLiveEvent(conversation, event) {
|
|
6459
7093
|
if (event.type === 'message.created') {
|
|
@@ -6461,7 +7095,7 @@ function applyNhAssistantLiveEvent(conversation, event) {
|
|
|
6461
7095
|
if (!message?.id || conversation.messages.some(existing => existing.id === message.id)) {
|
|
6462
7096
|
return conversation;
|
|
6463
7097
|
}
|
|
6464
|
-
return { ...conversation, messages:
|
|
7098
|
+
return { ...conversation, messages: insertBySequence(conversation.messages, message) };
|
|
6465
7099
|
}
|
|
6466
7100
|
if (!NH_ASSISTANT_SSE_EVENT_TYPES.includes(event.type)) {
|
|
6467
7101
|
return conversation;
|
|
@@ -6508,6 +7142,26 @@ function conversationStatusFor(status) {
|
|
|
6508
7142
|
return 'failed';
|
|
6509
7143
|
}
|
|
6510
7144
|
}
|
|
7145
|
+
/**
|
|
7146
|
+
* Places a stored message before the messages at the end that have a higher sequence number. A
|
|
7147
|
+
* message without a number, such as an optimistic message or the answer a running turn is still
|
|
7148
|
+
* writing, counts as earlier: the server numbers a turn's messages when the turn starts, so a message
|
|
7149
|
+
* stored during the turn follows its answer. A message without a number of its own goes last.
|
|
7150
|
+
*/
|
|
7151
|
+
function insertBySequence(messages, message) {
|
|
7152
|
+
const sequence = message.sequence;
|
|
7153
|
+
let index = messages.length;
|
|
7154
|
+
if (typeof sequence === 'number' && sequence > 0) {
|
|
7155
|
+
while (index > 0) {
|
|
7156
|
+
const previous = messages[index - 1].sequence;
|
|
7157
|
+
if (typeof previous !== 'number' || previous <= sequence) {
|
|
7158
|
+
break;
|
|
7159
|
+
}
|
|
7160
|
+
index--;
|
|
7161
|
+
}
|
|
7162
|
+
}
|
|
7163
|
+
return [...messages.slice(0, index), message, ...messages.slice(index)];
|
|
7164
|
+
}
|
|
6511
7165
|
function createAssistantMessage(id) {
|
|
6512
7166
|
return { id, role: 'assistant', createdAt: new Date().toISOString(), parts: [] };
|
|
6513
7167
|
}
|
|
@@ -6763,6 +7417,8 @@ const NH_ASSISTANT_NO_ANSWER_NOTICE_CODE = 'assistant-no-answer';
|
|
|
6763
7417
|
*/
|
|
6764
7418
|
const NH_ASSISTANT_MESSAGE_QUEUED_NOTICE_CODE = 'assistant-message-queued';
|
|
6765
7419
|
const fourEyesRequiredCode = 'assistant-four-eyes-required';
|
|
7420
|
+
/** A consultation's proposal in the consulted thread that the person who asked decides in their own chat. */
|
|
7421
|
+
const askerDecidesCode = 'assistant-consult-asker-decides';
|
|
6766
7422
|
/** True when a conversation has messages the caller has not read. A running turn is not unread yet. */
|
|
6767
7423
|
function nhAssistantIsUnread(summary) {
|
|
6768
7424
|
if (summary.status === 'running' || summary.lastReadSequence === undefined) {
|
|
@@ -6876,6 +7532,12 @@ class NhAssistantStore {
|
|
|
6876
7532
|
/** Non-blocking remark about the latest completed turn; shown only while no error is shown. */
|
|
6877
7533
|
this.notice = computed(() => this.activeSession()?.notice ?? null, ...(ngDevMode ? [{ debugName: "notice" }] : []));
|
|
6878
7534
|
this.lastUsage = computed(() => this.activeSession()?.lastUsage ?? null, ...(ngDevMode ? [{ debugName: "lastUsage" }] : []));
|
|
7535
|
+
/**
|
|
7536
|
+
* The answer the running turn of the open conversation writes, while this tab streams the turn or
|
|
7537
|
+
* follows it live; `null` otherwise. Pass it to `nh-assistant-thread` as `writingMessageId`, so
|
|
7538
|
+
* the working indicator stays under that answer when a message arrives after it during the turn.
|
|
7539
|
+
*/
|
|
7540
|
+
this.writingMessageId = computed(() => this.activeSession()?.writingMessageId ?? null, ...(ngDevMode ? [{ debugName: "writingMessageId" }] : []));
|
|
6879
7541
|
/** Text of a message the server did not accept, so the composer can offer it again. */
|
|
6880
7542
|
this.restoredDraft = this.restoredDraftState.asReadonly();
|
|
6881
7543
|
/** Page context that the next message would send, for the transparency chip. */
|
|
@@ -6960,7 +7622,7 @@ class NhAssistantStore {
|
|
|
6960
7622
|
const decision = decisions.get(approval.approvalId);
|
|
6961
7623
|
rights.set(approval.approvalId, {
|
|
6962
7624
|
canDecide: decision?.canDecide === true,
|
|
6963
|
-
waitingFor: decision?.reasonCode
|
|
7625
|
+
waitingFor: waitingForOf(decision?.reasonCode),
|
|
6964
7626
|
decisionOwner: null
|
|
6965
7627
|
});
|
|
6966
7628
|
}
|
|
@@ -7463,8 +8125,11 @@ class NhAssistantStore {
|
|
|
7463
8125
|
/**
|
|
7464
8126
|
* Approves or rejects an approval of the open conversation: `approvalId`, or the pending approval
|
|
7465
8127
|
* when it is left out. A proposal of an agent's run is decided with its proposal hash through the
|
|
7466
|
-
* agent-run endpoint; other approvals resume their turn as a stream.
|
|
7467
|
-
*
|
|
8128
|
+
* agent-run endpoint; other approvals resume their turn as a stream. `leave` leaves a consulted
|
|
8129
|
+
* agent's proposal that has a `consultation.leaveRoute` for the subject's approvers; it resumes the
|
|
8130
|
+
* turn like a decision and reads the conversation again, which then names the proposal that waits
|
|
8131
|
+
* at the subject. Ignores calls the current user may not make, `leave` for other approvals and
|
|
8132
|
+
* repeated calls while a decision is in flight.
|
|
7468
8133
|
*/
|
|
7469
8134
|
decide(decision, reason, approvalId) {
|
|
7470
8135
|
const session = this.activeSession();
|
|
@@ -7478,9 +8143,15 @@ class NhAssistantStore {
|
|
|
7478
8143
|
if (!approval || this.approvalRights().get(approval.approvalId)?.canDecide !== true) {
|
|
7479
8144
|
return;
|
|
7480
8145
|
}
|
|
8146
|
+
if (decision === 'leave' && !approval.consultation?.leaveRoute) {
|
|
8147
|
+
// Only a consulted agent's proposal with a route at the subject can be left for its approvers.
|
|
8148
|
+
return;
|
|
8149
|
+
}
|
|
7481
8150
|
const proposal = conversation.thread?.decisions.find(item => item.approvalId === approval.approvalId);
|
|
7482
8151
|
if (proposal?.runId) {
|
|
7483
|
-
|
|
8152
|
+
if (decision !== 'leave') {
|
|
8153
|
+
void this.decideProposal(conversation.id, approval, decision, reason);
|
|
8154
|
+
}
|
|
7484
8155
|
return;
|
|
7485
8156
|
}
|
|
7486
8157
|
if (conversation.pendingApproval?.approvalId !== approval.approvalId) {
|
|
@@ -7512,7 +8183,8 @@ class NhAssistantStore {
|
|
|
7512
8183
|
},
|
|
7513
8184
|
complete: () => {
|
|
7514
8185
|
this.patchSession(conversationId, current => ({ ...current, deciding: false }));
|
|
7515
|
-
|
|
8186
|
+
// A proposal left for the subject's approvers names the one that waits there only once read again.
|
|
8187
|
+
this.afterTurn(conversationId, failed || decision === 'leave');
|
|
7516
8188
|
}
|
|
7517
8189
|
});
|
|
7518
8190
|
}
|
|
@@ -7586,7 +8258,7 @@ class NhAssistantStore {
|
|
|
7586
8258
|
if (this.sessionsState().get(conversationId)?.streaming) {
|
|
7587
8259
|
this.streams.get(conversationId)?.unsubscribe();
|
|
7588
8260
|
this.streams.delete(conversationId);
|
|
7589
|
-
this.patchSession(conversationId, current => ({ ...current, streaming: false, deciding: false }));
|
|
8261
|
+
this.patchSession(conversationId, current => ({ ...current, streaming: false, deciding: false, writingMessageId: null }));
|
|
7590
8262
|
void this.reloadSession(conversationId);
|
|
7591
8263
|
}
|
|
7592
8264
|
}, cancelGracePeriodMs));
|
|
@@ -7759,7 +8431,7 @@ class NhAssistantStore {
|
|
|
7759
8431
|
const added = [];
|
|
7760
8432
|
const pending = [];
|
|
7761
8433
|
for (const file of files) {
|
|
7762
|
-
const mediaType = nhAssistantMediaTypeOf(file);
|
|
8434
|
+
const mediaType = nhAssistantMediaTypeOf(file, uploads.acceptedMediaTypes, uploads.mappedExtensions);
|
|
7763
8435
|
const problem = nhAssistantFileProblem(file, mediaType, uploads, attached);
|
|
7764
8436
|
const attachment = {
|
|
7765
8437
|
id: createClientMessageId(),
|
|
@@ -8070,12 +8742,12 @@ class NhAssistantStore {
|
|
|
8070
8742
|
}
|
|
8071
8743
|
runStream(conversationId, stream, handlers) {
|
|
8072
8744
|
this.streams.get(conversationId)?.unsubscribe();
|
|
8073
|
-
this.patchSession(conversationId, session => ({ ...session, streaming: true }));
|
|
8745
|
+
this.patchSession(conversationId, session => ({ ...session, streaming: true, writingMessageId: null }));
|
|
8074
8746
|
const finish = () => {
|
|
8075
8747
|
clearTimeout(this.cancelTimers.get(conversationId));
|
|
8076
8748
|
this.cancelTimers.delete(conversationId);
|
|
8077
8749
|
this.streams.delete(conversationId);
|
|
8078
|
-
this.patchSession(conversationId, session => ({ ...session, streaming: false }));
|
|
8750
|
+
this.patchSession(conversationId, session => ({ ...session, streaming: false, writingMessageId: null }));
|
|
8079
8751
|
handlers.complete();
|
|
8080
8752
|
};
|
|
8081
8753
|
const subscription = stream.subscribe({
|
|
@@ -8120,7 +8792,7 @@ class NhAssistantStore {
|
|
|
8120
8792
|
notice = completionNotice(conversation, event.data.errorCode);
|
|
8121
8793
|
}
|
|
8122
8794
|
}
|
|
8123
|
-
return { ...session, conversation, error, notice, lastUsage };
|
|
8795
|
+
return { ...session, conversation, error, notice, lastUsage, writingMessageId: writingAnswerAfter(session.writingMessageId, event) };
|
|
8124
8796
|
});
|
|
8125
8797
|
}
|
|
8126
8798
|
afterTurn(conversationId, reload) {
|
|
@@ -8208,7 +8880,8 @@ class NhAssistantStore {
|
|
|
8208
8880
|
const wasRunning = session.conversation.status === 'running';
|
|
8209
8881
|
this.patchSession(change.conversationId, current => ({
|
|
8210
8882
|
...current,
|
|
8211
|
-
conversation: applyNhAssistantConversationChange(current.conversation, change)
|
|
8883
|
+
conversation: applyNhAssistantConversationChange(current.conversation, change),
|
|
8884
|
+
writingMessageId: change.status === 'running' ? current.writingMessageId : null
|
|
8212
8885
|
}));
|
|
8213
8886
|
if (wasRunning && change.status !== 'running') {
|
|
8214
8887
|
// Another session ended its turn; the snapshot holds the exact answer and approvals.
|
|
@@ -8231,18 +8904,27 @@ class NhAssistantStore {
|
|
|
8231
8904
|
this.draftErrorState.set(clientError(NhAssistantClientErrorCodes.conversationRemoved));
|
|
8232
8905
|
}
|
|
8233
8906
|
}
|
|
8907
|
+
/**
|
|
8908
|
+
* Applies a live turn event or message to a conversation this tab shows. While the tab streams a
|
|
8909
|
+
* turn of the conversation, its stream brings the turn's events and its own message, so it applies
|
|
8910
|
+
* only messages that others stored meanwhile: the application's and other people's.
|
|
8911
|
+
*/
|
|
8234
8912
|
onLiveEvent(event) {
|
|
8235
8913
|
const session = this.sessionsState().get(event.conversationId);
|
|
8236
8914
|
if (event.type === 'turn.started') {
|
|
8237
8915
|
this.patchSummary(event.conversationId, summary => ({ ...summary, status: 'running', activeActorId: event.actorId }));
|
|
8238
8916
|
}
|
|
8239
|
-
if (!session
|
|
8240
|
-
|
|
8917
|
+
if (!session) {
|
|
8918
|
+
return;
|
|
8919
|
+
}
|
|
8920
|
+
if (session.streaming && !isMessageOfOthers(session.conversation, event)) {
|
|
8241
8921
|
return;
|
|
8242
8922
|
}
|
|
8243
8923
|
this.patchSession(event.conversationId, current => ({
|
|
8244
8924
|
...current,
|
|
8245
|
-
conversation: applyNhAssistantLiveEvent(current.conversation, event)
|
|
8925
|
+
conversation: applyNhAssistantLiveEvent(current.conversation, event),
|
|
8926
|
+
// A turn this tab follows live names its answer; while the tab streams, its stream does.
|
|
8927
|
+
writingMessageId: current.streaming ? current.writingMessageId : writingAnswerAfter(current.writingMessageId, event)
|
|
8246
8928
|
}));
|
|
8247
8929
|
}
|
|
8248
8930
|
/**
|
|
@@ -8294,8 +8976,8 @@ class NhAssistantStore {
|
|
|
8294
8976
|
const next = new Map(sessions);
|
|
8295
8977
|
const existing = next.get(conversation.id);
|
|
8296
8978
|
next.set(conversation.id, existing
|
|
8297
|
-
? { ...existing, conversation }
|
|
8298
|
-
: { conversation, streaming: false, deciding: false, error: null, notice: null, lastUsage: null });
|
|
8979
|
+
? { ...existing, conversation, writingMessageId: conversation.status === 'running' ? existing.writingMessageId : null }
|
|
8980
|
+
: { conversation, streaming: false, deciding: false, error: null, notice: null, lastUsage: null, writingMessageId: null });
|
|
8299
8981
|
if (next.size > maxSessions) {
|
|
8300
8982
|
const activeId = this.activeIdState();
|
|
8301
8983
|
for (const [id, session] of next) {
|
|
@@ -8424,16 +9106,59 @@ function messageQueuedNotice(fileCount) {
|
|
|
8424
9106
|
messageKey: fileCount > 0 ? 'nh-assistant.notices.message-queued-with-files' : 'nh-assistant.notices.message-queued'
|
|
8425
9107
|
};
|
|
8426
9108
|
}
|
|
8427
|
-
/**
|
|
9109
|
+
/**
|
|
9110
|
+
* The answer a turn writes after `event`: `turn.started` names it, `turn.completed` and `error` end
|
|
9111
|
+
* the turn, and every other event leaves it as it is.
|
|
9112
|
+
*/
|
|
9113
|
+
function writingAnswerAfter(current, event) {
|
|
9114
|
+
switch (event.type) {
|
|
9115
|
+
case 'turn.started':
|
|
9116
|
+
return event.data?.assistantMessageId ?? null;
|
|
9117
|
+
case 'turn.completed':
|
|
9118
|
+
case 'error':
|
|
9119
|
+
return null;
|
|
9120
|
+
default:
|
|
9121
|
+
return current;
|
|
9122
|
+
}
|
|
9123
|
+
}
|
|
9124
|
+
/**
|
|
9125
|
+
* A completed turn with a server code, or without any answer text, explains itself with a notice.
|
|
9126
|
+
* Another person's message that arrived while the turn ran does not end this tab's turn.
|
|
9127
|
+
*/
|
|
8428
9128
|
function completionNotice(conversation, errorCode) {
|
|
8429
9129
|
if (errorCode) {
|
|
8430
9130
|
return clientError(errorCode);
|
|
8431
9131
|
}
|
|
8432
|
-
|
|
9132
|
+
const ownTurn = { ...conversation, messages: conversation.messages.filter(message => !isOtherPersonsMessage(conversation, message)) };
|
|
9133
|
+
if (!nhAssistantLatestTurnHasText(ownTurn)) {
|
|
8433
9134
|
return { code: NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, messageKey: 'nh-assistant.notices.no-answer' };
|
|
8434
9135
|
}
|
|
8435
9136
|
return null;
|
|
8436
9137
|
}
|
|
9138
|
+
/**
|
|
9139
|
+
* True for a live `message.created` of a message that this tab did not write: the application's, or
|
|
9140
|
+
* a user message of another writer. A user message is this tab's own when the current user wrote it,
|
|
9141
|
+
* and when the tab does not know the current user, so a turn's own message never shows twice.
|
|
9142
|
+
*/
|
|
9143
|
+
function isMessageOfOthers(conversation, event) {
|
|
9144
|
+
if (event.type !== 'message.created') {
|
|
9145
|
+
return false;
|
|
9146
|
+
}
|
|
9147
|
+
const message = event.data;
|
|
9148
|
+
if (!message?.id) {
|
|
9149
|
+
return false;
|
|
9150
|
+
}
|
|
9151
|
+
if (message.role === 'application') {
|
|
9152
|
+
return true;
|
|
9153
|
+
}
|
|
9154
|
+
return message.role === 'user' && isOtherPersonsMessage(conversation, message, event.actorId);
|
|
9155
|
+
}
|
|
9156
|
+
/** True for a user message that a known writer other than the current user wrote. */
|
|
9157
|
+
function isOtherPersonsMessage(conversation, message, fallbackAuthor) {
|
|
9158
|
+
const author = message.authorActorId ?? fallbackAuthor;
|
|
9159
|
+
const currentActorId = conversation.currentActorId;
|
|
9160
|
+
return message.role === 'user' && !!author && !!currentActorId && author !== currentActorId;
|
|
9161
|
+
}
|
|
8437
9162
|
/** The approvals of a conversation that still wait for a decision, each once. */
|
|
8438
9163
|
/** Every approval of the conversation once, by approval id; later parts win. */
|
|
8439
9164
|
function approvalParts(conversation) {
|
|
@@ -8461,6 +9186,20 @@ function pendingApprovalParts(conversation) {
|
|
|
8461
9186
|
}
|
|
8462
9187
|
return [...approvals.values()];
|
|
8463
9188
|
}
|
|
9189
|
+
/**
|
|
9190
|
+
* Who decides an open proposal of an agent thread the caller may not decide, by the server's reason:
|
|
9191
|
+
* the person who consulted the agent, another approver for four-eyes, otherwise an approver.
|
|
9192
|
+
*/
|
|
9193
|
+
function waitingForOf(reasonCode) {
|
|
9194
|
+
switch (reasonCode) {
|
|
9195
|
+
case askerDecidesCode:
|
|
9196
|
+
return 'asker';
|
|
9197
|
+
case fourEyesRequiredCode:
|
|
9198
|
+
return 'other-approver';
|
|
9199
|
+
default:
|
|
9200
|
+
return 'approver';
|
|
9201
|
+
}
|
|
9202
|
+
}
|
|
8464
9203
|
/**
|
|
8465
9204
|
* Shows the decision of an agent's proposal until the reloaded snapshot arrives: the approval's new
|
|
8466
9205
|
* status, no open decision for it and, for the approval the conversation waited for, no pending one.
|
|
@@ -9132,6 +9871,7 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9132
9871
|
'assistant-service-account-not-found',
|
|
9133
9872
|
'assistant-skill-in-code',
|
|
9134
9873
|
'assistant-trigger-in-code',
|
|
9874
|
+
'assistant-trigger-filter-not-found',
|
|
9135
9875
|
'assistant-skill-in-use',
|
|
9136
9876
|
'assistant-configuration-limit',
|
|
9137
9877
|
'assistant-run-settings-in-code',
|
|
@@ -9193,6 +9933,14 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9193
9933
|
'assistant-consult-timeout',
|
|
9194
9934
|
'assistant-consult-failed',
|
|
9195
9935
|
'assistant-consult-read-only',
|
|
9936
|
+
'assistant-consult-proposal-refused',
|
|
9937
|
+
'assistant-consult-asker-decides',
|
|
9938
|
+
'assistant-consult-route-not-allowed',
|
|
9939
|
+
'assistant-consult-proposal-moved',
|
|
9940
|
+
// Consultations defined as data in the administration
|
|
9941
|
+
'assistant-consultation-in-code',
|
|
9942
|
+
'assistant-consultation-not-found',
|
|
9943
|
+
'assistant-consultations-not-allowed',
|
|
9196
9944
|
// Preferences and administration
|
|
9197
9945
|
'assistant-validation',
|
|
9198
9946
|
'assistant-instructions-too-long',
|
|
@@ -9669,8 +10417,11 @@ class NhAssistantComposerComponent {
|
|
|
9669
10417
|
/** True while a file of the next message still uploads. */
|
|
9670
10418
|
this.uploading = computed(() => this.attachments().some(attachment => attachment.state === 'uploading'), ...(ngDevMode ? [{ debugName: "uploading" }] : []));
|
|
9671
10419
|
this.canSend = computed(() => !this.disabled() && !this.sendDisabled() && this.length() > 0 && !this.tooLong() && !this.uploading(), ...(ngDevMode ? [{ debugName: "canSend" }] : []));
|
|
9672
|
-
/** The `accept` attribute of the file input. */
|
|
9673
|
-
this.accept = computed(() =>
|
|
10420
|
+
/** The `accept` attribute of the file input, with the extensions the application mapped. */
|
|
10421
|
+
this.accept = computed(() => {
|
|
10422
|
+
const uploads = this.uploads();
|
|
10423
|
+
return nhAssistantAcceptAttribute(uploads?.acceptedMediaTypes ?? [], uploads?.mappedExtensions);
|
|
10424
|
+
}, ...(ngDevMode ? [{ debugName: "accept" }] : []));
|
|
9674
10425
|
/** The values the attachment texts name: the accepted types, the largest size and the most files. */
|
|
9675
10426
|
this.uploadParams = computed(() => {
|
|
9676
10427
|
const uploads = this.uploads();
|
|
@@ -10289,6 +11040,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10289
11040
|
args: [{ name: 'nhAssistantMarkdown', standalone: true }]
|
|
10290
11041
|
}] });
|
|
10291
11042
|
|
|
11043
|
+
/**
|
|
11044
|
+
* The name of a subject with the name of its type, linked to where the application shows the
|
|
11045
|
+
* subject (internal). The host's `subjectLinks` builder wins over the server's link; a link within
|
|
11046
|
+
* the application navigates through the router, an `https` link leaves it, and anything else shows
|
|
11047
|
+
* no link. Ctrl-, Cmd-, Shift- and middle-clicks keep the browser's behavior, such as a new tab.
|
|
11048
|
+
* A name that already says the type, as "The whole application" does for the application as a
|
|
11049
|
+
* whole, is shown once.
|
|
11050
|
+
*/
|
|
11051
|
+
class NhAssistantSubjectLinkComponent {
|
|
11052
|
+
constructor() {
|
|
11053
|
+
this.config = inject(NH_ASSISTANT_CONFIG, { optional: true });
|
|
11054
|
+
this.router = inject(Router, { optional: true });
|
|
11055
|
+
this.locationStrategy = inject(LocationStrategy, { optional: true });
|
|
11056
|
+
this.injector = inject(EnvironmentInjector);
|
|
11057
|
+
this.subjectType = input.required(...(ngDevMode ? [{ debugName: "subjectType" }] : []));
|
|
11058
|
+
this.subjectId = input.required(...(ngDevMode ? [{ debugName: "subjectId" }] : []));
|
|
11059
|
+
/** The text people read, usually the subject's display name. */
|
|
11060
|
+
this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
11061
|
+
/** The name of the subject type, such as "Project"; nothing is shown without one. */
|
|
11062
|
+
this.typeName = input(null, ...(ngDevMode ? [{ debugName: "typeName" }] : []));
|
|
11063
|
+
/** The server's link to the subject. */
|
|
11064
|
+
this.link = input(null, ...(ngDevMode ? [{ debugName: "link" }] : []));
|
|
11065
|
+
/** The type's name, unless the subject's name is the type's name itself, as for the whole application. */
|
|
11066
|
+
this.shownTypeName = computed(() => {
|
|
11067
|
+
const type = this.typeName()?.trim();
|
|
11068
|
+
if (!type) {
|
|
11069
|
+
return null;
|
|
11070
|
+
}
|
|
11071
|
+
return type.toLocaleLowerCase() === this.label().trim().toLocaleLowerCase() ? null : type;
|
|
11072
|
+
}, ...(ngDevMode ? [{ debugName: "shownTypeName" }] : []));
|
|
11073
|
+
this.target = computed(() => {
|
|
11074
|
+
const builder = this.config?.subjectLinks?.[this.subjectType()];
|
|
11075
|
+
const subject = { type: this.subjectType(), id: this.subjectId() };
|
|
11076
|
+
const custom = builder ? runInInjectionContext(this.injector, () => builder(subject)) : undefined;
|
|
11077
|
+
if (custom === null) {
|
|
11078
|
+
return null;
|
|
11079
|
+
}
|
|
11080
|
+
if (Array.isArray(custom)) {
|
|
11081
|
+
return this.routeTarget(this.router ? this.router.serializeUrl(this.router.createUrlTree([...custom])) : null);
|
|
11082
|
+
}
|
|
11083
|
+
return this.urlTarget(typeof custom === 'string' ? custom : this.link() ?? null);
|
|
11084
|
+
}, ...(ngDevMode ? [{ debugName: "target" }] : []));
|
|
11085
|
+
}
|
|
11086
|
+
open(event, target) {
|
|
11087
|
+
nhAssistantOpenLink(event, target, this.router);
|
|
11088
|
+
}
|
|
11089
|
+
urlTarget(url) {
|
|
11090
|
+
return nhAssistantLinkTarget(url, this.router, this.locationStrategy);
|
|
11091
|
+
}
|
|
11092
|
+
routeTarget(url) {
|
|
11093
|
+
return nhAssistantRouteTarget(url, this.router, this.locationStrategy);
|
|
11094
|
+
}
|
|
11095
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11096
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantSubjectLinkComponent, isStandalone: true, selector: "nh-assistant-subject-link", inputs: { subjectType: { classPropertyName: "subjectType", publicName: "subjectType", isSignal: true, isRequired: true, transformFunction: null }, subjectId: { classPropertyName: "subjectId", publicName: "subjectId", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, typeName: { classPropertyName: "typeName", publicName: "typeName", isSignal: true, isRequired: false, transformFunction: null }, link: { classPropertyName: "link", publicName: "link", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
11097
|
+
@if (shownTypeName(); as type) {
|
|
11098
|
+
<!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
|
|
11099
|
+
<span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
|
|
11100
|
+
}
|
|
11101
|
+
@if (target(); as link) {
|
|
11102
|
+
<a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
|
|
11103
|
+
} @else {
|
|
11104
|
+
<span class="nh-assistant-subject-name">{{ label() }}</span>
|
|
11105
|
+
}
|
|
11106
|
+
`, isInline: true, styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:.35em;min-width:0;overflow-wrap:anywhere}.nh-assistant-subject-type{color:var(--nha-text-muted);font-size:.85em;font-weight:500}a.nh-assistant-subject-name{border-radius:2px;color:inherit;text-decoration:underline;text-underline-offset:.15em}a.nh-assistant-subject-name:hover{color:var(--nha-accent)}a.nh-assistant-subject-name:focus-visible{outline:2px solid var(--nha-focus);outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11107
|
+
}
|
|
11108
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, decorators: [{
|
|
11109
|
+
type: Component,
|
|
11110
|
+
args: [{ selector: 'nh-assistant-subject-link', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
11111
|
+
@if (shownTypeName(); as type) {
|
|
11112
|
+
<!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
|
|
11113
|
+
<span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
|
|
11114
|
+
}
|
|
11115
|
+
@if (target(); as link) {
|
|
11116
|
+
<a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
|
|
11117
|
+
} @else {
|
|
11118
|
+
<span class="nh-assistant-subject-name">{{ label() }}</span>
|
|
11119
|
+
}
|
|
11120
|
+
`, styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:.35em;min-width:0;overflow-wrap:anywhere}.nh-assistant-subject-type{color:var(--nha-text-muted);font-size:.85em;font-weight:500}a.nh-assistant-subject-name{border-radius:2px;color:inherit;text-decoration:underline;text-underline-offset:.15em}a.nh-assistant-subject-name:hover{color:var(--nha-accent)}a.nh-assistant-subject-name:focus-visible{outline:2px solid var(--nha-focus);outline-offset:2px}\n"] }]
|
|
11121
|
+
}], propDecorators: { subjectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "subjectType", required: true }] }], subjectId: [{ type: i0.Input, args: [{ isSignal: true, alias: "subjectId", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], typeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeName", required: false }] }], link: [{ type: i0.Input, args: [{ isSignal: true, alias: "link", required: false }] }] } });
|
|
11122
|
+
/**
|
|
11123
|
+
* Where a link the server sent leads (internal): a path within the application, which the router
|
|
11124
|
+
* opens, an `https` address elsewhere, or `null` for anything else, so no other scheme reaches an
|
|
11125
|
+
* anchor. Subject links and the links of application messages follow this rule.
|
|
11126
|
+
*/
|
|
11127
|
+
function nhAssistantLinkTarget(url, router, locationStrategy) {
|
|
11128
|
+
if (!url) {
|
|
11129
|
+
return null;
|
|
11130
|
+
}
|
|
11131
|
+
if (url.startsWith('/') && !url.startsWith('//') && !url.startsWith('/\\')) {
|
|
11132
|
+
return nhAssistantRouteTarget(url, router, locationStrategy);
|
|
11133
|
+
}
|
|
11134
|
+
return /^https:\/\/[^/\\\s]+/i.test(url) ? { href: url, route: null } : null;
|
|
11135
|
+
}
|
|
11136
|
+
/** A route of the application as the browser shows it and as the router opens it (internal). */
|
|
11137
|
+
function nhAssistantRouteTarget(url, router, locationStrategy) {
|
|
11138
|
+
if (!url) {
|
|
11139
|
+
return null;
|
|
11140
|
+
}
|
|
11141
|
+
return {
|
|
11142
|
+
href: locationStrategy ? locationStrategy.prepareExternalUrl(url) : url,
|
|
11143
|
+
route: router ? url : null
|
|
11144
|
+
};
|
|
11145
|
+
}
|
|
11146
|
+
/**
|
|
11147
|
+
* Opens a route of the application through the router on a plain click (internal). Ctrl-, Cmd-,
|
|
11148
|
+
* Shift-, Alt- and middle-clicks, and addresses outside the application, keep the browser's behavior.
|
|
11149
|
+
*/
|
|
11150
|
+
function nhAssistantOpenLink(event, target, router) {
|
|
11151
|
+
if (!target.route || !router || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
11152
|
+
return;
|
|
11153
|
+
}
|
|
11154
|
+
event.preventDefault();
|
|
11155
|
+
void router.navigateByUrl(target.route);
|
|
11156
|
+
}
|
|
11157
|
+
|
|
11158
|
+
/**
|
|
11159
|
+
* The link of a message the application posted (internal): a path within the application opens
|
|
11160
|
+
* through the router, an `https` address leaves it, and anything else shows nothing, by the same rule
|
|
11161
|
+
* as subject links.
|
|
11162
|
+
*/
|
|
11163
|
+
class NhAssistantMessageLinkComponent {
|
|
11164
|
+
constructor() {
|
|
11165
|
+
this.router = inject(Router, { optional: true });
|
|
11166
|
+
this.locationStrategy = inject(LocationStrategy, { optional: true });
|
|
11167
|
+
/** A path within the application or an `https` address. */
|
|
11168
|
+
this.url = input.required(...(ngDevMode ? [{ debugName: "url" }] : []));
|
|
11169
|
+
/** The text people read. */
|
|
11170
|
+
this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
11171
|
+
this.target = computed(() => nhAssistantLinkTarget(this.url(), this.router, this.locationStrategy), ...(ngDevMode ? [{ debugName: "target" }] : []));
|
|
11172
|
+
}
|
|
11173
|
+
open(event, target) {
|
|
11174
|
+
nhAssistantOpenLink(event, target, this.router);
|
|
11175
|
+
}
|
|
11176
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantMessageLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11177
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantMessageLinkComponent, isStandalone: true, selector: "nh-assistant-message-link", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
11178
|
+
@if (target(); as link) {
|
|
11179
|
+
<a class="nh-assistant-message-link" [href]="link.href" (click)="open($event, link)">
|
|
11180
|
+
<nh-assistant-icon name="link" />{{ label() }}
|
|
11181
|
+
</a>
|
|
11182
|
+
}
|
|
11183
|
+
`, isInline: true, styles: [":host{display:block}.nh-assistant-message-link{display:inline-flex;align-items:center;gap:6px;color:var(--nha-accent);font-size:13px;font-weight:600;text-decoration:none}.nh-assistant-message-link:hover{text-decoration:underline}.nh-assistant-message-link:focus-visible{outline:2px solid var(--nha-focus);outline-offset:2px;border-radius:4px}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11184
|
+
}
|
|
11185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantMessageLinkComponent, decorators: [{
|
|
11186
|
+
type: Component,
|
|
11187
|
+
args: [{ selector: 'nh-assistant-message-link', standalone: true, imports: [NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
11188
|
+
@if (target(); as link) {
|
|
11189
|
+
<a class="nh-assistant-message-link" [href]="link.href" (click)="open($event, link)">
|
|
11190
|
+
<nh-assistant-icon name="link" />{{ label() }}
|
|
11191
|
+
</a>
|
|
11192
|
+
}
|
|
11193
|
+
`, styles: [":host{display:block}.nh-assistant-message-link{display:inline-flex;align-items:center;gap:6px;color:var(--nha-accent);font-size:13px;font-weight:600;text-decoration:none}.nh-assistant-message-link:hover{text-decoration:underline}.nh-assistant-message-link:focus-visible{outline:2px solid var(--nha-focus);outline-offset:2px;border-radius:4px}\n"] }]
|
|
11194
|
+
}], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }] } });
|
|
11195
|
+
|
|
10292
11196
|
/**
|
|
10293
11197
|
* Groups consecutive tool calls of a message, and consecutive files. Text and approvals break a
|
|
10294
11198
|
* group, so an approval always stays visible. A tool group's key is its first invocation id, so it
|
|
@@ -10473,10 +11377,16 @@ function formatNhAssistantCountdown(milliseconds) {
|
|
|
10473
11377
|
* proposed arguments and a countdown to expiry. A decision is emitted at most once until
|
|
10474
11378
|
* the host reports that it is no longer deciding. After the user rejected an agent's proposal
|
|
10475
11379
|
* (`canGiveFeedback`), a low-key action asks what was wrong. A proposal that closed because it no
|
|
10476
|
-
* longer fits shows why, such as "Already done", with the application's explanation.
|
|
11380
|
+
* longer fits shows why, such as "Already done", with the application's explanation. A proposal of
|
|
11381
|
+
* another agent the assistant consulted (`consultation`) names that agent and the subject, offers the
|
|
11382
|
+
* agent's answer and says that approving runs it with the user's own rights; with a
|
|
11383
|
+
* `consultation.leaveRoute` a third action leaves it for the subject's approvers (`leave`), after which
|
|
11384
|
+
* the card says that it waits for them.
|
|
10477
11385
|
*/
|
|
10478
11386
|
class NhAssistantApprovalCardComponent {
|
|
10479
11387
|
constructor() {
|
|
11388
|
+
/** Names the consulted agent as the status does; the card also works outside `provideNhAssistant`. */
|
|
11389
|
+
this.store = inject(NhAssistantStore, { optional: true });
|
|
10480
11390
|
this.approval = input.required(...(ngDevMode ? [{ debugName: "approval" }] : []));
|
|
10481
11391
|
/** True while the host submits a decision; disables both buttons. */
|
|
10482
11392
|
this.deciding = input(false, ...(ngDevMode ? [{ debugName: "deciding" }] : []));
|
|
@@ -10501,6 +11411,8 @@ class NhAssistantApprovalCardComponent {
|
|
|
10501
11411
|
this.decide = output();
|
|
10502
11412
|
this.now = signal(Date.now(), ...(ngDevMode ? [{ debugName: "now" }] : []));
|
|
10503
11413
|
this.submitted = signal(false, ...(ngDevMode ? [{ debugName: "submitted" }] : []));
|
|
11414
|
+
/** The decision this card sent last, so a proposal left for the approvers reads as such at once. */
|
|
11415
|
+
this.chosen = signal(null, ...(ngDevMode ? [{ debugName: "chosen" }] : []));
|
|
10504
11416
|
/** The feedback question is expanded. */
|
|
10505
11417
|
this.feedbackOpen = signal(false, ...(ngDevMode ? [{ debugName: "feedbackOpen" }] : []));
|
|
10506
11418
|
/** The feedback was stored; the question thanks the person and the action disappears. */
|
|
@@ -10510,11 +11422,45 @@ class NhAssistantApprovalCardComponent {
|
|
|
10510
11422
|
this.expired = computed(() => this.approval().status === 'expired' ||
|
|
10511
11423
|
(this.approval().status === 'pending' && this.remainingMs() <= 0), ...(ngDevMode ? [{ debugName: "expired" }] : []));
|
|
10512
11424
|
this.effectiveStatus = computed(() => this.expired() ? 'expired' : this.approval().status, ...(ngDevMode ? [{ debugName: "effectiveStatus" }] : []));
|
|
11425
|
+
/** Where a consulted agent's proposal comes from; `null` for the conversation's own proposals. */
|
|
11426
|
+
this.consultation = computed(() => this.approval().consultation ?? null, ...(ngDevMode ? [{ debugName: "consultation" }] : []));
|
|
11427
|
+
/**
|
|
11428
|
+
* The translation keys of the consulted agent's name: the name the assistant's status gives it,
|
|
11429
|
+
* then the convention `nh-assistant.agents.{id}.name`; the id when neither translates.
|
|
11430
|
+
*/
|
|
11431
|
+
this.consultedAgentKeys = computed(() => {
|
|
11432
|
+
const consultation = this.consultation();
|
|
11433
|
+
if (!consultation) {
|
|
11434
|
+
return [];
|
|
11435
|
+
}
|
|
11436
|
+
const convention = `nh-assistant.agents.${consultation.agentId}.name`;
|
|
11437
|
+
const known = this.store?.agents().find(agent => agent.id === consultation.agentId)?.displayNameKey;
|
|
11438
|
+
return known && known !== convention ? [known, convention] : [convention];
|
|
11439
|
+
}, ...(ngDevMode ? [{ debugName: "consultedAgentKeys" }] : []));
|
|
11440
|
+
/** The subject the consulted agent was asked about, by name or else by id. */
|
|
11441
|
+
this.consultedSubject = computed(() => {
|
|
11442
|
+
const consultation = this.consultation();
|
|
11443
|
+
return consultation ? consultation.subjectDisplayName ?? consultation.subjectId : null;
|
|
11444
|
+
}, ...(ngDevMode ? [{ debugName: "consultedSubject" }] : []));
|
|
11445
|
+
/**
|
|
11446
|
+
* The user left the consulted agent's proposal for the subject's approvers: the server names the
|
|
11447
|
+
* proposal that waits there, or this card just sent the decision and it was accepted.
|
|
11448
|
+
*/
|
|
11449
|
+
this.leftForApprovers = computed(() => {
|
|
11450
|
+
const consultation = this.consultation();
|
|
11451
|
+
return consultation !== null
|
|
11452
|
+
&& (!!consultation.movedToApprovalId || (this.chosen() === 'leave' && this.approval().status !== 'pending'));
|
|
11453
|
+
}, ...(ngDevMode ? [{ debugName: "leftForApprovers" }] : []));
|
|
11454
|
+
/** The status the card shows: `moved` for a proposal left for the subject's approvers. */
|
|
11455
|
+
this.shownStatus = computed(() => this.leftForApprovers() ? 'moved' : this.effectiveStatus(), ...(ngDevMode ? [{ debugName: "shownStatus" }] : []));
|
|
10513
11456
|
/**
|
|
10514
11457
|
* Translation key of the status: the kind of a stale proposal, "replaced" for a superseded one,
|
|
10515
|
-
* otherwise the status itself.
|
|
11458
|
+
* "left for approvers" for a consulted agent's proposal the user left, otherwise the status itself.
|
|
10516
11459
|
*/
|
|
10517
11460
|
this.statusKey = computed(() => {
|
|
11461
|
+
if (this.leftForApprovers()) {
|
|
11462
|
+
return 'nh-assistant.approval.consultation.moved-status';
|
|
11463
|
+
}
|
|
10518
11464
|
const kind = this.approval().staleKind;
|
|
10519
11465
|
if (this.effectiveStatus() === 'stale' && kind) {
|
|
10520
11466
|
return `nh-assistant.approval.stale-kind.${kind}`;
|
|
@@ -10530,6 +11476,9 @@ class NhAssistantApprovalCardComponent {
|
|
|
10530
11476
|
this.actionable = computed(() => this.effectiveStatus() === 'pending', ...(ngDevMode ? [{ debugName: "actionable" }] : []));
|
|
10531
11477
|
this.succeeded = computed(() => ['approved', 'executing', 'executed', 'resolved'].includes(this.effectiveStatus()), ...(ngDevMode ? [{ debugName: "succeeded" }] : []));
|
|
10532
11478
|
this.disabled = computed(() => !this.actionable() || !this.canDecide() || this.deciding() || this.submitted(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
11479
|
+
/** The route at the subject the pending proposal may be left for; `null` when it can only be approved or rejected. */
|
|
11480
|
+
this.leaveRoute = computed(() => this.actionable() ? this.consultation()?.leaveRoute ?? null : null, ...(ngDevMode ? [{ debugName: "leaveRoute" }] : []));
|
|
11481
|
+
this.leaveHintId = `nh-assistant-approval-leave-${nextId$5++}`;
|
|
10533
11482
|
this.countdown = computed(() => formatNhAssistantCountdown(this.remainingMs()), ...(ngDevMode ? [{ debugName: "countdown" }] : []));
|
|
10534
11483
|
this.presentedSummary = computed(() => this.approval().presentation?.summary ?? null, ...(ngDevMode ? [{ debugName: "presentedSummary" }] : []));
|
|
10535
11484
|
this.feedbackAvailable = computed(() => this.canGiveFeedback() && this.effectiveStatus() === 'rejected', ...(ngDevMode ? [{ debugName: "feedbackAvailable" }] : []));
|
|
@@ -10542,6 +11491,8 @@ class NhAssistantApprovalCardComponent {
|
|
|
10542
11491
|
return 'nh-assistant.approval.waiting-for-approver';
|
|
10543
11492
|
case 'other-approver':
|
|
10544
11493
|
return 'nh-assistant.approval.waiting-for-other-approver';
|
|
11494
|
+
case 'asker':
|
|
11495
|
+
return 'nh-assistant.approval.waiting-for-asker';
|
|
10545
11496
|
default:
|
|
10546
11497
|
return this.decisionOwner() ? 'nh-assistant.approval.waiting-for' : 'nh-assistant.approval.waiting-for-participant';
|
|
10547
11498
|
}
|
|
@@ -10567,11 +11518,13 @@ class NhAssistantApprovalCardComponent {
|
|
|
10567
11518
|
}
|
|
10568
11519
|
});
|
|
10569
11520
|
}
|
|
11521
|
+
/** Emits a decision; `leave` only for a consulted agent's proposal with a route at the subject. */
|
|
10570
11522
|
choose(decision) {
|
|
10571
|
-
if (this.disabled()) {
|
|
11523
|
+
if (this.disabled() || (decision === 'leave' && this.leaveRoute() === null)) {
|
|
10572
11524
|
return;
|
|
10573
11525
|
}
|
|
10574
11526
|
this.submitted.set(true);
|
|
11527
|
+
this.chosen.set(decision);
|
|
10575
11528
|
this.decide.emit(decision);
|
|
10576
11529
|
}
|
|
10577
11530
|
toggleFeedback() {
|
|
@@ -10586,13 +11539,13 @@ class NhAssistantApprovalCardComponent {
|
|
|
10586
11539
|
this.feedbackToggle()?.nativeElement.focus();
|
|
10587
11540
|
}
|
|
10588
11541
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantApprovalCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10589
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantApprovalCardComponent, isStandalone: true, selector: "nh-assistant-approval-card", inputs: { approval: { classPropertyName: "approval", publicName: "approval", isSignal: true, isRequired: true, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, canDecide: { classPropertyName: "canDecide", publicName: "canDecide", isSignal: true, isRequired: false, transformFunction: null }, decisionOwner: { classPropertyName: "decisionOwner", publicName: "decisionOwner", isSignal: true, isRequired: false, transformFunction: null }, waitingFor: { classPropertyName: "waitingFor", publicName: "waitingFor", isSignal: true, isRequired: false, transformFunction: null }, canGiveFeedback: { classPropertyName: "canGiveFeedback", publicName: "canGiveFeedback", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { decide: "decide" }, host: { properties: { "attr.data-status": "effectiveStatus()" } }, viewQueries: [{ propertyName: "feedbackToggle", first: true, predicate: ["feedbackToggle"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"actionable() ? 'warning' : succeeded() ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ statusKey() | translate }}</span>\n </header>\n\n @if (staleExplanation(); as explanation) {\n <p class=\"stale-explanation\">{{ explanation }}</p>\n }\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n @if (rationale(); as why) {\n <p class=\"rationale\">{{ 'nh-assistant.approval.rationale' | translate: { rationale: why } }}</p>\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable() && !canDecide()) {\n <p class=\"waiting-for-other\" role=\"status\">\n <nh-assistant-icon name=\"users\" />\n {{ waitingKey() | translate: { name: decisionOwner() } }}\n </p>\n } @else if (actionable()) {\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n\n @if (feedbackAvailable()) {\n @if (!feedbackSaved()) {\n <button\n #feedbackToggle\n class=\"feedback-toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"feedbackOpen()\"\n [attr.aria-controls]=\"feedbackOpen() ? feedbackPanelId : null\"\n (click)=\"toggleFeedback()\">\n {{ 'nh-assistant.approval.give-feedback' | translate }}\n </button>\n }\n @if (feedbackOpen()) {\n <nh-assistant-proposal-feedback\n class=\"feedback\"\n [attr.id]=\"feedbackPanelId\"\n [approvalIds]=\"feedbackIds()\"\n (saved)=\"onFeedbackSaved()\"\n (dismissed)=\"onFeedbackDismissed()\" />\n }\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]),:host([data-status=stale]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700;overflow-wrap:anywhere}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.stale-explanation{margin:8px 0 0;border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong);font-size:13px;overflow-wrap:anywhere}.rationale{margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding,.waiting-for-other{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.reject{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}.feedback-toggle{display:inline-flex;min-height:0;margin-top:10px;border:0;border-radius:6px;padding:2px 0;color:var(--nha-text-muted);background:transparent;font-size:12px;font-weight:650;text-decoration:underline;text-underline-offset:2px}.feedback-toggle:hover:not(:disabled){color:var(--nha-text)}.feedback{display:block;margin-top:10px}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantProposalFeedbackComponent, selector: "nh-assistant-proposal-feedback", inputs: ["approvalIds", "initial"], outputs: ["saved", "dismissed"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11542
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantApprovalCardComponent, isStandalone: true, selector: "nh-assistant-approval-card", inputs: { approval: { classPropertyName: "approval", publicName: "approval", isSignal: true, isRequired: true, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, canDecide: { classPropertyName: "canDecide", publicName: "canDecide", isSignal: true, isRequired: false, transformFunction: null }, decisionOwner: { classPropertyName: "decisionOwner", publicName: "decisionOwner", isSignal: true, isRequired: false, transformFunction: null }, waitingFor: { classPropertyName: "waitingFor", publicName: "waitingFor", isSignal: true, isRequired: false, transformFunction: null }, canGiveFeedback: { classPropertyName: "canGiveFeedback", publicName: "canGiveFeedback", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { decide: "decide" }, host: { properties: { "attr.data-status": "shownStatus()" } }, viewQueries: [{ propertyName: "feedbackToggle", first: true, predicate: ["feedbackToggle"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"leftForApprovers() ? 'users' : actionable() ? 'warning' : succeeded() ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ statusKey() | translate }}</span>\n </header>\n\n @if (staleExplanation(); as explanation) {\n <p class=\"stale-explanation\">{{ explanation }}</p>\n }\n\n <!-- Another agent the assistant consulted proposes this; the person who asked decides it here. -->\n @if (consultation(); as origin) {\n <p class=\"consultation-origin\" data-consultation-origin>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.origin' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId), subject: consultedSubject() } }}</span>\n </p>\n }\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n @if (rationale(); as why) {\n <p class=\"rationale\">{{ 'nh-assistant.approval.rationale' | translate: { rationale: why } }}</p>\n }\n\n @if (consultation(); as origin) {\n @if (origin.answer) {\n <details class=\"consultation-answer\" data-consultation-answer>\n <summary>{{ 'nh-assistant.approval.consultation.answer' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId) } }}</summary>\n <p>{{ origin.answer }}</p>\n </details>\n }\n @if (leftForApprovers()) {\n <p class=\"consultation-moved\" role=\"status\" data-consultation-moved>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.moved' | translate: { subject: consultedSubject() } }}</span>\n </p>\n }\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable() && !canDecide()) {\n <p class=\"waiting-for-other\" role=\"status\">\n <nh-assistant-icon name=\"users\" />\n {{ waitingKey() | translate: { name: decisionOwner() } }}\n </p>\n } @else if (actionable()) {\n @if (consultation()) {\n <p class=\"consultation-rights\" data-consultation-rights>{{ 'nh-assistant.approval.consultation.own-rights' | translate }}</p>\n }\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n <!-- The person may leave a consulted agent's proposal for the subject's approvers instead. -->\n @if (leaveRoute(); as route) {\n <div class=\"leave-for-approvers\">\n <p class=\"leave-explanation\" [id]=\"leaveHintId\">{{ 'nh-assistant.approval.consultation.leave-explain.' + route | translate: { subject: consultedSubject() } }}</p>\n <button\n class=\"leave\"\n type=\"button\"\n data-leave\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.consultation.leave-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n [attr.aria-describedby]=\"leaveHintId\"\n (click)=\"choose('leave')\">\n {{ 'nh-assistant.approval.consultation.leave' | translate }}\n </button>\n </div>\n }\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n\n @if (feedbackAvailable()) {\n @if (!feedbackSaved()) {\n <button\n #feedbackToggle\n class=\"feedback-toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"feedbackOpen()\"\n [attr.aria-controls]=\"feedbackOpen() ? feedbackPanelId : null\"\n (click)=\"toggleFeedback()\">\n {{ 'nh-assistant.approval.give-feedback' | translate }}\n </button>\n }\n @if (feedbackOpen()) {\n <nh-assistant-proposal-feedback\n class=\"feedback\"\n [attr.id]=\"feedbackPanelId\"\n [approvalIds]=\"feedbackIds()\"\n (saved)=\"onFeedbackSaved()\"\n (dismissed)=\"onFeedbackDismissed()\" />\n }\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]),:host([data-status=stale]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700;overflow-wrap:anywhere}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.stale-explanation{margin:8px 0 0;border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong);font-size:13px;overflow-wrap:anywhere}.consultation-origin,.consultation-moved{display:flex;align-items:flex-start;gap:6px;margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.consultation-moved{border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong)}.consultation-answer{margin-top:8px;font-size:13px}.consultation-answer summary{cursor:pointer;color:var(--nha-text-muted);font-size:12px;font-weight:700}.consultation-answer summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.consultation-answer p{max-height:200px;margin:6px 0 0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);white-space:pre-wrap;overflow-wrap:anywhere}.consultation-rights{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.rationale{margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding,.waiting-for-other{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.leave-for-approvers{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-top:10px}.leave-explanation{flex:1 1 200px;margin:0;color:var(--nha-text-muted);font-size:12px}.reject,.leave{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled),.leave:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}.feedback-toggle{display:inline-flex;min-height:0;margin-top:10px;border:0;border-radius:6px;padding:2px 0;color:var(--nha-text-muted);background:transparent;font-size:12px;font-weight:650;text-decoration:underline;text-underline-offset:2px}.feedback-toggle:hover:not(:disabled){color:var(--nha-text)}.feedback{display:block;margin-top:10px}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantProposalFeedbackComponent, selector: "nh-assistant-proposal-feedback", inputs: ["approvalIds", "initial"], outputs: ["saved", "dismissed"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10590
11543
|
}
|
|
10591
11544
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantApprovalCardComponent, decorators: [{
|
|
10592
11545
|
type: Component,
|
|
10593
|
-
args: [{ selector: 'nh-assistant-approval-card', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent, NhAssistantProposalFeedbackComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
10594
|
-
'[attr.data-status]': '
|
|
10595
|
-
}, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"actionable() ? 'warning' : succeeded() ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ statusKey() | translate }}</span>\n </header>\n\n @if (staleExplanation(); as explanation) {\n <p class=\"stale-explanation\">{{ explanation }}</p>\n }\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n @if (rationale(); as why) {\n <p class=\"rationale\">{{ 'nh-assistant.approval.rationale' | translate: { rationale: why } }}</p>\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable() && !canDecide()) {\n <p class=\"waiting-for-other\" role=\"status\">\n <nh-assistant-icon name=\"users\" />\n {{ waitingKey() | translate: { name: decisionOwner() } }}\n </p>\n } @else if (actionable()) {\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n\n @if (feedbackAvailable()) {\n @if (!feedbackSaved()) {\n <button\n #feedbackToggle\n class=\"feedback-toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"feedbackOpen()\"\n [attr.aria-controls]=\"feedbackOpen() ? feedbackPanelId : null\"\n (click)=\"toggleFeedback()\">\n {{ 'nh-assistant.approval.give-feedback' | translate }}\n </button>\n }\n @if (feedbackOpen()) {\n <nh-assistant-proposal-feedback\n class=\"feedback\"\n [attr.id]=\"feedbackPanelId\"\n [approvalIds]=\"feedbackIds()\"\n (saved)=\"onFeedbackSaved()\"\n (dismissed)=\"onFeedbackDismissed()\" />\n }\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]),:host([data-status=stale]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700;overflow-wrap:anywhere}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.stale-explanation{margin:8px 0 0;border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong);font-size:13px;overflow-wrap:anywhere}.rationale{margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding,.waiting-for-other{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.reject{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}.feedback-toggle{display:inline-flex;min-height:0;margin-top:10px;border:0;border-radius:6px;padding:2px 0;color:var(--nha-text-muted);background:transparent;font-size:12px;font-weight:650;text-decoration:underline;text-underline-offset:2px}.feedback-toggle:hover:not(:disabled){color:var(--nha-text)}.feedback{display:block;margin-top:10px}\n"] }]
|
|
11546
|
+
args: [{ selector: 'nh-assistant-approval-card', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent, NhAssistantProposalFeedbackComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
11547
|
+
'[attr.data-status]': 'shownStatus()'
|
|
11548
|
+
}, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"leftForApprovers() ? 'users' : actionable() ? 'warning' : succeeded() ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ statusKey() | translate }}</span>\n </header>\n\n @if (staleExplanation(); as explanation) {\n <p class=\"stale-explanation\">{{ explanation }}</p>\n }\n\n <!-- Another agent the assistant consulted proposes this; the person who asked decides it here. -->\n @if (consultation(); as origin) {\n <p class=\"consultation-origin\" data-consultation-origin>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.origin' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId), subject: consultedSubject() } }}</span>\n </p>\n }\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n @if (rationale(); as why) {\n <p class=\"rationale\">{{ 'nh-assistant.approval.rationale' | translate: { rationale: why } }}</p>\n }\n\n @if (consultation(); as origin) {\n @if (origin.answer) {\n <details class=\"consultation-answer\" data-consultation-answer>\n <summary>{{ 'nh-assistant.approval.consultation.answer' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId) } }}</summary>\n <p>{{ origin.answer }}</p>\n </details>\n }\n @if (leftForApprovers()) {\n <p class=\"consultation-moved\" role=\"status\" data-consultation-moved>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.moved' | translate: { subject: consultedSubject() } }}</span>\n </p>\n }\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable() && !canDecide()) {\n <p class=\"waiting-for-other\" role=\"status\">\n <nh-assistant-icon name=\"users\" />\n {{ waitingKey() | translate: { name: decisionOwner() } }}\n </p>\n } @else if (actionable()) {\n @if (consultation()) {\n <p class=\"consultation-rights\" data-consultation-rights>{{ 'nh-assistant.approval.consultation.own-rights' | translate }}</p>\n }\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n <!-- The person may leave a consulted agent's proposal for the subject's approvers instead. -->\n @if (leaveRoute(); as route) {\n <div class=\"leave-for-approvers\">\n <p class=\"leave-explanation\" [id]=\"leaveHintId\">{{ 'nh-assistant.approval.consultation.leave-explain.' + route | translate: { subject: consultedSubject() } }}</p>\n <button\n class=\"leave\"\n type=\"button\"\n data-leave\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.consultation.leave-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n [attr.aria-describedby]=\"leaveHintId\"\n (click)=\"choose('leave')\">\n {{ 'nh-assistant.approval.consultation.leave' | translate }}\n </button>\n </div>\n }\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n\n @if (feedbackAvailable()) {\n @if (!feedbackSaved()) {\n <button\n #feedbackToggle\n class=\"feedback-toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"feedbackOpen()\"\n [attr.aria-controls]=\"feedbackOpen() ? feedbackPanelId : null\"\n (click)=\"toggleFeedback()\">\n {{ 'nh-assistant.approval.give-feedback' | translate }}\n </button>\n }\n @if (feedbackOpen()) {\n <nh-assistant-proposal-feedback\n class=\"feedback\"\n [attr.id]=\"feedbackPanelId\"\n [approvalIds]=\"feedbackIds()\"\n (saved)=\"onFeedbackSaved()\"\n (dismissed)=\"onFeedbackDismissed()\" />\n }\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]),:host([data-status=stale]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700;overflow-wrap:anywhere}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.stale-explanation{margin:8px 0 0;border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong);font-size:13px;overflow-wrap:anywhere}.consultation-origin,.consultation-moved{display:flex;align-items:flex-start;gap:6px;margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.consultation-moved{border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong)}.consultation-answer{margin-top:8px;font-size:13px}.consultation-answer summary{cursor:pointer;color:var(--nha-text-muted);font-size:12px;font-weight:700}.consultation-answer summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.consultation-answer p{max-height:200px;margin:6px 0 0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);white-space:pre-wrap;overflow-wrap:anywhere}.consultation-rights{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.rationale{margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding,.waiting-for-other{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.leave-for-approvers{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-top:10px}.leave-explanation{flex:1 1 200px;margin:0;color:var(--nha-text-muted);font-size:12px}.reject,.leave{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled),.leave:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}.feedback-toggle{display:inline-flex;min-height:0;margin-top:10px;border:0;border-radius:6px;padding:2px 0;color:var(--nha-text-muted);background:transparent;font-size:12px;font-weight:650;text-decoration:underline;text-underline-offset:2px}.feedback-toggle:hover:not(:disabled){color:var(--nha-text)}.feedback{display:block;margin-top:10px}\n"] }]
|
|
10596
11549
|
}], ctorParameters: () => [], propDecorators: { approval: [{ type: i0.Input, args: [{ isSignal: true, alias: "approval", required: true }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], canDecide: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDecide", required: false }] }], decisionOwner: [{ type: i0.Input, args: [{ isSignal: true, alias: "decisionOwner", required: false }] }], waitingFor: [{ type: i0.Input, args: [{ isSignal: true, alias: "waitingFor", required: false }] }], canGiveFeedback: [{ type: i0.Input, args: [{ isSignal: true, alias: "canGiveFeedback", required: false }] }], decide: [{ type: i0.Output, args: ["decide"] }], feedbackToggle: [{ type: i0.ViewChild, args: ['feedbackToggle', { isSignal: true }] }] } });
|
|
10597
11550
|
|
|
10598
11551
|
let nextId$4 = 0;
|
|
@@ -10774,9 +11727,12 @@ const stickToBottomDistance = 120;
|
|
|
10774
11727
|
* The messages of a conversation as a live log. Assistant text renders as sanitized
|
|
10775
11728
|
* Markdown, consecutive tool calls as one collapsible group that counts along, and
|
|
10776
11729
|
* approvals as cards. The files a person attached show by name, type and size. Messages a
|
|
10777
|
-
* trigger wrote into an agent thread read as events, not as a person
|
|
10778
|
-
*
|
|
10779
|
-
*
|
|
11730
|
+
* trigger wrote into an agent thread read as events, not as a person, and a message the application
|
|
11731
|
+
* posted reads as the application's, with its sender, title, Markdown text and link, and a label when
|
|
11732
|
+
* the assistant follows it as an instruction. While a turn runs without visible progress, a working
|
|
11733
|
+
* indicator shows the elapsed time: under the answer `writingMessageId` names, also when the
|
|
11734
|
+
* application's or another person's message arrived after it, and at the end without it. The thread
|
|
11735
|
+
* follows new content while the user is at the bottom.
|
|
10780
11736
|
*/
|
|
10781
11737
|
class NhAssistantThreadComponent {
|
|
10782
11738
|
/** The type and size of an attached file, in the current language. */
|
|
@@ -10824,6 +11780,13 @@ class NhAssistantThreadComponent {
|
|
|
10824
11780
|
* card of a rejected proposal ask what was wrong.
|
|
10825
11781
|
*/
|
|
10826
11782
|
this.approvalRights = input(null, ...(ngDevMode ? [{ debugName: "approvalRights" }] : []));
|
|
11783
|
+
/**
|
|
11784
|
+
* The answer the running turn writes, for example `NhAssistantStore.writingMessageId`. The working
|
|
11785
|
+
* indicator stays under that answer, also when the application's or a colleague's message arrives
|
|
11786
|
+
* after it during the turn. Without it, or when it names no message of `messages`, the indicator
|
|
11787
|
+
* shows at the end of the thread.
|
|
11788
|
+
*/
|
|
11789
|
+
this.writingMessageId = input(null, ...(ngDevMode ? [{ debugName: "writingMessageId" }] : []));
|
|
10827
11790
|
/** The decision about an approval card, without the approval it belongs to. */
|
|
10828
11791
|
this.approvalDecision = output();
|
|
10829
11792
|
/** The decision about an approval card together with its approval id. */
|
|
@@ -10839,14 +11802,16 @@ class NhAssistantThreadComponent {
|
|
|
10839
11802
|
/**
|
|
10840
11803
|
* True while the turn runs and nothing else shows progress: before the first part and
|
|
10841
11804
|
* between tool calls while the model decides what to do next. Streaming text and a
|
|
10842
|
-
* running tool group show their own progress; an approval waits for the user.
|
|
11805
|
+
* running tool group show their own progress; an approval waits for the user. With
|
|
11806
|
+
* `writingMessageId`, the answer it names decides, as if the messages after it were not there.
|
|
10843
11807
|
*/
|
|
10844
11808
|
this.working = computed(() => {
|
|
10845
11809
|
if (!this.streaming()) {
|
|
10846
11810
|
return false;
|
|
10847
11811
|
}
|
|
10848
|
-
const
|
|
10849
|
-
|
|
11812
|
+
const messages = this.messages();
|
|
11813
|
+
const last = this.answerBeingWritten() ?? messages[messages.length - 1];
|
|
11814
|
+
if (!last || last.role === 'user' || last.role === 'application' || last.parts.length === 0) {
|
|
10850
11815
|
return true;
|
|
10851
11816
|
}
|
|
10852
11817
|
const lastPart = last.parts[last.parts.length - 1];
|
|
@@ -10854,6 +11819,19 @@ class NhAssistantThreadComponent {
|
|
|
10854
11819
|
&& lastPart.status !== 'running'
|
|
10855
11820
|
&& lastPart.status !== 'awaiting-approval';
|
|
10856
11821
|
}, ...(ngDevMode ? [{ debugName: "working" }] : []));
|
|
11822
|
+
/**
|
|
11823
|
+
* The message in whose row the working indicator shows: the answer `writingMessageId` names.
|
|
11824
|
+
* `null` puts the indicator at the end of the thread.
|
|
11825
|
+
*/
|
|
11826
|
+
this.workingAfterId = computed(() => this.answerBeingWritten()?.id ?? null, ...(ngDevMode ? [{ debugName: "workingAfterId" }] : []));
|
|
11827
|
+
/** While a turn runs: the answer `writingMessageId` names, when `messages` holds it. */
|
|
11828
|
+
this.answerBeingWritten = computed(() => {
|
|
11829
|
+
const writingMessageId = this.writingMessageId();
|
|
11830
|
+
if (!this.streaming() || !writingMessageId) {
|
|
11831
|
+
return null;
|
|
11832
|
+
}
|
|
11833
|
+
return this.messages().find(message => message.id === writingMessageId) ?? null;
|
|
11834
|
+
}, ...(ngDevMode ? [{ debugName: "answerBeingWritten" }] : []));
|
|
10857
11835
|
/** Whole seconds since the running turn started. */
|
|
10858
11836
|
this.elapsedSeconds = computed(() => {
|
|
10859
11837
|
const startedAt = this.turnStartedAt();
|
|
@@ -10895,6 +11873,10 @@ class NhAssistantThreadComponent {
|
|
|
10895
11873
|
isTrigger(message) {
|
|
10896
11874
|
return message.role === 'user' && message.authorKind === 'trigger';
|
|
10897
11875
|
}
|
|
11876
|
+
/** True for a message the application posted into the conversation. */
|
|
11877
|
+
isApplication(message) {
|
|
11878
|
+
return message.role === 'application';
|
|
11879
|
+
}
|
|
10898
11880
|
/** True for an assistant message the agent's rules wrote without a model. */
|
|
10899
11881
|
isRule(message) {
|
|
10900
11882
|
return message.role === 'assistant' && message.authorKind === 'rule';
|
|
@@ -10939,7 +11921,7 @@ class NhAssistantThreadComponent {
|
|
|
10939
11921
|
}
|
|
10940
11922
|
}
|
|
10941
11923
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantThreadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10942
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantThreadComponent, isStandalone: true, selector: "nh-assistant-thread", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, markdown: { classPropertyName: "markdown", publicName: "markdown", isSignal: true, isRequired: false, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: false, transformFunction: null }, currentActorId: { classPropertyName: "currentActorId", publicName: "currentActorId", isSignal: true, isRequired: false, transformFunction: null }, canDecide: { classPropertyName: "canDecide", publicName: "canDecide", isSignal: true, isRequired: false, transformFunction: null }, decisionOwner: { classPropertyName: "decisionOwner", publicName: "decisionOwner", isSignal: true, isRequired: false, transformFunction: null }, approvalRights: { classPropertyName: "approvalRights", publicName: "approvalRights", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalDecision: "approvalDecision", approvalChoice: "approvalChoice", retryMessage: "retryMessage" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true, isSignal: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n }\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article\n class=\"message\"\n [attr.data-role]=\"message.role\"\n [attr.data-others]=\"isOthers(message) ? 'true' : null\"\n [attr.data-author]=\"isTrigger(message) ? 'trigger' : isRule(message) ? 'rule' : null\">\n @if (isTrigger(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.trigger' | translate }}</p>\n } @else if (isRule(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.rule' | translate }}</p>\n } @else if (isOthers(message)) {\n <p class=\"author\">{{ authorName(message) ?? ('nh-assistant.thread.participant' | translate) }}</p>\n } @else {\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n }\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if (message.role === 'assistant' && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('files') {\n <ul class=\"files\" [attr.aria-label]=\"'nh-assistant.thread.files' | translate\">\n @for (file of group.files; track $index) {\n <li class=\"file\">\n <nh-assistant-icon class=\"file-icon\" name=\"file\" />\n <span class=\"file-name\" [attr.title]=\"file.name\">{{ file.name }}</span>\n <span class=\"file-meta\">{{ 'nh-assistant.thread.file-meta' | translate: fileMeta(file) }}</span>\n </li>\n }\n </ul>\n }\n @case ('connection') {\n <nh-assistant-connection-required\n class=\"part\"\n [part]=\"group.part\"\n [canRetry]=\"!streaming()\"\n (retry)=\"retryAfterConnect(message)\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card\n class=\"part\"\n [approval]=\"group.part\"\n [deciding]=\"deciding()\"\n [canDecide]=\"rightFor(group.part).canDecide\"\n [decisionOwner]=\"rightFor(group.part).decisionOwner\"\n [waitingFor]=\"rightFor(group.part).waitingFor\"\n [canGiveFeedback]=\"rightFor(group.part).canGiveFeedback === true\"\n (decide)=\"choose(group.part, $event)\" />\n }\n }\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:20px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:600}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-others=true]{align-items:flex-start}.message[data-others=true] .bubble{color:var(--nha-text);background:var(--nha-surface-strong)}.message[data-author=trigger]{align-items:stretch}.message[data-author=trigger] .bubble{max-width:none;color:var(--nha-text-muted);background:transparent;border:1px dashed var(--nha-border)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{padding-inline:0;background:transparent}.part{width:100%}.files{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;max-width:88%;min-width:0;margin:0;padding:0;list-style:none}.message:not([data-role=user]) .files,.message[data-others=true] .files{justify-content:flex-start}.file{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 10px;color:var(--nha-text);background:var(--nha-surface);font-size:12px}.file-icon{flex-shrink:0;color:var(--nha-text-muted)}.file-name{min-width:0;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.file-meta{flex-shrink:0;color:var(--nha-text-muted);white-space:nowrap}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown hr{margin:12px 0;border:0;border-top:1px solid var(--nha-border)}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantToolCallGroupComponent, selector: "nh-assistant-tool-call-group", inputs: ["calls"] }, { kind: "component", type: NhAssistantApprovalCardComponent, selector: "nh-assistant-approval-card", inputs: ["approval", "deciding", "canDecide", "decisionOwner", "waitingFor", "canGiveFeedback"], outputs: ["decide"] }, { kind: "component", type: NhAssistantConnectionRequiredComponent, selector: "nh-assistant-connection-required", inputs: ["part", "canRetry"], outputs: ["retry"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantMarkdownPipe, name: "nhAssistantMarkdown" }, { kind: "pipe", type: NhAssistantPartGroupsPipe, name: "nhAssistantPartGroups" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11924
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantThreadComponent, isStandalone: true, selector: "nh-assistant-thread", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, markdown: { classPropertyName: "markdown", publicName: "markdown", isSignal: true, isRequired: false, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: false, transformFunction: null }, currentActorId: { classPropertyName: "currentActorId", publicName: "currentActorId", isSignal: true, isRequired: false, transformFunction: null }, canDecide: { classPropertyName: "canDecide", publicName: "canDecide", isSignal: true, isRequired: false, transformFunction: null }, decisionOwner: { classPropertyName: "decisionOwner", publicName: "decisionOwner", isSignal: true, isRequired: false, transformFunction: null }, approvalRights: { classPropertyName: "approvalRights", publicName: "approvalRights", isSignal: true, isRequired: false, transformFunction: null }, writingMessageId: { classPropertyName: "writingMessageId", publicName: "writingMessageId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalDecision: "approvalDecision", approvalChoice: "approvalChoice", retryMessage: "retryMessage" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true, isSignal: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n <!-- The answer a turn still writes (writingMessageId) keeps the indicator under it, also when messages arrived after it. -->\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article\n class=\"message\"\n [attr.data-role]=\"message.role\"\n [attr.data-others]=\"isOthers(message) ? 'true' : null\"\n [attr.data-author]=\"isTrigger(message) ? 'trigger' : isRule(message) ? 'rule' : isApplication(message) ? 'application' : null\"\n [attr.aria-label]=\"isApplication(message) ? ('nh-assistant.thread.application-label' | translate) : null\">\n @if (isTrigger(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.trigger' | translate }}</p>\n } @else if (isRule(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.rule' | translate }}</p>\n } @else if (isApplication(message)) {\n <!-- The application's message reads as the application's, also when it names who in the application posted it. -->\n <p class=\"author\">\n <nh-assistant-icon class=\"author-icon\" name=\"bell\" />\n @if (message.application?.senderName; as sender) {\n <!-- The space keeps the sender and the tag apart for screen readers; the flex gap shows it. -->\n <span>{{ sender }}</span>{{ ' ' }}<span class=\"tag\">{{ 'nh-assistant.thread.application' | translate }}</span>\n } @else {\n <span>{{ 'nh-assistant.thread.application' | translate }}</span>\n }\n @if (message.application?.trusted) {\n <!-- People see which of the application's messages the assistant follows as an instruction. -->\n {{ ' ' }}<span class=\"tag trusted\">{{ 'nh-assistant.thread.application-trusted' | translate }}</span>\n }\n </p>\n @if (message.application?.title; as title) {\n <p class=\"application-title\">{{ title }}</p>\n }\n } @else if (isOthers(message)) {\n <p class=\"author\">{{ authorName(message) ?? ('nh-assistant.thread.participant' | translate) }}</p>\n } @else {\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n }\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if ((message.role === 'assistant' || isApplication(message)) && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('files') {\n <ul class=\"files\" [attr.aria-label]=\"'nh-assistant.thread.files' | translate\">\n @for (file of group.files; track $index) {\n <li class=\"file\">\n <nh-assistant-icon class=\"file-icon\" name=\"file\" />\n <span class=\"file-name\" [attr.title]=\"file.name\">{{ file.name }}</span>\n <span class=\"file-meta\">{{ 'nh-assistant.thread.file-meta' | translate: fileMeta(file) }}</span>\n </li>\n }\n </ul>\n }\n @case ('connection') {\n <nh-assistant-connection-required\n class=\"part\"\n [part]=\"group.part\"\n [canRetry]=\"!streaming()\"\n (retry)=\"retryAfterConnect(message)\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card\n class=\"part\"\n [approval]=\"group.part\"\n [deciding]=\"deciding()\"\n [canDecide]=\"rightFor(group.part).canDecide\"\n [decisionOwner]=\"rightFor(group.part).decisionOwner\"\n [waitingFor]=\"rightFor(group.part).waitingFor\"\n [canGiveFeedback]=\"rightFor(group.part).canGiveFeedback === true\"\n (decide)=\"choose(group.part, $event)\" />\n }\n }\n }\n @if (isApplication(message) && message.application?.link; as link) {\n <nh-assistant-message-link\n class=\"application-link\"\n [url]=\"link.url\"\n [label]=\"link.label || ('nh-assistant.thread.application-link' | translate)\" />\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:20px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:600}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-others=true]{align-items:flex-start}.message[data-others=true] .bubble{color:var(--nha-text);background:var(--nha-surface-strong)}.message[data-author=trigger]{align-items:stretch}.message[data-author=trigger] .bubble{max-width:none;color:var(--nha-text-muted);background:transparent;border:1px dashed var(--nha-border)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{padding-inline:0;background:transparent}.part{width:100%}.files{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;max-width:88%;min-width:0;margin:0;padding:0;list-style:none}.message:not([data-role=user]) .files,.message[data-others=true] .files{justify-content:flex-start}.file{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 10px;color:var(--nha-text);background:var(--nha-surface);font-size:12px}.file-icon{flex-shrink:0;color:var(--nha-text-muted)}.file-name{min-width:0;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.file-meta{flex-shrink:0;color:var(--nha-text-muted);white-space:nowrap}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown hr{margin:12px 0;border:0;border-top:1px solid var(--nha-border)}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}.message[data-author=application]{align-items:stretch;border-left:3px solid var(--nha-accent);border-radius:var(--nha-radius-control);padding:8px 12px;background:var(--nha-surface-strong)}.message[data-author=application] .author{display:flex;align-items:center;gap:6px}.message[data-author=application] .author-icon{color:var(--nha-accent)}.message[data-author=application] .tag{border:1px solid var(--nha-border);border-radius:999px;padding:0 6px;color:var(--nha-text-muted);font-weight:500}.message[data-author=application] .application-title{margin:0;color:var(--nha-text);font-size:14px;font-weight:600}.message[data-author=application] .bubble{max-width:none;padding:0;color:var(--nha-text);background:transparent}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantMessageLinkComponent, selector: "nh-assistant-message-link", inputs: ["url", "label"] }, { kind: "component", type: NhAssistantToolCallGroupComponent, selector: "nh-assistant-tool-call-group", inputs: ["calls"] }, { kind: "component", type: NhAssistantApprovalCardComponent, selector: "nh-assistant-approval-card", inputs: ["approval", "deciding", "canDecide", "decisionOwner", "waitingFor", "canGiveFeedback"], outputs: ["decide"] }, { kind: "component", type: NhAssistantConnectionRequiredComponent, selector: "nh-assistant-connection-required", inputs: ["part", "canRetry"], outputs: ["retry"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantMarkdownPipe, name: "nhAssistantMarkdown" }, { kind: "pipe", type: NhAssistantPartGroupsPipe, name: "nhAssistantPartGroups" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10943
11925
|
}
|
|
10944
11926
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantThreadComponent, decorators: [{
|
|
10945
11927
|
type: Component,
|
|
@@ -10949,12 +11931,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10949
11931
|
TranslatePipe,
|
|
10950
11932
|
NhAssistantIconComponent,
|
|
10951
11933
|
NhAssistantMarkdownPipe,
|
|
11934
|
+
NhAssistantMessageLinkComponent,
|
|
10952
11935
|
NhAssistantPartGroupsPipe,
|
|
10953
11936
|
NhAssistantToolCallGroupComponent,
|
|
10954
11937
|
NhAssistantApprovalCardComponent,
|
|
10955
11938
|
NhAssistantConnectionRequiredComponent
|
|
10956
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n </div>\n }\n @if (working()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article\n class=\"message\"\n [attr.data-role]=\"message.role\"\n [attr.data-others]=\"isOthers(message) ? 'true' : null\"\n [attr.data-author]=\"isTrigger(message) ? 'trigger' : isRule(message) ? 'rule' : null\">\n @if (isTrigger(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.trigger' | translate }}</p>\n } @else if (isRule(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.rule' | translate }}</p>\n } @else if (isOthers(message)) {\n <p class=\"author\">{{ authorName(message) ?? ('nh-assistant.thread.participant' | translate) }}</p>\n } @else {\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n }\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if (message.role === 'assistant' && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('files') {\n <ul class=\"files\" [attr.aria-label]=\"'nh-assistant.thread.files' | translate\">\n @for (file of group.files; track $index) {\n <li class=\"file\">\n <nh-assistant-icon class=\"file-icon\" name=\"file\" />\n <span class=\"file-name\" [attr.title]=\"file.name\">{{ file.name }}</span>\n <span class=\"file-meta\">{{ 'nh-assistant.thread.file-meta' | translate: fileMeta(file) }}</span>\n </li>\n }\n </ul>\n }\n @case ('connection') {\n <nh-assistant-connection-required\n class=\"part\"\n [part]=\"group.part\"\n [canRetry]=\"!streaming()\"\n (retry)=\"retryAfterConnect(message)\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card\n class=\"part\"\n [approval]=\"group.part\"\n [deciding]=\"deciding()\"\n [canDecide]=\"rightFor(group.part).canDecide\"\n [decisionOwner]=\"rightFor(group.part).decisionOwner\"\n [waitingFor]=\"rightFor(group.part).waitingFor\"\n [canGiveFeedback]=\"rightFor(group.part).canGiveFeedback === true\"\n (decide)=\"choose(group.part, $event)\" />\n }\n }\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:20px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:600}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-others=true]{align-items:flex-start}.message[data-others=true] .bubble{color:var(--nha-text);background:var(--nha-surface-strong)}.message[data-author=trigger]{align-items:stretch}.message[data-author=trigger] .bubble{max-width:none;color:var(--nha-text-muted);background:transparent;border:1px dashed var(--nha-border)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{padding-inline:0;background:transparent}.part{width:100%}.files{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;max-width:88%;min-width:0;margin:0;padding:0;list-style:none}.message:not([data-role=user]) .files,.message[data-others=true] .files{justify-content:flex-start}.file{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 10px;color:var(--nha-text);background:var(--nha-surface);font-size:12px}.file-icon{flex-shrink:0;color:var(--nha-text-muted)}.file-name{min-width:0;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.file-meta{flex-shrink:0;color:var(--nha-text-muted);white-space:nowrap}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown hr{margin:12px 0;border:0;border-top:1px solid var(--nha-border)}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}\n"] }]
|
|
10957
|
-
}], ctorParameters: () => [], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], markdown: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdown", required: false }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: false }] }], currentActorId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentActorId", required: false }] }], canDecide: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDecide", required: false }] }], decisionOwner: [{ type: i0.Input, args: [{ isSignal: true, alias: "decisionOwner", required: false }] }], approvalRights: [{ type: i0.Input, args: [{ isSignal: true, alias: "approvalRights", required: false }] }], approvalDecision: [{ type: i0.Output, args: ["approvalDecision"] }], approvalChoice: [{ type: i0.Output, args: ["approvalChoice"] }], retryMessage: [{ type: i0.Output, args: ["retryMessage"] }], scroller: [{ type: i0.ViewChild, args: ['scroller', { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }] } });
|
|
11939
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n <!-- The answer a turn still writes (writingMessageId) keeps the indicator under it, also when messages arrived after it. -->\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article\n class=\"message\"\n [attr.data-role]=\"message.role\"\n [attr.data-others]=\"isOthers(message) ? 'true' : null\"\n [attr.data-author]=\"isTrigger(message) ? 'trigger' : isRule(message) ? 'rule' : isApplication(message) ? 'application' : null\"\n [attr.aria-label]=\"isApplication(message) ? ('nh-assistant.thread.application-label' | translate) : null\">\n @if (isTrigger(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.trigger' | translate }}</p>\n } @else if (isRule(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.rule' | translate }}</p>\n } @else if (isApplication(message)) {\n <!-- The application's message reads as the application's, also when it names who in the application posted it. -->\n <p class=\"author\">\n <nh-assistant-icon class=\"author-icon\" name=\"bell\" />\n @if (message.application?.senderName; as sender) {\n <!-- The space keeps the sender and the tag apart for screen readers; the flex gap shows it. -->\n <span>{{ sender }}</span>{{ ' ' }}<span class=\"tag\">{{ 'nh-assistant.thread.application' | translate }}</span>\n } @else {\n <span>{{ 'nh-assistant.thread.application' | translate }}</span>\n }\n @if (message.application?.trusted) {\n <!-- People see which of the application's messages the assistant follows as an instruction. -->\n {{ ' ' }}<span class=\"tag trusted\">{{ 'nh-assistant.thread.application-trusted' | translate }}</span>\n }\n </p>\n @if (message.application?.title; as title) {\n <p class=\"application-title\">{{ title }}</p>\n }\n } @else if (isOthers(message)) {\n <p class=\"author\">{{ authorName(message) ?? ('nh-assistant.thread.participant' | translate) }}</p>\n } @else {\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n }\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if ((message.role === 'assistant' || isApplication(message)) && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('files') {\n <ul class=\"files\" [attr.aria-label]=\"'nh-assistant.thread.files' | translate\">\n @for (file of group.files; track $index) {\n <li class=\"file\">\n <nh-assistant-icon class=\"file-icon\" name=\"file\" />\n <span class=\"file-name\" [attr.title]=\"file.name\">{{ file.name }}</span>\n <span class=\"file-meta\">{{ 'nh-assistant.thread.file-meta' | translate: fileMeta(file) }}</span>\n </li>\n }\n </ul>\n }\n @case ('connection') {\n <nh-assistant-connection-required\n class=\"part\"\n [part]=\"group.part\"\n [canRetry]=\"!streaming()\"\n (retry)=\"retryAfterConnect(message)\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card\n class=\"part\"\n [approval]=\"group.part\"\n [deciding]=\"deciding()\"\n [canDecide]=\"rightFor(group.part).canDecide\"\n [decisionOwner]=\"rightFor(group.part).decisionOwner\"\n [waitingFor]=\"rightFor(group.part).waitingFor\"\n [canGiveFeedback]=\"rightFor(group.part).canGiveFeedback === true\"\n (decide)=\"choose(group.part, $event)\" />\n }\n }\n }\n @if (isApplication(message) && message.application?.link; as link) {\n <nh-assistant-message-link\n class=\"application-link\"\n [url]=\"link.url\"\n [label]=\"link.label || ('nh-assistant.thread.application-link' | translate)\" />\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:20px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:600}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-others=true]{align-items:flex-start}.message[data-others=true] .bubble{color:var(--nha-text);background:var(--nha-surface-strong)}.message[data-author=trigger]{align-items:stretch}.message[data-author=trigger] .bubble{max-width:none;color:var(--nha-text-muted);background:transparent;border:1px dashed var(--nha-border)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{padding-inline:0;background:transparent}.part{width:100%}.files{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;max-width:88%;min-width:0;margin:0;padding:0;list-style:none}.message:not([data-role=user]) .files,.message[data-others=true] .files{justify-content:flex-start}.file{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 10px;color:var(--nha-text);background:var(--nha-surface);font-size:12px}.file-icon{flex-shrink:0;color:var(--nha-text-muted)}.file-name{min-width:0;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.file-meta{flex-shrink:0;color:var(--nha-text-muted);white-space:nowrap}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown hr{margin:12px 0;border:0;border-top:1px solid var(--nha-border)}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}.message[data-author=application]{align-items:stretch;border-left:3px solid var(--nha-accent);border-radius:var(--nha-radius-control);padding:8px 12px;background:var(--nha-surface-strong)}.message[data-author=application] .author{display:flex;align-items:center;gap:6px}.message[data-author=application] .author-icon{color:var(--nha-accent)}.message[data-author=application] .tag{border:1px solid var(--nha-border);border-radius:999px;padding:0 6px;color:var(--nha-text-muted);font-weight:500}.message[data-author=application] .application-title{margin:0;color:var(--nha-text);font-size:14px;font-weight:600}.message[data-author=application] .bubble{max-width:none;padding:0;color:var(--nha-text);background:transparent}\n"] }]
|
|
11940
|
+
}], ctorParameters: () => [], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], markdown: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdown", required: false }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: false }] }], currentActorId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentActorId", required: false }] }], canDecide: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDecide", required: false }] }], decisionOwner: [{ type: i0.Input, args: [{ isSignal: true, alias: "decisionOwner", required: false }] }], approvalRights: [{ type: i0.Input, args: [{ isSignal: true, alias: "approvalRights", required: false }] }], writingMessageId: [{ type: i0.Input, args: [{ isSignal: true, alias: "writingMessageId", required: false }] }], approvalDecision: [{ type: i0.Output, args: ["approvalDecision"] }], approvalChoice: [{ type: i0.Output, args: ["approvalChoice"] }], retryMessage: [{ type: i0.Output, args: ["retryMessage"] }], scroller: [{ type: i0.ViewChild, args: ['scroller', { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }] } });
|
|
10958
11941
|
|
|
10959
11942
|
let nextId$1 = 0;
|
|
10960
11943
|
/**
|
|
@@ -11179,7 +12162,7 @@ class NhAssistantPanelComponent {
|
|
|
11179
12162
|
void this.store.cancel();
|
|
11180
12163
|
}
|
|
11181
12164
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11182
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", 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 (retryMessage)=\"store.send($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.files?.length) {\n <span class=\"queue-state queue-files\" data-queue-files>{{ 'nh-assistant.queue.files' | translate: { count: item.files!.length, names: fileNames(item.files!) } }}</span>\n }\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 [uploads]=\"store.uploads()\"\n [attachments]=\"store.attachments()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (attach)=\"attach($event)\"\n (removeAttachment)=\"store.removeAttachment($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-files{display:block;overflow-wrap:anywhere}.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", "uploads", "attachments"], outputs: ["send", "cancel", "restored", "attach", "removeAttachment"] }, { 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", "retryMessage"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12165
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", 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 [writingMessageId]=\"store.writingMessageId()\"\n (approvalChoice)=\"decideApproval($event)\"\n (retryMessage)=\"store.send($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.files?.length) {\n <span class=\"queue-state queue-files\" data-queue-files>{{ 'nh-assistant.queue.files' | translate: { count: item.files!.length, names: fileNames(item.files!) } }}</span>\n }\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 [uploads]=\"store.uploads()\"\n [attachments]=\"store.attachments()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (attach)=\"attach($event)\"\n (removeAttachment)=\"store.removeAttachment($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-files{display:block;overflow-wrap:anywhere}.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", "uploads", "attachments"], outputs: ["send", "cancel", "restored", "attach", "removeAttachment"] }, { 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", "writingMessageId"], outputs: ["approvalDecision", "approvalChoice", "retryMessage"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11183
12166
|
}
|
|
11184
12167
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantPanelComponent, decorators: [{
|
|
11185
12168
|
type: Component,
|
|
@@ -11195,7 +12178,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
11195
12178
|
NhAssistantPreferencesComponent,
|
|
11196
12179
|
NhAssistantShareComponent,
|
|
11197
12180
|
NhAssistantThreadComponent
|
|
11198
|
-
], 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 (retryMessage)=\"store.send($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.files?.length) {\n <span class=\"queue-state queue-files\" data-queue-files>{{ 'nh-assistant.queue.files' | translate: { count: item.files!.length, names: fileNames(item.files!) } }}</span>\n }\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 [uploads]=\"store.uploads()\"\n [attachments]=\"store.attachments()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (attach)=\"attach($event)\"\n (removeAttachment)=\"store.removeAttachment($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-files{display:block;overflow-wrap:anywhere}.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"] }]
|
|
12181
|
+
], 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 [writingMessageId]=\"store.writingMessageId()\"\n (approvalChoice)=\"decideApproval($event)\"\n (retryMessage)=\"store.send($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.files?.length) {\n <span class=\"queue-state queue-files\" data-queue-files>{{ 'nh-assistant.queue.files' | translate: { count: item.files!.length, names: fileNames(item.files!) } }}</span>\n }\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 [uploads]=\"store.uploads()\"\n [attachments]=\"store.attachments()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (attach)=\"attach($event)\"\n (removeAttachment)=\"store.removeAttachment($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-files{display:block;overflow-wrap:anywhere}.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"] }]
|
|
11199
12182
|
}], ctorParameters: () => [], propDecorators: { drawer: [{ type: i0.ViewChild, args: ['drawer', { isSignal: true }] }] } });
|
|
11200
12183
|
|
|
11201
12184
|
/**
|
|
@@ -11520,102 +12503,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
11520
12503
|
args: [{ selector: 'nh-assistant-picker', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"picker\" [class.open]=\"open()\">\n <div class=\"control\">\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n aria-autocomplete=\"list\"\n [id]=\"inputId()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.aria-invalid]=\"invalid() ? true : null\"\n [attr.aria-describedby]=\"fieldDescribedBy()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [value]=\"inputText()\"\n (input)=\"onInput($event)\"\n (click)=\"openList()\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onBlur()\" />\n <button\n type=\"button\"\n class=\"toggle\"\n tabindex=\"-1\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.picker.toggle' | translate\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"toggle()\">\n <nh-assistant-icon name=\"chevron-down\" />\n </button>\n </div>\n @if (searchError(); as failure) {\n <!-- A failed search says why and offers to search again; the list never claims nothing was found. -->\n <p class=\"field-error search-error\" role=\"alert\" data-search-error [id]=\"searchErrorId\">\n <nh-assistant-icon name=\"warning\" />\n <span>{{ searchErrorKeys() | nhAssistantTranslate: failure.code }}</span>\n <button\n type=\"button\"\n class=\"link\"\n data-search-retry\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"retrySearch()\">{{ 'nh-assistant.picker.search-again' | translate }}</button>\n </p>\n }\n @if (open()) {\n <ul class=\"listbox\" role=\"listbox\" [id]=\"listId\">\n @for (option of visible(); track option.value; let index = $index) {\n <li\n role=\"option\"\n [id]=\"optionId(index)\"\n [class.active]=\"index === active()\"\n [attr.aria-selected]=\"option.value === (value() ?? '')\"\n (mousedown)=\"$event.preventDefault()\"\n (mousemove)=\"active.set(index)\"\n (click)=\"choose(option)\">\n <span class=\"label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"description\">{{ option.description }}</span>\n }\n </li>\n } @empty {\n <li class=\"state\" role=\"presentation\">{{ emptyKey() | translate }}</li>\n }\n </ul>\n } @else if (selected()?.description; as description) {\n <p class=\"chosen\">{{ description }}</p>\n }\n</div>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;min-width:0;color:var(--nha-text);font-family:var(--nha-font)}:host fieldset{min-width:0;margin:0;border:0;padding:0}:host legend,:host .label,:host .field>label{display:block;margin-bottom:6px;padding:0;color:var(--nha-text);font-size:12px;font-weight:700}:host input[type=text],:host input[type=url],:host input[type=password],:host input[type=search],:host input[type=email],:host input[type=number],:host input[type=date],:host input[type=time],:host input[type=datetime-local],:host select,:host textarea{box-sizing:border-box;width:100%;min-width:0;min-height:38px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:8px 10px;color:var(--nha-text);background:var(--nha-background);font:inherit;font-size:13px}:host input[type=text]:focus-visible,:host input[type=url]:focus-visible,:host input[type=password]:focus-visible,:host input[type=search]:focus-visible,:host input[type=email]:focus-visible,:host input[type=number]:focus-visible,:host input[type=date]:focus-visible,:host input[type=time]:focus-visible,:host input[type=datetime-local]:focus-visible,:host select:focus-visible,:host textarea:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host input[type=text]:disabled,:host input[type=url]:disabled,:host input[type=password]:disabled,:host input[type=search]:disabled,:host input[type=email]:disabled,:host input[type=number]:disabled,:host input[type=date]:disabled,:host input[type=time]:disabled,:host input[type=datetime-local]:disabled,:host select:disabled,:host textarea:disabled{cursor:not-allowed;opacity:.6}:host input[type=text][aria-invalid=true],:host input[type=url][aria-invalid=true],:host input[type=password][aria-invalid=true],:host input[type=search][aria-invalid=true],:host input[type=email][aria-invalid=true],:host input[type=number][aria-invalid=true],:host input[type=date][aria-invalid=true],:host input[type=time][aria-invalid=true],:host input[type=datetime-local][aria-invalid=true],:host select[aria-invalid=true],:host textarea[aria-invalid=true]{border-color:var(--nha-danger)}:host textarea{line-height:1.45;resize:vertical}:host input[type=number]{font-variant-numeric:tabular-nums}:host .mono{font-family:var(--nha-mono);font-size:12px}:host .field{display:flex;flex-direction:column;min-width:0}:host .hint{display:flex;justify-content:space-between;gap:8px;margin:4px 2px 0;color:var(--nha-text-muted);font-size:11px}:host .counter{flex:none;font-variant-numeric:tabular-nums}:host .error-text{color:var(--nha-danger)}:host .field-error{display:flex;align-items:flex-start;gap:6px;margin:4px 2px 0;color:var(--nha-danger);font-size:12px;font-weight:600;overflow-wrap:anywhere}:host .field-error nh-assistant-icon{flex:none;margin-top:1px}:host .form-error{box-sizing:border-box;display:flex;align-items:flex-start;gap:8px;margin:0;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:8px 12px;color:var(--nha-text);background:var(--nha-danger-soft);font-size:13px;overflow-wrap:anywhere}:host .form-error ul{margin:4px 0 0;padding-left:18px}:host .message{box-sizing:border-box;display:flex;align-items:center;gap:8px;margin:0;border:1px solid transparent;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:13px;overflow-wrap:anywhere}:host .message.error{border-color:var(--nha-danger);color:var(--nha-text);background:var(--nha-danger-soft)}:host .message.warning{border-color:var(--nha-warning);color:var(--nha-text);background:var(--nha-warning-soft)}:host .message.success{border-color:var(--nha-success);color:var(--nha-text);background:var(--nha-success-soft)}:host .message.info{border-color:var(--nha-border);color:var(--nha-text);background:var(--nha-surface)}:host .message nh-assistant-icon{flex:none}:host button.link{min-height:0;border:0;padding:0;color:var(--nha-accent, currentColor);background:none;font:inherit;text-decoration:underline;cursor:pointer}:host button.link:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host button.link:disabled{cursor:not-allowed;opacity:.55}:host .primary,:host .secondary,:host .danger{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;gap:6px;min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;white-space:nowrap;cursor:pointer}:host .primary:focus-visible,:host .secondary:focus-visible,:host .danger:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host .primary:disabled,:host .secondary:disabled,:host .danger:disabled{cursor:not-allowed;opacity:.55}:host .primary{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}:host .primary:hover:not(:disabled){filter:brightness(1.12)}:host .secondary{color:var(--nha-text);background:transparent}:host .secondary:hover:not(:disabled){background:var(--nha-surface-strong)}:host .danger{border-color:var(--nha-danger);color:var(--nha-danger);background:transparent}:host .danger:hover:not(:disabled){background:var(--nha-danger-soft)}:host .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}:host .icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host .icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}:host .icon-button:disabled{cursor:not-allowed;opacity:.5}:host .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}:host .badge{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:2px 8px;color:var(--nha-text-muted);background:var(--nha-surface-strong);font-size:11px;font-weight:700;white-space:nowrap}:host .badge.success{color:var(--nha-success);background:var(--nha-success-soft)}:host .badge.warning{color:var(--nha-warning);background:var(--nha-warning-soft)}:host .badge.danger{color:var(--nha-danger);background:var(--nha-danger-soft)}:host .visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.picker{position:relative;min-width:0}.control{position:relative}.control input{padding-right:36px;text-overflow:ellipsis}.toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);background:transparent;cursor:pointer;position:absolute;top:50%;right:4px;width:30px;height:30px;transform:translateY(-50%);color:var(--nha-text-muted)}.toggle:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.toggle:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.toggle:disabled{cursor:not-allowed;opacity:.5}.open .toggle{transform:translateY(-50%) rotate(180deg)}.listbox{position:absolute;z-index:30;top:calc(100% + 4px);right:0;left:0;max-height:280px;margin:0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px;background:var(--nha-background);box-shadow:0 12px 28px #0000002e;list-style:none}[role=option]{display:grid;gap:2px;border-radius:8px;padding:7px 10px;cursor:pointer;overflow-wrap:anywhere}[role=option].active{background:var(--nha-surface-strong)}[role=option][aria-selected=true] .label{font-weight:700}.label{font-size:13px}.description,.chosen{color:var(--nha-text-muted);font-size:12px;line-height:1.4}.chosen{margin:4px 2px 0;overflow-wrap:anywhere}.state{padding:8px 10px;color:var(--nha-text-muted);font-size:12px}.search-error{flex-wrap:wrap;align-items:baseline}.search-error span{flex:1 1 auto;min-width:0}\n"] }]
|
|
11521
12504
|
}], ctorParameters: () => [], propDecorators: { field: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], selectedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedLabel", required: false }] }], noneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "noneLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], search: [{ type: i0.Input, args: [{ isSignal: true, alias: "search", required: false }] }], minQueryLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minQueryLength", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], describedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "describedBy", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], optionChange: [{ type: i0.Output, args: ["optionChange"] }] } });
|
|
11522
12505
|
|
|
11523
|
-
/**
|
|
11524
|
-
* The name of a subject with the name of its type, linked to where the application shows the
|
|
11525
|
-
* subject (internal). The host's `subjectLinks` builder wins over the server's link; a link within
|
|
11526
|
-
* the application navigates through the router, an `https` link leaves it, and anything else shows
|
|
11527
|
-
* no link. Ctrl-, Cmd-, Shift- and middle-clicks keep the browser's behavior, such as a new tab.
|
|
11528
|
-
* A name that already says the type, as "The whole application" does for the application as a
|
|
11529
|
-
* whole, is shown once.
|
|
11530
|
-
*/
|
|
11531
|
-
class NhAssistantSubjectLinkComponent {
|
|
11532
|
-
constructor() {
|
|
11533
|
-
this.config = inject(NH_ASSISTANT_CONFIG, { optional: true });
|
|
11534
|
-
this.router = inject(Router, { optional: true });
|
|
11535
|
-
this.locationStrategy = inject(LocationStrategy, { optional: true });
|
|
11536
|
-
this.injector = inject(EnvironmentInjector);
|
|
11537
|
-
this.subjectType = input.required(...(ngDevMode ? [{ debugName: "subjectType" }] : []));
|
|
11538
|
-
this.subjectId = input.required(...(ngDevMode ? [{ debugName: "subjectId" }] : []));
|
|
11539
|
-
/** The text people read, usually the subject's display name. */
|
|
11540
|
-
this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
11541
|
-
/** The name of the subject type, such as "Project"; nothing is shown without one. */
|
|
11542
|
-
this.typeName = input(null, ...(ngDevMode ? [{ debugName: "typeName" }] : []));
|
|
11543
|
-
/** The server's link to the subject. */
|
|
11544
|
-
this.link = input(null, ...(ngDevMode ? [{ debugName: "link" }] : []));
|
|
11545
|
-
/** The type's name, unless the subject's name is the type's name itself, as for the whole application. */
|
|
11546
|
-
this.shownTypeName = computed(() => {
|
|
11547
|
-
const type = this.typeName()?.trim();
|
|
11548
|
-
if (!type) {
|
|
11549
|
-
return null;
|
|
11550
|
-
}
|
|
11551
|
-
return type.toLocaleLowerCase() === this.label().trim().toLocaleLowerCase() ? null : type;
|
|
11552
|
-
}, ...(ngDevMode ? [{ debugName: "shownTypeName" }] : []));
|
|
11553
|
-
this.target = computed(() => {
|
|
11554
|
-
const builder = this.config?.subjectLinks?.[this.subjectType()];
|
|
11555
|
-
const subject = { type: this.subjectType(), id: this.subjectId() };
|
|
11556
|
-
const custom = builder ? runInInjectionContext(this.injector, () => builder(subject)) : undefined;
|
|
11557
|
-
if (custom === null) {
|
|
11558
|
-
return null;
|
|
11559
|
-
}
|
|
11560
|
-
if (Array.isArray(custom)) {
|
|
11561
|
-
return this.routeTarget(this.router ? this.router.serializeUrl(this.router.createUrlTree([...custom])) : null);
|
|
11562
|
-
}
|
|
11563
|
-
return this.urlTarget(typeof custom === 'string' ? custom : this.link() ?? null);
|
|
11564
|
-
}, ...(ngDevMode ? [{ debugName: "target" }] : []));
|
|
11565
|
-
}
|
|
11566
|
-
open(event, target) {
|
|
11567
|
-
if (!target.route || !this.router || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
11568
|
-
return;
|
|
11569
|
-
}
|
|
11570
|
-
event.preventDefault();
|
|
11571
|
-
void this.router.navigateByUrl(target.route);
|
|
11572
|
-
}
|
|
11573
|
-
urlTarget(url) {
|
|
11574
|
-
if (!url) {
|
|
11575
|
-
return null;
|
|
11576
|
-
}
|
|
11577
|
-
if (url.startsWith('/') && !url.startsWith('//') && !url.startsWith('/\\')) {
|
|
11578
|
-
return this.routeTarget(url);
|
|
11579
|
-
}
|
|
11580
|
-
return /^https:\/\/[^/\\\s]+/i.test(url) ? { href: url, route: null } : null;
|
|
11581
|
-
}
|
|
11582
|
-
routeTarget(url) {
|
|
11583
|
-
if (!url) {
|
|
11584
|
-
return null;
|
|
11585
|
-
}
|
|
11586
|
-
return {
|
|
11587
|
-
href: this.locationStrategy ? this.locationStrategy.prepareExternalUrl(url) : url,
|
|
11588
|
-
route: this.router ? url : null
|
|
11589
|
-
};
|
|
11590
|
-
}
|
|
11591
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11592
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantSubjectLinkComponent, isStandalone: true, selector: "nh-assistant-subject-link", inputs: { subjectType: { classPropertyName: "subjectType", publicName: "subjectType", isSignal: true, isRequired: true, transformFunction: null }, subjectId: { classPropertyName: "subjectId", publicName: "subjectId", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, typeName: { classPropertyName: "typeName", publicName: "typeName", isSignal: true, isRequired: false, transformFunction: null }, link: { classPropertyName: "link", publicName: "link", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
11593
|
-
@if (shownTypeName(); as type) {
|
|
11594
|
-
<!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
|
|
11595
|
-
<span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
|
|
11596
|
-
}
|
|
11597
|
-
@if (target(); as link) {
|
|
11598
|
-
<a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
|
|
11599
|
-
} @else {
|
|
11600
|
-
<span class="nh-assistant-subject-name">{{ label() }}</span>
|
|
11601
|
-
}
|
|
11602
|
-
`, isInline: true, styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:.35em;min-width:0;overflow-wrap:anywhere}.nh-assistant-subject-type{color:var(--nha-text-muted);font-size:.85em;font-weight:500}a.nh-assistant-subject-name{border-radius:2px;color:inherit;text-decoration:underline;text-underline-offset:.15em}a.nh-assistant-subject-name:hover{color:var(--nha-accent)}a.nh-assistant-subject-name:focus-visible{outline:2px solid var(--nha-focus);outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11603
|
-
}
|
|
11604
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, decorators: [{
|
|
11605
|
-
type: Component,
|
|
11606
|
-
args: [{ selector: 'nh-assistant-subject-link', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
11607
|
-
@if (shownTypeName(); as type) {
|
|
11608
|
-
<!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
|
|
11609
|
-
<span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
|
|
11610
|
-
}
|
|
11611
|
-
@if (target(); as link) {
|
|
11612
|
-
<a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
|
|
11613
|
-
} @else {
|
|
11614
|
-
<span class="nh-assistant-subject-name">{{ label() }}</span>
|
|
11615
|
-
}
|
|
11616
|
-
`, styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:.35em;min-width:0;overflow-wrap:anywhere}.nh-assistant-subject-type{color:var(--nha-text-muted);font-size:.85em;font-weight:500}a.nh-assistant-subject-name{border-radius:2px;color:inherit;text-decoration:underline;text-underline-offset:.15em}a.nh-assistant-subject-name:hover{color:var(--nha-accent)}a.nh-assistant-subject-name:focus-visible{outline:2px solid var(--nha-focus);outline-offset:2px}\n"] }]
|
|
11617
|
-
}], propDecorators: { subjectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "subjectType", required: true }] }], subjectId: [{ type: i0.Input, args: [{ isSignal: true, alias: "subjectId", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], typeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeName", required: false }] }], link: [{ type: i0.Input, args: [{ isSignal: true, alias: "link", required: false }] }] } });
|
|
11618
|
-
|
|
11619
12506
|
/*
|
|
11620
12507
|
* Public API surface of @newheap/platform-ai-chat.
|
|
11621
12508
|
*/
|
|
@@ -11624,5 +12511,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
11624
12511
|
* Generated bundle index. Do not edit.
|
|
11625
12512
|
*/
|
|
11626
12513
|
|
|
11627
|
-
export { NH_ASSISTANT_ACCESS_POLICY, NH_ASSISTANT_CONFIG, NH_ASSISTANT_CONVERSATION_FRAGMENT, NH_ASSISTANT_ERROR_CODES, NH_ASSISTANT_FEEDBACK_CATEGORIES, NH_ASSISTANT_FEEDBACK_GROUPS, NH_ASSISTANT_FETCH, NH_ASSISTANT_ICONS, NH_ASSISTANT_JOIN_FRAGMENT, NH_ASSISTANT_MAX_BULK_FEEDBACK, NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS, NH_ASSISTANT_MAX_FEEDBACK_TEXT, NH_ASSISTANT_MAX_PROPOSAL_LOOKUP, NH_ASSISTANT_MAX_SUBJECT_SUMMARY, NH_ASSISTANT_MCP_AUTHORIZATION_MESSAGE, NH_ASSISTANT_MCP_AUTHORIZATION_WINDOW, NH_ASSISTANT_MESSAGE_QUEUED_NOTICE_CODE, NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, NH_ASSISTANT_PAGE_CONTEXT_LIMITS, NH_ASSISTANT_PANEL_MOBILE_QUERY, NH_ASSISTANT_PANEL_WIDTH, NH_ASSISTANT_RESULT_PREVIEW_LENGTH, NH_ASSISTANT_RUN_HISTORY_MAX_PAGE, NH_ASSISTANT_RUN_RESULT_MAX_LENGTH, NH_ASSISTANT_SERVER_ERROR_CODES, NH_ASSISTANT_SSE_EVENT_TYPES, NH_ASSISTANT_SUBJECT_SEARCH, NH_ASSISTANT_SYSTEM_GLOBAL_ID, NH_ASSISTANT_SYSTEM_SUBJECT_TYPE, NH_ASSISTANT_TRANSLATIONS, NH_ASSISTANT_UPLOAD, NH_ASSISTANT_UPLOAD_HEADER, NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD, NhAssistantActivityComponent, NhAssistantAdminApiService, NhAssistantAgentPickerComponent, NhAssistantAgentRunApiService, NhAssistantAllowAllAccessPolicy, NhAssistantApiError, NhAssistantApiService, NhAssistantApprovalCardComponent, NhAssistantClientErrorCodes, NhAssistantComposerComponent, NhAssistantConnectionRequiredComponent, NhAssistantConversationListComponent, NhAssistantLauncherComponent, NhAssistantLiveService, NhAssistantMcpConnectService, NhAssistantMcpConnectionsComponent, NhAssistantMcpPopupAuthorizationWindow, NhAssistantPanelComponent, NhAssistantPanelService, NhAssistantPreferencesComponent, NhAssistantProposalFeedbackComponent, NhAssistantPushService, NhAssistantShareComponent, NhAssistantSseParser, NhAssistantStore, NhAssistantSubjectBadgeComponent, NhAssistantSubjectSummaryService, NhAssistantThreadComponent, NhAssistantToolCallCardComponent, NhAssistantToolCallGroupComponent, NhAssistantTranslationMerger, applyNhAssistantApprovalDecision, applyNhAssistantConversationChange, applyNhAssistantEvent, applyNhAssistantLiveEvent, describeNhAssistantClientContext, formatNhAssistantCountdown, nhAssistantCodeForStatus, nhAssistantConnectMcp, nhAssistantErrorMessageKey, nhAssistantIsUnread, nhAssistantLatestTurnHasText, nhAssistantMcpAuthorizationFromFragment, nhAssistantShareLink, nhAssistantXhrUpload, normalizeNhAssistantClientContext, provideNhAssistant, toNhAssistantError, NH_ASSISTANT_DASH_CASE as ɵNH_ASSISTANT_DASH_CASE, NhAssistantIconComponent as ɵNhAssistantIconComponent, NhAssistantMarkdownPipe as ɵNhAssistantMarkdownPipe, NhAssistantPickerComponent as ɵNhAssistantPickerComponent, NhAssistantSubjectLinkComponent as ɵNhAssistantSubjectLinkComponent, NhAssistantTranslatePipe as ɵNhAssistantTranslatePipe, nhAssistantCodeKeys as ɵnhAssistantCodeKeys, nhAssistantErrorKeys as ɵnhAssistantErrorKeys, nhAssistantErrorOf as ɵnhAssistantErrorOf, nhAssistantReloadOnAgentWork as ɵnhAssistantReloadOnAgentWork, nhAssistantWatchAgentWork as ɵnhAssistantWatchAgentWork, toNhAssistantError as ɵtoNhAssistantError };
|
|
12514
|
+
export { NH_ASSISTANT_ACCESS_POLICY, NH_ASSISTANT_CONFIG, NH_ASSISTANT_CONVERSATION_FRAGMENT, NH_ASSISTANT_ERROR_CODES, NH_ASSISTANT_FEEDBACK_CATEGORIES, NH_ASSISTANT_FEEDBACK_GROUPS, NH_ASSISTANT_FETCH, NH_ASSISTANT_ICONS, NH_ASSISTANT_JOIN_FRAGMENT, NH_ASSISTANT_MAX_BULK_FEEDBACK, NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS, NH_ASSISTANT_MAX_FEEDBACK_TEXT, NH_ASSISTANT_MAX_PROPOSAL_LOOKUP, NH_ASSISTANT_MAX_SUBJECT_SUMMARY, NH_ASSISTANT_MCP_AUTHORIZATION_MESSAGE, NH_ASSISTANT_MCP_AUTHORIZATION_WINDOW, NH_ASSISTANT_MESSAGE_QUEUED_NOTICE_CODE, NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, NH_ASSISTANT_PAGE_CONTEXT_LIMITS, NH_ASSISTANT_PANEL_MOBILE_QUERY, NH_ASSISTANT_PANEL_WIDTH, NH_ASSISTANT_RESULT_PREVIEW_LENGTH, NH_ASSISTANT_RUN_HISTORY_MAX_PAGE, NH_ASSISTANT_RUN_RESULT_MAX_LENGTH, NH_ASSISTANT_SERVER_ERROR_CODES, NH_ASSISTANT_SSE_EVENT_TYPES, NH_ASSISTANT_SUBJECT_SEARCH, NH_ASSISTANT_SYSTEM_GLOBAL_ID, NH_ASSISTANT_SYSTEM_SUBJECT_TYPE, NH_ASSISTANT_TRANSLATIONS, NH_ASSISTANT_UPLOAD, NH_ASSISTANT_UPLOAD_HEADER, NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD, NhAssistantActivityComponent, NhAssistantAdminApiService, NhAssistantAgentPickerComponent, NhAssistantAgentRunApiService, NhAssistantAllowAllAccessPolicy, NhAssistantApiError, NhAssistantApiService, NhAssistantApprovalCardComponent, NhAssistantClientErrorCodes, NhAssistantComposerComponent, NhAssistantConnectionRequiredComponent, NhAssistantConversationListComponent, NhAssistantLauncherComponent, NhAssistantLiveService, NhAssistantMcpConnectService, NhAssistantMcpConnectionsComponent, NhAssistantMcpPopupAuthorizationWindow, NhAssistantPanelComponent, NhAssistantPanelService, NhAssistantPreferencesComponent, NhAssistantProposalFeedbackComponent, NhAssistantPushService, NhAssistantShareComponent, NhAssistantSseParser, NhAssistantStore, NhAssistantSubjectBadgeComponent, NhAssistantSubjectSummaryService, NhAssistantThreadComponent, NhAssistantToolCallCardComponent, NhAssistantToolCallGroupComponent, NhAssistantTranslationMerger, applyNhAssistantApprovalDecision, applyNhAssistantConversationChange, applyNhAssistantEvent, applyNhAssistantLiveEvent, describeNhAssistantClientContext, formatNhAssistantCountdown, nhAssistantCodeForStatus, nhAssistantConnectMcp, nhAssistantErrorMessageKey, nhAssistantIsUnread, nhAssistantLatestTurnHasText, nhAssistantMcpAuthorizationFromFragment, nhAssistantShareLink, nhAssistantXhrUpload, normalizeNhAssistantClientContext, provideNhAssistant, toNhAssistantError, NH_ASSISTANT_DASH_CASE as ɵNH_ASSISTANT_DASH_CASE, NhAssistantIconComponent as ɵNhAssistantIconComponent, NhAssistantMarkdownPipe as ɵNhAssistantMarkdownPipe, NhAssistantPickerComponent as ɵNhAssistantPickerComponent, NhAssistantSubjectLinkComponent as ɵNhAssistantSubjectLinkComponent, NhAssistantTranslatePipe as ɵNhAssistantTranslatePipe, nhAssistantCodeKeys as ɵnhAssistantCodeKeys, nhAssistantErrorKeys as ɵnhAssistantErrorKeys, nhAssistantErrorOf as ɵnhAssistantErrorOf, nhAssistantMediaTypeOf as ɵnhAssistantMediaTypeOf, nhAssistantReloadOnAgentWork as ɵnhAssistantReloadOnAgentWork, nhAssistantWatchAgentWork as ɵnhAssistantWatchAgentWork, toNhAssistantError as ɵtoNhAssistantError };
|
|
11628
12515
|
//# sourceMappingURL=newheap-platform-ai-chat.mjs.map
|