@newheap/platform-ai-chat 0.17.0 → 0.19.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.
@@ -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, NgTemplateOutlet, LocationStrategy } from '@angular/common';
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';
@@ -94,6 +94,38 @@ const NH_ASSISTANT_MAX_FEEDBACK_TEXT = 1_000;
94
94
  /** Maximum number of proposals one `POST approvals/feedback` request accepts. */
95
95
  const NH_ASSISTANT_MAX_BULK_FEEDBACK = 50;
96
96
 
97
+ /** The `format` of every agent package. */
98
+ const NH_ASSISTANT_AGENT_PACKAGE_FORMAT = 'newheap.assistant.agent-package';
99
+ /** The format version this library reads and writes; a newer one is refused. */
100
+ const NH_ASSISTANT_AGENT_PACKAGE_FORMAT_VERSION = 1;
101
+ /** The largest package in bytes of its UTF-8 JSON: 1 MB (`assistant-package-too-large` above). */
102
+ const NH_ASSISTANT_AGENT_PACKAGE_MAX_BYTES = 1_048_576;
103
+ /** The most agents of one package. */
104
+ const NH_ASSISTANT_AGENT_PACKAGE_MAX_AGENTS = 20;
105
+ /** The lock of a whole part, instead of a list of its fields. */
106
+ const NH_ASSISTANT_PACKAGE_LOCK_ALL = '*';
107
+ /**
108
+ * The fields a package may lock per part kind (`NhAssistantPackageLockFields`). A save that changes a
109
+ * locked field is refused with the field error `{field}: locked`, named as here; `worksOn`,
110
+ * `dailyBudget`, `files` and `limits` each stand for the fields the forms show together. An agent in
111
+ * code carries only the first six fields of `agent`.
112
+ */
113
+ const NH_ASSISTANT_PACKAGE_LOCK_FIELDS = {
114
+ agent: ['displayName', 'description', 'instructions', 'toolSelectors', 'requiredPolicy', 'autonomy', 'offeredInChat', 'worksOn', 'profile', 'dataClassification'],
115
+ runSettings: [
116
+ 'accountability', 'delegateFromInitiator', 'allowGatewayReads', 'elevatedReads', 'approvalPolicy', 'retryCount', 'dailyBudget',
117
+ 'maxConcurrentRuns', 'maxRunsPerSubjectPerDay', 'maxTokensPerRun', 'triageProfile', 'ruleHandler', 'files'
118
+ ],
119
+ skill: ['description', 'instructions', 'tools', 'profile', 'ruleHandler', 'maxTokensPerRun', 'dailyBudget', 'approvalPolicy', 'dataClassification', 'files'],
120
+ trigger: ['skill', 'source', 'event', 'filters', 'cron', 'timeZone', 'subjectSet', 'message', 'conflict', 'debounceSeconds'],
121
+ consultation: [
122
+ 'description', 'instructions', 'minimumRole', 'askerPolicy', 'routes', 'proposalRole', 'proposalPolicy', 'toolSelectors', 'limits',
123
+ 'allowRequests', 'exposeToMcp', 'dataClassification'
124
+ ],
125
+ handOff: ['sources', 'description', 'notifySource', 'maxPerSubjectPerDay'],
126
+ metadata: ['value']
127
+ };
128
+
97
129
  const NH_ASSISTANT_CONFIG = new InjectionToken('NH_ASSISTANT_CONFIG');
98
130
  const NH_ASSISTANT_ACCESS_POLICY = new InjectionToken('NH_ASSISTANT_ACCESS_POLICY');
99
131
  /**
@@ -236,7 +268,11 @@ var en = {
236
268
  trigger: "Event",
237
269
  rule: "Automatic rule",
238
270
  files: "Attached files",
239
- "file-meta": "{{type}}, {{size}}"
271
+ "file-meta": "{{type}}, {{size}}",
272
+ application: "Application",
273
+ "application-label": "Message from the application",
274
+ "application-link": "Open",
275
+ "application-trusted": "Instruction for the assistant"
240
276
  },
241
277
  composer: {
242
278
  label: "Message",
@@ -344,6 +380,7 @@ var en = {
344
380
  withdrawn: "Withdrawn",
345
381
  stale: "Outdated",
346
382
  executing: "Running",
383
+ "awaiting-application": "With the application",
347
384
  executed: "Done",
348
385
  "execution-failed": "Failed",
349
386
  "execution-unknown": "Outcome unknown",
@@ -354,6 +391,7 @@ var en = {
354
391
  "waiting-for-participant": "Waiting for the participant who started this task to decide.",
355
392
  "waiting-for-approver": "Waiting for an approver to decide.",
356
393
  "waiting-for-other-approver": "You started this work, so another approver decides.",
394
+ "waiting-for-asker": "Waiting for the person who asked to decide in their own chat.",
357
395
  "give-feedback": "What was wrong?",
358
396
  "stale-kind": {
359
397
  "already-done": "Already done",
@@ -361,7 +399,20 @@ var en = {
361
399
  "not-applicable": "No longer needed"
362
400
  },
363
401
  rationale: "Why: {{rationale}}",
364
- superseded: "Replaced by a newer proposal"
402
+ superseded: "Replaced by a newer proposal",
403
+ consultation: {
404
+ origin: "{{agent}} proposes this, about {{subject}}",
405
+ answer: "Answer of {{agent}}",
406
+ "own-rights": "Approving runs it right away with your own rights.",
407
+ leave: "Leave for approvers",
408
+ "leave-label": "Leave for approvers: {{summary}}",
409
+ "leave-explain": {
410
+ "subject-agent-rights": "The approvers of {{subject}} decide; it then runs with the agent's own rights.",
411
+ "subject-asker-rights": "The approvers of {{subject}} decide; it then runs with your rights."
412
+ },
413
+ "moved-status": "Left for approvers",
414
+ moved: "It now waits for the approvers of {{subject}}."
415
+ }
365
416
  },
366
417
  "proposal-feedback": {
367
418
  legend: "What was wrong? (optional)",
@@ -569,6 +620,11 @@ var en = {
569
620
  "assistant-consult-timeout": "The agent did not answer in time.",
570
621
  "assistant-consult-failed": "The agent could not answer.",
571
622
  "assistant-consult-read-only": "A consultation cannot change anything.",
623
+ "assistant-consult-tool-not-selected": "This consultation does not offer that tool, so nothing ran.",
624
+ "assistant-consult-proposal-refused": "No route at the subject takes this proposal any more. Approve or reject it here.",
625
+ "assistant-consult-asker-decides": "The person who asked decides this proposal in their own chat.",
626
+ "assistant-consult-route-not-allowed": "None of the agent's consultations allows this route, so it cannot be switched on.",
627
+ "assistant-consult-proposal-moved": "The proposal was left for the subject's approvers.",
572
628
  "assistant-moved-to-shadow": "The work went to the agent's shadow thread, where a run in shadow takes it.",
573
629
  "assistant-shadow-variant": "A shadow variant always works in shadow.",
574
630
  "assistant-service-account-not-used": "This agent does not answer to a technical account.",
@@ -577,10 +633,11 @@ var en = {
577
633
  "assistant-trigger-in-code": "This trigger is part of the code and cannot change here.",
578
634
  "assistant-trigger-filter-not-found": "The event has no filter with this name. Choose from the filters the event offers.",
579
635
  "assistant-skill-in-use": "A trigger still starts this skill. Change or remove the trigger first.",
580
- "assistant-configuration-limit": "This agent already has as many skills or triggers as allowed.",
636
+ "assistant-configuration-limit": "This agent already has as many skills, triggers or consultations as allowed.",
581
637
  "assistant-run-settings-in-code": "This agent is part of the code; its runs are configured there.",
582
- "assistant-run-settings-in-use": "Skills or triggers still belong to this agent. Remove them first.",
638
+ "assistant-run-settings-in-use": "Skills, triggers, consultations or hand-offs still belong to this agent. Remove them first.",
583
639
  "assistant-skill-candidate-not-found": "This skill has no version being evaluated in shadow.",
640
+ "assistant-trigger-candidate-not-found": "This trigger has no version being evaluated in shadow.",
584
641
  "assistant-skill-version-gone": "The skill version this run was for is no longer evaluated.",
585
642
  "assistant-account-search-unavailable": "The application offers no account search; enter the account's id.",
586
643
  "assistant-mcp-connection-required": "This server needs a connection first. Connect it and try again.",
@@ -607,7 +664,24 @@ var en = {
607
664
  "assistant-file-type-not-accepted": "This type of file cannot be attached.",
608
665
  "assistant-file-upload-refused": "The application refused this file.",
609
666
  "assistant-file-upload-failed": "The file could not be stored right now. Try again in a moment.",
610
- "assistant-file-scan-refused": "The file did not pass the scan for harmful content and was not stored."
667
+ "assistant-file-scan-refused": "The file did not pass the scan for harmful content and was not stored.",
668
+ "assistant-consultation-in-code": "The agent allows consultation about this kind of object in code; it cannot change here.",
669
+ "assistant-consultation-not-found": "The consultation was not found.",
670
+ "assistant-consultations-not-allowed": "The application does not let administrators add consultations to this agent.",
671
+ "assistant-handoffs-not-allowed": "The application does not let administrators connect agents to this one.",
672
+ "assistant-handoff-in-code": "The agent accepts hand-offs about this kind of object in code; it cannot change here.",
673
+ "assistant-handoff-not-found": "The hand-off was not found.",
674
+ "assistant-shadow-variants-not-allowed": "The application does not let administrators create shadow variants of this agent.",
675
+ "assistant-metadata-entry-not-found": "The application does not register this field of agents.",
676
+ "assistant-metadata-read-only": "The application sets this field of the agent in its code; it cannot change here.",
677
+ "assistant-instructions-asset-not-found": "The application has no such text asset in this version.",
678
+ "assistant-instructions-asset-unavailable": "The application's text assets cannot be read right now. Nothing was saved; try again shortly.",
679
+ "assistant-agent-instructions-unavailable": "This agent cannot work right now: the application's text with its instructions is not available. An administrator checks the agent.",
680
+ "assistant-package-format-unsupported": "This is no agent package this version can read: its format, format version or a property is unknown.",
681
+ "assistant-package-locked": "An agent package locks this. Unlink it from the package first.",
682
+ "assistant-package-too-large": "An agent package is at most 1 MB and holds at most 20 agents.",
683
+ "assistant-package-refused": "The check refused parts of the package, so nothing was imported. Check the package again to see which.",
684
+ "assistant-package-not-linked": "This agent, or this part of it, is not linked to an agent package."
611
685
  },
612
686
  notices: {
613
687
  "no-answer": "The assistant finished without an answer. Try again or rephrase your question.",
@@ -765,6 +839,8 @@ var en = {
765
839
  changed: "Changed by {{user}} on {{date}}.",
766
840
  reason: "Note: {{reason}}",
767
841
  waiting: "{{count}} events wait for the resume.",
842
+ "stopped-was-off-hint": "It was off when it stopped: releasing the kill switch switches it back off. Resume switches it on.",
843
+ "stopped-was-on-hint": "It was not off when it stopped: releasing the kill switch makes it work again, as Resume does.",
768
844
  action: {
769
845
  active: "Resume",
770
846
  paused: "Pause",
@@ -852,6 +928,44 @@ var en = {
852
928
  },
853
929
  "input-label-search": "Account"
854
930
  },
931
+ "consultation-routes": {
932
+ title: "Consultation routes",
933
+ 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.",
934
+ "load-failed": "The consultation routes could not be read.",
935
+ route: {
936
+ "asker-decides": "The person who asked decides",
937
+ "subject-agent-rights": "Approvers decide, agent's rights",
938
+ "subject-asker-rights": "Approvers decide, asker's rights"
939
+ },
940
+ explain: {
941
+ "asker-decides": "The person who asked decides in their own chat; it runs with their own rights.",
942
+ "subject-agent-rights": "The subject's approvers other than the person who asked decide; it runs with the agent's own rights.",
943
+ "subject-asker-rights": "The subject's approvers decide; it runs later with the rights of the person who asked."
944
+ },
945
+ on: "On",
946
+ off: "Off",
947
+ code: "As the consultations allow",
948
+ overridden: "Overridden",
949
+ "not-allowed": "Not allowed",
950
+ "not-allowed-hint": "No consultation of this agent allows this route, so it stays off and cannot be switched on.",
951
+ "subject-types": "For: {{types}}",
952
+ action: {
953
+ on: "Switch on",
954
+ off: "Switch off",
955
+ code: "Back to what the consultations allow"
956
+ },
957
+ "explain-change": {
958
+ on: "Consultations use this route for new proposals again. Proposals already recorded keep their route.",
959
+ 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.",
960
+ "code-on": "The consultations decide again: one of them allows this route, so it is on.",
961
+ "code-off": "The consultations decide again: none of them allows this route, so it stays off."
962
+ },
963
+ confirm: {
964
+ on: "Confirm switching on",
965
+ off: "Confirm switching off",
966
+ code: "Confirm"
967
+ }
968
+ },
855
969
  "run-config": "Run configuration",
856
970
  "run-now": "Run now",
857
971
  runs: "Runs",
@@ -889,7 +1003,7 @@ var en = {
889
1003
  instructions: "Instructions",
890
1004
  "instructions-hint": "What the agent does and how it answers.",
891
1005
  autonomy: "Autonomy",
892
- "autonomy-hint": "Only Execute allows changes, and every change still needs approval.",
1006
+ "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.",
893
1007
  "required-policy": "Required policy",
894
1008
  "required-policy-hint": "Optional. Only users who pass this policy see the agent.",
895
1009
  profile: "Model profile",
@@ -951,7 +1065,26 @@ var en = {
951
1065
  "in-code": "In this group in code",
952
1066
  "shadow-variant": "A shadow variant works for administrators only and joins no group."
953
1067
  },
954
- "catalog-unavailable": "The building blocks of agent runs could not be read, so what this agent works on and its groups cannot be changed now. Saving keeps them as they are."
1068
+ metadata: {
1069
+ title: "Application fields",
1070
+ hint: "The application keeps its own data about agents here. Each field has an editor of the application, which saves it on its own.",
1071
+ "save-first": "Save the agent first; then its fields appear here.",
1072
+ loading: "Loading the fields",
1073
+ "load-failed": "The fields of this agent could not be loaded.",
1074
+ "no-editor": "The application shows no editor for this field.",
1075
+ "read-only": "Set in the application's code; it cannot change here.",
1076
+ saved: "Saved.",
1077
+ removed: "Removed.",
1078
+ source: {
1079
+ code: "From code",
1080
+ override: "Changed here, over the value in code",
1081
+ data: "Stored with the agent",
1082
+ none: "No value"
1083
+ }
1084
+ },
1085
+ "catalog-unavailable": "The building blocks of agent runs could not be read, so what this agent works on and its groups cannot be changed now. Saving keeps them as they are.",
1086
+ "starts-in-shadow": "Start in shadow",
1087
+ "starts-in-shadow-hint": "Once it has run settings, its runs work in its shadow threads, where nobody is notified and nothing executes, until you put it live in the agent list."
955
1088
  },
956
1089
  effect: {
957
1090
  "read-only": "Read only",
@@ -1309,7 +1442,10 @@ var en = {
1309
1442
  agent: "Run settings:",
1310
1443
  skill: "Skill {{id}}:",
1311
1444
  candidate: "Candidate of skill {{id}}:",
1312
- trigger: "Trigger {{id}}:"
1445
+ trigger: "Trigger {{id}}:",
1446
+ consultation: "Consultation about {{id}}:",
1447
+ "hand-off": "Hand-off about {{id}}:",
1448
+ "trigger-candidate": "Candidate of trigger {{id}}:"
1313
1449
  },
1314
1450
  code: {
1315
1451
  "unknown-agent": "the agent can no longer run on its own.",
@@ -1325,7 +1461,29 @@ var en = {
1325
1461
  "unknown-skill": "the skill no longer exists.",
1326
1462
  "invalid-schedule": "the schedule or its time zone is not valid.",
1327
1463
  invalid: "a value is not valid.",
1328
- "not-worked-on": "it concerns a kind of object, or the whole application, that the agent does not work on."
1464
+ "not-worked-on": "it concerns a kind of object, or the whole application, that the agent does not work on.",
1465
+ "unknown-subject-type": "the kind of object no longer exists.",
1466
+ "unknown-agent-policy": "the policy the people who ask need is no longer listed.",
1467
+ "conflicts-with-tool": "another tool already has the name of its tool.",
1468
+ "not-consultable": "the application no longer lets administrators add consultations to this agent.",
1469
+ "route-not-allowed": "a route is no longer allowed, so it is left out.",
1470
+ "agent-answers-to-person": "the route with the agent's account is left out, because the agent answers to the object's responsible person.",
1471
+ "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.",
1472
+ "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.",
1473
+ "limit-above-ceiling": "a limit is above what the application allows, so the application's applies.",
1474
+ "requests-not-allowed": "the application no longer allows requests, so it takes none.",
1475
+ "mcp-not-allowed": "the application no longer offers consultations to MCP clients, so they do not see it.",
1476
+ "tools-not-allowed": "a chosen tool is no longer among the agent's own tools, so it is left out; with none left the agent gets no tools in it.",
1477
+ "no-asset-source": "its instructions come from the application's text assets, which the application no longer offers.",
1478
+ "asset-missing": "the application no longer has the text asset with its instructions in this version.",
1479
+ "asset-changed": "the text of the asset with its instructions changed since it was saved, so it is not used. Read the asset again and save it as the next version.",
1480
+ "asset-invalid": "the application's text asset cannot be used as instructions.",
1481
+ "asset-unavailable": "the application's text assets could not be read; they are read again shortly.",
1482
+ "outside-ceiling": "the application no longer allows it.",
1483
+ "unknown-source": "an agent that may hand off can no longer run on its own.",
1484
+ "unknown-live-agent": "the agent this shadow variant follows can no longer run on its own.",
1485
+ "live-agent-not-live": "the agent this shadow variant follows is no live agent.",
1486
+ "too-many-variants": "the agent it follows has more shadow variants than the application allows."
1329
1487
  }
1330
1488
  },
1331
1489
  "field-errors": {
@@ -1342,7 +1500,11 @@ var en = {
1342
1500
  "instructions-for-model": "Without fixed rules the model works from these instructions; describe what it should do.",
1343
1501
  "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.",
1344
1502
  "megabytes-up-to": "Enter a size above 0 and at most {{max}} MB.",
1345
- "megabytes-positive": "Enter a size above 0 MB."
1503
+ "megabytes-positive": "Enter a size above 0 MB.",
1504
+ "not-allowed": "The application does not allow this.",
1505
+ "routes-required": "Choose at least one route, or let it only answer.",
1506
+ "tools-not-allowed": "A chosen tool is outside the agent's own tools. Clear it, or add the tool to the agent first.",
1507
+ locked: "An agent package locks this field. Unlink the part first to change it."
1346
1508
  },
1347
1509
  settings: {
1348
1510
  title: "Run settings",
@@ -1585,6 +1747,24 @@ var en = {
1585
1747
  "set-hint": "One run each time for every object in a set, such as the active projects.",
1586
1748
  "every-division": "Every division",
1587
1749
  dropped: "This schedule ran for the whole application, which the agent no longer works on. Choose a set of objects."
1750
+ },
1751
+ "saved-candidate": "The new version fires in shadow next to the live version, which keeps working.",
1752
+ apply: "How the change takes effect",
1753
+ "apply-live": "Apply at once",
1754
+ "apply-live-hint": "The new version replaces the live one at once, in the mode the trigger has.",
1755
+ "apply-shadow": "Evaluate in shadow next to the live version first",
1756
+ "apply-shadow-hint": "The new version fires next to the live one into the agent's shadow threads, where nothing executes; compare them, then promote or discard it.",
1757
+ versions: "Versions",
1758
+ candidate: {
1759
+ explain: "Version {{version}} fires in shadow next to the live version: its runs work in the agent's shadow threads, and the live version keeps working.",
1760
+ "out-of-effect": "The candidate does not fire: it no longer fits the code ({{problem}}). The live version keeps working.",
1761
+ changes: "What the candidate changes",
1762
+ "no-changes": "The candidate has the same definition as the live version.",
1763
+ change: "{{candidate}} (live: {{live}})",
1764
+ comparison: "Live version and candidate of trigger {{trigger}}",
1765
+ paired: "Since {{date}} both started a run on {{count}} of the same events, only the live version on {{liveOnly}} and only the candidate on {{candidateOnly}}.",
1766
+ promoted: "The candidate is the live version of the trigger now.",
1767
+ none: "none"
1588
1768
  }
1589
1769
  },
1590
1770
  "way-of-working": "Way of working",
@@ -1720,7 +1900,14 @@ var en = {
1720
1900
  "configured-off": "Run now: not while the application's code switches the agent off.",
1721
1901
  "no-settings": "Run now: only once the agent has run settings.",
1722
1902
  "no-catalog": "Run now: not until the run catalog can be read."
1723
- }
1903
+ },
1904
+ consultations: "When another assistant consults it",
1905
+ "no-consultations": "No other assistant can consult it yet.",
1906
+ "consultation-proposes": "Answers and proposes",
1907
+ "consultation-answers": "Only answers",
1908
+ "asked-by-none": "No agent asks it yet",
1909
+ "asked-by-one": "Asked by 1 agent",
1910
+ "asked-by": "Asked by {{count}} agents"
1724
1911
  },
1725
1912
  skills: {
1726
1913
  "code-rules": "Fixed rules in the application's code",
@@ -1803,8 +1990,235 @@ var en = {
1803
1990
  "edit-trigger": "Change the trigger",
1804
1991
  "edit-skill": "Change the skill",
1805
1992
  "edit-trigger-named": "Edit trigger {{trigger}}",
1806
- "edit-skill-named": "Edit skill {{skill}}"
1993
+ "edit-skill-named": "Edit skill {{skill}}",
1994
+ "edit-consultation": "Change the consultation",
1995
+ "edit-consultation-named": "Edit the consultation about {{type}}"
1807
1996
  }
1997
+ },
1998
+ consultations: {
1999
+ title: "Consultations",
2000
+ 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.",
2001
+ add: "Add consultation",
2002
+ empty: "Nobody can consult this agent yet.",
2003
+ closed: {
2004
+ application: "The application does not let administrators add consultations; they come from its code.",
2005
+ agent: "This agent is defined in code and does not let administrators add consultations to it.",
2006
+ "needs-settings": "Give the agent run settings before you add consultations.",
2007
+ limit: "This agent has as many consultations as allowed ({{max}}).",
2008
+ "no-types": "Every kind of object this agent works on already has a consultation."
2009
+ },
2010
+ requests: "Takes requests",
2011
+ mcp: "Offered to MCP clients",
2012
+ "no-description": "No description.",
2013
+ askers: "Asked by:",
2014
+ "open-asker": "Open the editor of {{agent}}",
2015
+ "no-askers": "No agent asks it yet. Select its tool in the tools of an agent that should ask it.",
2016
+ "code-hint": "Allowed in code; here only the route switches below change it.",
2017
+ "limits-value": "At most {{calls}} tool calls, {{seconds}} seconds, {{chars}} characters and {{history}} thread messages",
2018
+ "tools-label": "Tools:",
2019
+ "tools-all": "every tool of the agent",
2020
+ "tools-none": "none, because no chosen tool is among the agent's own tools any more",
2021
+ "edit-named": "Edit the consultation about {{type}}",
2022
+ "remove-named": "Delete the consultation about {{type}}",
2023
+ "remove-explain": "Its tools disappear; proposals it made can still be decided.",
2024
+ added: "The consultation was added. It answers once an agent that asks selects its tool.",
2025
+ saved: "The consultation was saved.",
2026
+ removed: "The consultation was removed.",
2027
+ roles: {
2028
+ reader: "Reader",
2029
+ participant: "Participant",
2030
+ approver: "Approver"
2031
+ },
2032
+ "roles-lower": {
2033
+ reader: "reader",
2034
+ participant: "participant",
2035
+ approver: "approver"
2036
+ },
2037
+ summary: {
2038
+ ask: "People who are at least {{role}} of the object may ask.",
2039
+ "asker-policy": "They also need {{policy}}.",
2040
+ "asker-policy-agent": "They also need the policy the agent requires, or else access to the assistant.",
2041
+ "read-only": "The agent only answers and proposes nothing.",
2042
+ proposes: "The agent may propose changes when the person who asked is at least {{role}}: {{routes}}.",
2043
+ "proposes-code": "The agent may propose changes: {{routes}}."
2044
+ },
2045
+ routes: {
2046
+ "asker-decides": "The person who asked decides in their chat",
2047
+ "subject-asker-rights": "The object's approvers decide, with the rights of the person who asked",
2048
+ "subject-agent-rights": "The object's approvers decide, with this agent's technical account"
2049
+ },
2050
+ "routes-hint": {
2051
+ "asker-decides": "Approving runs it at once with that person's own rights.",
2052
+ "subject-asker-rights": "It waits at the object and runs later with the rights of the person who asked.",
2053
+ "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."
2054
+ },
2055
+ "route-blocks": {
2056
+ "not-in-ceiling": "The application does not allow this route.",
2057
+ system: "Not for the whole application.",
2058
+ "agent-answers-to-person": "Not for an agent that answers to the object's responsible person.",
2059
+ "agent-has-no-rights": "Not for an agent that answers for itself: it has no rights of its own to lend."
2060
+ },
2061
+ limits: {
2062
+ "tool-calls": "Tool calls",
2063
+ "timeout-seconds": "Time limit in seconds",
2064
+ "answer-chars": "Longest answer in characters",
2065
+ "history-messages": "Thread messages it reads"
2066
+ },
2067
+ form: {
2068
+ "new-title": "New consultation",
2069
+ "edit-title": "Consultation about {{type}}, version {{version}}",
2070
+ what: "What may other assistants consult it about?",
2071
+ "subject-type": "Kind of object",
2072
+ "subject-type-hint": "Only kinds of objects the agent works on and has no consultation about yet.",
2073
+ description: "When to consult it",
2074
+ "description-hint": "The assistant that asks reads this to decide when to consult this agent.",
2075
+ instructions: "Instructions when consulted",
2076
+ "instructions-hint": "Optional. What the agent keeps in mind when it answers, after the platform's own rules for consultations.",
2077
+ who: "Who may ask?",
2078
+ "minimum-role": "The person who asks is at least",
2079
+ "role-hint": {
2080
+ reader: "Anyone who may read the object.",
2081
+ participant: "People who work on the object.",
2082
+ approver: "People who approve changes to the object."
2083
+ },
2084
+ "asker-policy": "Policy the person needs",
2085
+ "asker-policy-agent": "The policy the agent requires",
2086
+ "asker-policy-hint": "One of the policies the application lists. Without one, the agent's own policy applies, or else access to the assistant.",
2087
+ "do": "What may it do?",
2088
+ answer: "Only answer",
2089
+ "answer-hint": "It answers with the rights of the person who asked and proposes nothing.",
2090
+ propose: "Answer and propose changes",
2091
+ "propose-hint": "It may also propose changes; the routes below decide who decides them.",
2092
+ "answers-only": "The application lets consultations only answer.",
2093
+ routes: "Who decides its proposals?",
2094
+ "routes-hint": "Choose at least one. Of the two routes at the object, choose one at most.",
2095
+ "proposal-role": "Role needed for proposals",
2096
+ "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.",
2097
+ "agent-policy": "The agent's approval policy",
2098
+ "policy-warning": {
2099
+ "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.",
2100
+ "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."
2101
+ },
2102
+ advanced: "Advanced: tools, limits, requests and classification",
2103
+ limits: "Limits of one consultation",
2104
+ "limits-hint": "Empty starts at the default within what the application allows.",
2105
+ "limit-range": "From {{min}} to {{max}}.",
2106
+ requests: "Also take requests",
2107
+ "requests-hint": "The assistant that asks may also ask this agent to start a run, with the person as its initiator.",
2108
+ "requests-closed": "The application does not allow requests.",
2109
+ mcp: "Offer to MCP clients",
2110
+ "mcp-hint": "External MCP clients may consult it too, with the rights of their person.",
2111
+ "mcp-closed": "The application does not offer consultations to MCP clients.",
2112
+ "classification-hint": "How sensitive its answers are in the conversation that asked. Without one, the agent's classification applies.",
2113
+ tools: "Tools it may use",
2114
+ "tools-hint": "The agent's own tools; select some to narrow them for this consultation. None selected: every tool of the agent. Changes still need a route.",
2115
+ "tool-not-covered": "No longer among the agent's own tools.",
2116
+ "in-effect": "A consultation is in effect once saved; it answers once an agent that asks selects its tool.",
2117
+ "starts-off": "Start off",
2118
+ "starts-off-hint": "It is not offered until you switch it on in the list, for example after a review.",
2119
+ "starts-off-ceiling": "A new consultation starts off: the application wants every one reviewed before it is offered. Switch it on in the list."
2120
+ },
2121
+ "off-badge": "Off",
2122
+ "off-explain": "Off: asking agents get none of its tools until you switch it on.",
2123
+ "switch-on": "Switch on",
2124
+ "switch-off": "Switch off",
2125
+ "switch-on-named": "Switch on the consultation about {{type}}",
2126
+ "switch-off-named": "Switch off the consultation about {{type}}",
2127
+ "switched-on": "The consultation is on: agents that ask get its tools.",
2128
+ "switched-off": "The consultation is off: agents that ask get none of its tools."
2129
+ }
2130
+ },
2131
+ "hand-offs": {
2132
+ title: "Hand-offs",
2133
+ description: "In their runs, other agents may hand work on an object to this agent, which then works on it in a run of its own with its own approvals. The application decides in its code which agents may be connected; here you connect them within that.",
2134
+ loading: "Loading hand-offs…",
2135
+ "load-failed": "The hand-offs could not be loaded.",
2136
+ add: "Add hand-off",
2137
+ empty: "No agent can hand work to this agent yet.",
2138
+ closed: {
2139
+ application: "The application does not let administrators connect agents to this one; its hand-offs come from its code.",
2140
+ "needs-settings": "Give the agent run settings before you connect agents to it.",
2141
+ limit: "This agent accepts as many hand-offs as allowed ({{max}}).",
2142
+ "no-types": "Every kind of object the application lets you connect this agent about already has a hand-off."
2143
+ },
2144
+ notifies: "Tells the source how it ended",
2145
+ "no-description": "No description.",
2146
+ from: "From:",
2147
+ "limit-value": "At most {{max}} per source and object per day",
2148
+ "code-hint": "Accepted in code; it cannot change here.",
2149
+ changed: "Changed by {{user}} on {{date}}",
2150
+ "edit-named": "Edit the hand-off about {{type}}",
2151
+ "remove-named": "Delete the hand-off about {{type}}",
2152
+ "remove-explain": "Its tool disappears from the sources' next runs; runs it started finish.",
2153
+ added: "The hand-off was added. A source uses it once its tools select its tool.",
2154
+ saved: "The hand-off was saved.",
2155
+ removed: "The hand-off was removed.",
2156
+ problems: {
2157
+ invalid: "Out of effect: a stored value is not valid.",
2158
+ "outside-ceiling": "Out of effect: the application no longer lets these agents be connected about this kind of object.",
2159
+ "unknown-agent": "Out of effect: this agent can no longer run on its own.",
2160
+ "unknown-source": "Out of effect: an agent that may hand off can no longer run on its own.",
2161
+ "not-worked-on": "Out of effect: this agent does not work on this kind of object.",
2162
+ "conflicts-with-code": "Out of effect: the application now accepts hand-offs about this kind of object in code.",
2163
+ "limit-above-ceiling": "Out of effect: the daily limit is above what the application allows."
2164
+ },
2165
+ form: {
2166
+ "new-title": "New hand-off",
2167
+ "edit-title": "Hand-off about {{type}}, version {{version}}",
2168
+ "subject-type": "Kind of object",
2169
+ "subject-type-hint": "The kinds of object the application lets you connect this agent about.",
2170
+ sources: "Agents that may hand off",
2171
+ "no-sources": "The application allows no agent that can run on its own to hand off about this kind of object yet.",
2172
+ "source-not-allowed": "No longer allowed; clear it.",
2173
+ "sources-hint": "Only the agents the application allows; an agent created here counts once it has run settings.",
2174
+ "sources-admin": "The application also allows agents created in the administration.",
2175
+ description: "Description for the sources",
2176
+ "description-hint": "When a source should hand work off, in a sentence or two.",
2177
+ notify: "Give the source a follow-up when this agent's run ends",
2178
+ "notify-hint": "The source hears the outcome and the number of proposals, and the run's summary when both work on the same object.",
2179
+ limit: "Hand-offs per source and object per day",
2180
+ "limit-hint": "1 to {{max}}; 5 when left empty.",
2181
+ "in-effect": "It is in effect once saved. A source's model gets its tool when the source's tools select it."
2182
+ }
2183
+ },
2184
+ "shadow-variants": {
2185
+ title: "Shadow variants",
2186
+ description: "A shadow variant receives every event of this agent and works on it in shadow, in threads only administrators see: it notifies nobody and nothing it proposes is carried out. Compare it with this agent in the evaluation.",
2187
+ loading: "Loading shadow variants…",
2188
+ "load-failed": "The shadow variants could not be loaded.",
2189
+ add: "New shadow variant",
2190
+ empty: "This agent has no shadow variants.",
2191
+ closed: {
2192
+ "not-allowed": "The application does not let administrators create shadow variants of this agent.",
2193
+ limit: "This agent has as many shadow variants as allowed ({{max}})."
2194
+ },
2195
+ source: {
2196
+ code: "In code",
2197
+ data: "Created here"
2198
+ },
2199
+ "needs-settings": "Needs run settings",
2200
+ "in-effect": "Receives this agent's events",
2201
+ open: "Run configuration",
2202
+ "set-up": "Set up runs",
2203
+ "open-named": "Open the run configuration of {{name}}",
2204
+ problems: {
2205
+ invalid: "Out of effect: a stored value is not valid.",
2206
+ "outside-ceiling": "Out of effect: the application no longer lets administrators create shadow variants of this agent.",
2207
+ "unknown-live-agent": "Out of effect: the agent it follows can no longer run on its own.",
2208
+ "live-agent-not-live": "Out of effect: the agent it follows is no live agent.",
2209
+ "too-many-variants": "Out of effect: the agent it follows has more shadow variants than the application allows."
2210
+ },
2211
+ form: {
2212
+ title: "New shadow variant",
2213
+ copies: "It starts from this agent's tools, MCP servers and what it works on, and its own run settings come next. It is never offered in the chat and its shadow mode cannot change.",
2214
+ id: "Id",
2215
+ "id-hint": "Lowercase letters, digits and dashes; it cannot change later.",
2216
+ name: "Name",
2217
+ "default-name": "{{name}} (variant)",
2218
+ description: "Description",
2219
+ instructions: "Instructions",
2220
+ "instructions-hint": "They start as this agent's instructions; change what the variant should try.",
2221
+ create: "Create variant"
1808
2222
  }
1809
2223
  },
1810
2224
  runs: {
@@ -1837,6 +2251,225 @@ var en = {
1837
2251
  id: "Account ID {{id}}",
1838
2252
  "copy-id": "Copy the account ID of {{name}}",
1839
2253
  "id-copied": "Account ID copied"
2254
+ },
2255
+ "instruction-assets": {
2256
+ source: "Where do the instructions come from?",
2257
+ "source-inline": "Written here",
2258
+ "source-inline-hint": "Type the instructions in this form.",
2259
+ "source-asset": "The application's text",
2260
+ "source-asset-hint": "Instructions the application ships or keeps, in an exact version. A new version is used only when you save it.",
2261
+ "not-offered": "The application no longer offers its text assets; write the instructions here to keep this working.",
2262
+ loading: "Loading the application's texts…",
2263
+ asset: "Text",
2264
+ "asset-hint": "The application lists the texts you can choose, each in an exact version.",
2265
+ choose: "Choose a text",
2266
+ option: "{{asset}}, version {{version}}",
2267
+ deprecated: "Replaced by the application",
2268
+ "deprecated-by": "Replaced by {{asset}}",
2269
+ "none-listed": "The application lists no texts; enter the id and version it gave you.",
2270
+ "asset-id": "Text id",
2271
+ version: "Version",
2272
+ read: "Read the text",
2273
+ reading: "Reading the text…",
2274
+ reference: "Uses {{asset}}, version {{version}}.",
2275
+ hash: "Hash {{hash}}",
2276
+ newer: "Version {{version}} of this text is available. Choose it and save to use it; the version in use stays until then.",
2277
+ text: "Text of the instructions",
2278
+ "text-hint": "Read-only: the application owns this text. Saving stores which text and version, never a copy.",
2279
+ "agent-problem": "The agent does not work:",
2280
+ problems: {
2281
+ "no-asset-source": "The application no longer offers its texts; the instructions are not available.",
2282
+ "asset-missing": "The application no longer has this text in this version.",
2283
+ "asset-changed": "The text changed since it was saved, so it is not used. Read it again and save to use the new text.",
2284
+ "asset-invalid": "This text cannot be used as instructions.",
2285
+ "asset-unavailable": "The application's texts could not be read; they are read again shortly."
2286
+ },
2287
+ errors: {
2288
+ required: "Choose a text and read it first.",
2289
+ "not-found": "The application has no such text in this version.",
2290
+ changed: "The text changed since you read it. Read it again before you save.",
2291
+ invalid: "Enter a text id in lowercase letters, digits and dashes, and a version of 1 or higher. The application may also not allow this text as instructions.",
2292
+ "not-allowed": "The application does not offer its texts here."
2293
+ }
2294
+ },
2295
+ packages: {
2296
+ "export": "Export as package",
2297
+ "export-named": "Export {{name}} as a package",
2298
+ "import": "Import package",
2299
+ "linked-badge": "Package {{package}} {{version}}",
2300
+ "delete-locked": "The agent belongs to package {{package}}. Unlink the agent first to delete it.",
2301
+ "remove-locked": "Package {{package}} locks this part. Unlink it first to remove it.",
2302
+ lock: {
2303
+ linked: "Linked to package {{package}}, version {{version}}.",
2304
+ "agent-linked": "This agent comes from package {{package}}, version {{version}}.",
2305
+ whole: "The package locks it as a whole: it changes with the package's next version.",
2306
+ fields: "Locked: {{fields}}.",
2307
+ "nothing-locked": "Nothing of it is locked; the package's next version overwrites a change made here.",
2308
+ field: "Locked by package {{package}}, version {{version}}",
2309
+ unlink: "Unlink",
2310
+ "unlink-agent": "Unlink the agent",
2311
+ "unlink-explain": "Unlinked, this part is local: it changes here again, and later versions of {{package}} leave it as it is unless an import takes the package's version again.",
2312
+ "unlink-agent-explain": "Unlinked, every part of the agent is local: it changes here again, and later versions of {{package}} leave the agent as it is unless an import takes the package's version again.",
2313
+ "confirm-unlink": "Unlink"
2314
+ },
2315
+ parts: {
2316
+ agent: "Agent",
2317
+ "run-settings": "Run settings",
2318
+ skill: "Skill {{name}}",
2319
+ trigger: "Trigger {{name}}",
2320
+ consultation: "Consultation about {{name}}",
2321
+ "hand-off": "Hand-off about {{name}}",
2322
+ metadata: "Field {{name}}"
2323
+ },
2324
+ outcomes: {
2325
+ created: "New",
2326
+ changed: "Changed",
2327
+ unchanged: "Unchanged",
2328
+ "kept-local": "Kept local",
2329
+ "left-behind": "Left behind",
2330
+ refused: "Refused"
2331
+ },
2332
+ "outcome-explain": {
2333
+ created: "The import adds it.",
2334
+ changed: "The import replaces it with the package's version.",
2335
+ unchanged: "It is the same as the package's version.",
2336
+ "kept-local": "It was unlinked here, so the import leaves it as it is unless you take the package's version.",
2337
+ "left-behind": "The package no longer holds this agent: it stays here, unlinked.",
2338
+ refused: "The import refuses it, and with it the whole package."
2339
+ },
2340
+ "changed-locally": "Changed locally",
2341
+ "changed-locally-hint": "Someone changed it here since it was imported; the import overwrites that change.",
2342
+ "export-dialog": {
2343
+ title: "Export agents as a package",
2344
+ close: "Close",
2345
+ agents: "Agents in the package",
2346
+ "agents-hint": "The package holds exactly these agents, each with its run settings, skills, triggers, consultations, hand-offs, fields and groups; never runs, history, accounts or secrets.",
2347
+ "agents-required": "Choose at least one agent.",
2348
+ "too-many": "A package holds at most {{max}} agents.",
2349
+ "package-id": "Package id",
2350
+ "package-id-hint": "Lowercase letters, digits and dashes. A host upgrades the agents it imported from the same package id.",
2351
+ "package-id-default": "Empty: {{id}}",
2352
+ version: "Version",
2353
+ "version-hint": "A whole number from 1. Empty: the next version after the one this host imported, otherwise 1.",
2354
+ description: "Description",
2355
+ "description-hint": "Optional: what the package is for, for whoever imports it.",
2356
+ locks: "Locks",
2357
+ "locks-hint": "Where the package is imported, a locked part shows read-only and saving refuses to change it until an administrator unlinks it.",
2358
+ "lock-none": "Not locked",
2359
+ "lock-whole": "All of it",
2360
+ "lock-fields": "Chosen fields",
2361
+ "lock-choice": "Lock {{part}}",
2362
+ "lock-fields-of": "Fields of {{part}} to lock",
2363
+ "loading-parts": "Reading the parts of the agents…",
2364
+ "parts-failed": "The parts of the agents could not be read.",
2365
+ "no-parts": "Nothing of this agent travels as data.",
2366
+ references: "References outside the package",
2367
+ "references-hint": "These agents are not in the package, so they must exist where it is imported.",
2368
+ add: "Add {{agent}}",
2369
+ download: "Download package",
2370
+ downloading: "Exporting…",
2371
+ downloaded: "The package was downloaded as {{file}}.",
2372
+ reference: {
2373
+ "hand-off-source": "{{referenced}} hands work to {{agent}} ({{part}}).",
2374
+ "shadow-of": "{{agent}} is a shadow variant of {{referenced}}.",
2375
+ "consultation-asker": "{{referenced}} consults {{agent}} ({{part}}).",
2376
+ "shadow-variant": "{{referenced}} is a shadow variant of {{agent}} and receives its triggers."
2377
+ }
2378
+ },
2379
+ "import-dialog": {
2380
+ title: "Import an agent package",
2381
+ close: "Close",
2382
+ file: "Package file",
2383
+ "file-hint": "A JSON file of at most 1 MB, as an export writes it.",
2384
+ "file-chosen": "Read from {{name}}.",
2385
+ paste: "Or paste the package",
2386
+ "paste-hint": "The JSON of the package.",
2387
+ "invalid-json": "This is no package: its JSON cannot be read.",
2388
+ "too-large": "A package is at most 1 MB.",
2389
+ "no-package": "Choose a package file or paste a package first.",
2390
+ preview: "Check the package",
2391
+ previewing: "Checking…",
2392
+ "preview-again": "Check again",
2393
+ "preview-title": "What the import does",
2394
+ summary: "Package {{package}}, version {{version}}",
2395
+ "agent-heading": "Agent {{agent}}",
2396
+ "column-part": "Part",
2397
+ "column-outcome": "Outcome",
2398
+ "column-details": "Details",
2399
+ "column-relink": "Package's version",
2400
+ relink: "Take the package's version of {{part}}",
2401
+ "relink-hint": "Relinks the part: the import overwrites the local version and links it to the package again.",
2402
+ account: "Technical account of {{agent}}",
2403
+ "account-hint": "Accounts never travel: choose the account on this host that the agent answers to.",
2404
+ apply: "Changed skills and triggers",
2405
+ "apply-live": "Take effect at once",
2406
+ "apply-live-hint": "Each change becomes the live version, as a save does.",
2407
+ "apply-shadow": "Run in shadow first",
2408
+ "apply-shadow-hint": "Each change becomes a candidate next to the live version, to compare and promote.",
2409
+ "apply-new-hint": "New skills and triggers start in shadow either way.",
2410
+ refused: "The import refuses {{count}} parts. Fix the package or the host, then check again.",
2411
+ "options-changed": "The choices changed since the check; check again before importing.",
2412
+ "import": "Import",
2413
+ importing: "Importing…",
2414
+ imported: "The package was imported.",
2415
+ "result-title": "What the import did",
2416
+ done: "Done",
2417
+ "agent-exists": "An agent with this id exists on this host and is not linked to this package. Take it over to let the package replace its configuration and link it, or remove it first.",
2418
+ "agent-exists-other-package": "An agent with this id belongs to package {{package}} on this host. Unlink it from that package first, then take it over or remove it.",
2419
+ "agent-exists-in-code": "An agent in code has this id on this host; the package's agent cannot replace it.",
2420
+ "take-over": "Take over the existing agent",
2421
+ "take-over-hint": "The package replaces its configuration and links it.",
2422
+ "refused-one": "The import refuses {{count}} part. Fix the package or the host, then check again."
2423
+ },
2424
+ fields: {
2425
+ "display-name": "Name",
2426
+ description: "Description",
2427
+ instructions: "Instructions",
2428
+ "tool-selectors": "Tools",
2429
+ "required-policy": "Required policy",
2430
+ autonomy: "Autonomy",
2431
+ "offered-in-chat": "Use in the chat",
2432
+ "works-on": "What it works on",
2433
+ profile: "Model profile",
2434
+ "data-classification": "Data classification",
2435
+ accountability: "Answers to",
2436
+ "delegate-from-initiator": "Rights of the person who starts a run",
2437
+ "allow-gateway-reads": "Reads through the data gateway",
2438
+ "elevated-reads": "Reads with the account's rights",
2439
+ "approval-policy": "Approval policy",
2440
+ "retry-count": "Retries after a failure",
2441
+ "daily-budget": "Daily limits",
2442
+ "max-concurrent-runs": "Runs at the same time",
2443
+ "max-runs-per-subject-per-day": "Runs per subject per day",
2444
+ "max-tokens-per-run": "Tokens per run",
2445
+ "triage-profile": "Triage profile",
2446
+ "rule-handler": "Way of working",
2447
+ files: "Files",
2448
+ tools: "Tools",
2449
+ skill: "Skill",
2450
+ source: "When it starts",
2451
+ event: "Event",
2452
+ filters: "Filters",
2453
+ cron: "Schedule",
2454
+ "time-zone": "Time zone",
2455
+ "subject-set": "Subjects",
2456
+ message: "Message to every run",
2457
+ conflict: "While a run is busy",
2458
+ "debounce-seconds": "Wait for more events",
2459
+ "minimum-role": "Role of the person who asks",
2460
+ "asker-policy": "Policy of the person who asks",
2461
+ routes: "Routes",
2462
+ "proposal-role": "Role before it proposes",
2463
+ "proposal-policy": "Approval policy of its proposals",
2464
+ limits: "Limits",
2465
+ "allow-requests": "Requests",
2466
+ "expose-to-mcp": "MCP clients",
2467
+ sources: "Agents that may hand off",
2468
+ "notify-source": "Tells the source how it ended",
2469
+ "max-per-subject-per-day": "Hand-offs per source and object per day",
2470
+ value: "Value"
2471
+ },
2472
+ "reset-locked": "Package {{package}} locks fields of the definition. Unlink them first to reset the agent."
1840
2473
  }
1841
2474
  },
1842
2475
  "page-context": {
@@ -1942,6 +2575,7 @@ var en = {
1942
2575
  inbox: {
1943
2576
  title: "Proposals to decide",
1944
2577
  description: "Proposals of agents that wait for your decision, the ones that expire first on top.",
2578
+ "description-grouped": "Proposals of agents that wait for your decision, grouped by object; the group with the proposal that expires first is on top.",
1945
2579
  empty: "No proposals wait for you.",
1946
2580
  select: "Select this proposal",
1947
2581
  "select-all": "Select all",
@@ -1972,6 +2606,10 @@ var en = {
1972
2606
  "re-execute": "Run again",
1973
2607
  "mark-resolved": "Mark as resolved",
1974
2608
  "unknown-hint": "The execution stopped without a known outcome. Check whether it happened before you run it again.",
2609
+ "hand-to-application": "Hand to the application again",
2610
+ "unknown-application-hint": "The application did not confirm that it carried this out. Check in the application whether it happened before you hand it over again.",
2611
+ "awaiting-application-hint": "The application carries out this approved proposal and reports back when it is done.",
2612
+ "report-due": "Report due {{date}}",
1975
2613
  mode: {
1976
2614
  inline: "The run waits",
1977
2615
  deferred: "Decide later"
@@ -1984,6 +2622,7 @@ var en = {
1984
2622
  withdrawn: "Withdrawn",
1985
2623
  stale: "Outdated",
1986
2624
  executing: "Running",
2625
+ "awaiting-application": "With the application",
1987
2626
  executed: "Done",
1988
2627
  "execution-failed": "Failed",
1989
2628
  "execution-unknown": "Outcome unknown",
@@ -1991,7 +2630,22 @@ var en = {
1991
2630
  shadow: "Shadow"
1992
2631
  },
1993
2632
  "from-consultation": "From a consultation",
1994
- "from-consultation-hint": "Another assistant consulted the agent for this person; it runs with that person's rights only.",
2633
+ "from-consultation-hint": "Another assistant consulted the agent for a person, and the agent proposed this.",
2634
+ consultation: {
2635
+ "asked-by": "Asked by {{name}}",
2636
+ "the-asker": "the person who asked",
2637
+ route: {
2638
+ "asker-decides": "The person who asked decides in their own chat; it runs with their own rights.",
2639
+ "subject-agent-rights": "The subject's approvers other than the person who asked decide; it runs with the agent's own rights.",
2640
+ "subject-asker-rights": "The subject's approvers decide; it runs with the rights of the person who asked."
2641
+ },
2642
+ "waiting-for-asker": "Waiting for {{name}} to decide in their own chat.",
2643
+ "four-eyes": "You asked for this, so another approver decides; it runs with the agent's own rights.",
2644
+ "runs-with": {
2645
+ agent: "Runs with the agent's rights",
2646
+ accountable: "Runs with the technical account's rights"
2647
+ }
2648
+ },
1995
2649
  "give-feedback": "Give feedback",
1996
2650
  "change-feedback": "Change feedback",
1997
2651
  "your-feedback": "Your feedback: {{category}}",
@@ -2070,6 +2724,11 @@ var en = {
2070
2724
  running: "Running",
2071
2725
  completed: "Answered",
2072
2726
  failed: "Not answered"
2727
+ },
2728
+ routes: {
2729
+ "asker-decides": "Asker decides: {{count}}",
2730
+ "subject-agent-rights": "Approvers, agent's rights: {{count}}",
2731
+ "subject-asker-rights": "Approvers, asker's rights: {{count}}"
2073
2732
  }
2074
2733
  },
2075
2734
  "object-agents": {
@@ -2274,7 +2933,11 @@ var nl = {
2274
2933
  trigger: "Gebeurtenis",
2275
2934
  rule: "Automatische regel",
2276
2935
  files: "Bijgevoegde bestanden",
2277
- "file-meta": "{{type}}, {{size}}"
2936
+ "file-meta": "{{type}}, {{size}}",
2937
+ application: "Applicatie",
2938
+ "application-label": "Bericht van de applicatie",
2939
+ "application-link": "Openen",
2940
+ "application-trusted": "Instructie voor de assistent"
2278
2941
  },
2279
2942
  composer: {
2280
2943
  label: "Bericht",
@@ -2382,6 +3045,7 @@ var nl = {
2382
3045
  withdrawn: "Ingetrokken",
2383
3046
  stale: "Verouderd",
2384
3047
  executing: "Wordt uitgevoerd",
3048
+ "awaiting-application": "Bij de applicatie",
2385
3049
  executed: "Uitgevoerd",
2386
3050
  "execution-failed": "Mislukt",
2387
3051
  "execution-unknown": "Uitkomst onbekend",
@@ -2392,6 +3056,7 @@ var nl = {
2392
3056
  "waiting-for-participant": "Wacht op de beslissing van de deelnemer die deze taak startte.",
2393
3057
  "waiting-for-approver": "Wacht tot een beslisser hierover beslist.",
2394
3058
  "waiting-for-other-approver": "Jij startte dit werk, dus een andere beslisser beslist hierover.",
3059
+ "waiting-for-asker": "Wacht tot degene die het vroeg, beslist in de eigen chat.",
2395
3060
  "give-feedback": "Wat klopte er niet?",
2396
3061
  "stale-kind": {
2397
3062
  "already-done": "Al gedaan",
@@ -2399,7 +3064,20 @@ var nl = {
2399
3064
  "not-applicable": "Niet meer nodig"
2400
3065
  },
2401
3066
  rationale: "Waarom: {{rationale}}",
2402
- superseded: "Vervangen door een nieuwer voorstel"
3067
+ superseded: "Vervangen door een nieuwer voorstel",
3068
+ consultation: {
3069
+ origin: "{{agent}} stelt dit voor, over {{subject}}",
3070
+ answer: "Antwoord van {{agent}}",
3071
+ "own-rights": "Goedkeuren voert het meteen uit met je eigen rechten.",
3072
+ leave: "Aan goedkeurders laten",
3073
+ "leave-label": "Aan goedkeurders laten: {{summary}}",
3074
+ "leave-explain": {
3075
+ "subject-agent-rights": "De goedkeurders van {{subject}} beslissen; daarna loopt het met de eigen rechten van de agent.",
3076
+ "subject-asker-rights": "De goedkeurders van {{subject}} beslissen; daarna loopt het met jouw rechten."
3077
+ },
3078
+ "moved-status": "Aan goedkeurders gelaten",
3079
+ moved: "Het wacht nu op de goedkeurders van {{subject}}."
3080
+ }
2403
3081
  },
2404
3082
  "proposal-feedback": {
2405
3083
  legend: "Wat klopte er niet? (optioneel)",
@@ -2607,6 +3285,11 @@ var nl = {
2607
3285
  "assistant-consult-timeout": "De agent antwoordde niet op tijd.",
2608
3286
  "assistant-consult-failed": "De agent kon niet antwoorden.",
2609
3287
  "assistant-consult-read-only": "Een raadpleging kan niets wijzigen.",
3288
+ "assistant-consult-tool-not-selected": "Deze raadpleging biedt die tool niet aan, dus er is niets uitgevoerd.",
3289
+ "assistant-consult-proposal-refused": "Geen route bij het onderwerp neemt dit voorstel nog aan. Keur het hier goed of af.",
3290
+ "assistant-consult-asker-decides": "Degene die het vroeg, beslist over dit voorstel in de eigen chat.",
3291
+ "assistant-consult-route-not-allowed": "Geen van de raadplegingen van de agent staat deze route toe, dus die kan niet aan.",
3292
+ "assistant-consult-proposal-moved": "Het voorstel is aan de goedkeurders van het onderwerp gelaten.",
2610
3293
  "assistant-moved-to-shadow": "Het werk is naar de schaduwthread van de agent gegaan, waar een run in schaduw het oppakt.",
2611
3294
  "assistant-shadow-variant": "Een schaduwvariant werkt altijd in schaduw.",
2612
3295
  "assistant-service-account-not-used": "Deze agent werkt niet onder een technisch account.",
@@ -2615,10 +3298,11 @@ var nl = {
2615
3298
  "assistant-trigger-in-code": "Deze trigger staat in de code en kan hier niet veranderen.",
2616
3299
  "assistant-trigger-filter-not-found": "De gebeurtenis heeft geen filter met deze naam. Kies uit de filters die de gebeurtenis biedt.",
2617
3300
  "assistant-skill-in-use": "Een trigger start deze vaardigheid nog. Pas de trigger eerst aan of verwijder hem.",
2618
- "assistant-configuration-limit": "Deze agent heeft al zoveel vaardigheden of triggers als is toegestaan.",
3301
+ "assistant-configuration-limit": "Deze agent heeft al zoveel vaardigheden, triggers of raadplegingen als is toegestaan.",
2619
3302
  "assistant-run-settings-in-code": "Deze agent staat in de code; daar is ingesteld hoe hij werkt.",
2620
- "assistant-run-settings-in-use": "Er horen nog vaardigheden of triggers bij deze agent. Verwijder die eerst.",
3303
+ "assistant-run-settings-in-use": "Er horen nog vaardigheden, triggers, raadplegingen of overdrachten bij deze agent. Verwijder die eerst.",
2621
3304
  "assistant-skill-candidate-not-found": "Van deze vaardigheid wordt geen versie in schaduw beoordeeld.",
3305
+ "assistant-trigger-candidate-not-found": "Van deze trigger wordt geen versie in schaduw beoordeeld.",
2622
3306
  "assistant-skill-version-gone": "De versie van de vaardigheid waarvoor deze run was, wordt niet meer beoordeeld.",
2623
3307
  "assistant-account-search-unavailable": "De applicatie biedt geen accountzoeker; vul de id van het account in.",
2624
3308
  "assistant-mcp-connection-required": "Deze server moet eerst gekoppeld worden. Koppel hem en probeer het opnieuw.",
@@ -2645,7 +3329,24 @@ var nl = {
2645
3329
  "assistant-file-type-not-accepted": "Dit type bestand kan niet worden bijgevoegd.",
2646
3330
  "assistant-file-upload-refused": "De applicatie heeft dit bestand geweigerd.",
2647
3331
  "assistant-file-upload-failed": "Het bestand kon nu niet worden opgeslagen. Probeer het zo opnieuw.",
2648
- "assistant-file-scan-refused": "Het bestand is niet door de scan op schadelijke inhoud gekomen en is niet opgeslagen."
3332
+ "assistant-file-scan-refused": "Het bestand is niet door de scan op schadelijke inhoud gekomen en is niet opgeslagen.",
3333
+ "assistant-consultation-in-code": "De agent staat raadpleging over deze soort object in code toe; die kan hier niet veranderen.",
3334
+ "assistant-consultation-not-found": "De raadpleging is niet gevonden.",
3335
+ "assistant-consultations-not-allowed": "De applicatie laat beheerders geen raadplegingen aan deze agent toevoegen.",
3336
+ "assistant-handoffs-not-allowed": "De applicatie laat beheerders geen agents aan deze agent koppelen.",
3337
+ "assistant-handoff-in-code": "De agent neemt overdrachten over deze soort object in code aan; die kan hier niet veranderen.",
3338
+ "assistant-handoff-not-found": "De overdracht is niet gevonden.",
3339
+ "assistant-shadow-variants-not-allowed": "De applicatie laat beheerders geen schaduwvarianten van deze agent maken.",
3340
+ "assistant-metadata-entry-not-found": "De applicatie kent dit veld van agents niet.",
3341
+ "assistant-metadata-read-only": "De applicatie zet dit veld van de agent in haar code; het kan hier niet veranderen.",
3342
+ "assistant-instructions-asset-not-found": "De applicatie heeft deze tekst niet in deze versie.",
3343
+ "assistant-instructions-asset-unavailable": "De teksten van de applicatie zijn nu niet te lezen. Er is niets opgeslagen; probeer het zo opnieuw.",
3344
+ "assistant-agent-instructions-unavailable": "Deze agent kan nu niet werken: de tekst van de applicatie met zijn instructies is niet beschikbaar. Een beheerder controleert de agent.",
3345
+ "assistant-package-format-unsupported": "Dit is geen agentpakket dat deze versie kan lezen: het formaat, de formaatversie of een eigenschap is onbekend.",
3346
+ "assistant-package-locked": "Een agentpakket vergrendelt dit. Ontkoppel het eerst van het pakket.",
3347
+ "assistant-package-too-large": "Een agentpakket is hoogstens 1 MB en bevat hoogstens 20 agents.",
3348
+ "assistant-package-refused": "De controle weigerde onderdelen van het pakket, dus er is niets geïmporteerd. Controleer het pakket opnieuw om te zien welke.",
3349
+ "assistant-package-not-linked": "Deze agent, of dit onderdeel ervan, is niet aan een agentpakket gekoppeld."
2649
3350
  },
2650
3351
  notices: {
2651
3352
  "no-answer": "De assistent is klaar zonder antwoord. Probeer het opnieuw of stel je vraag anders.",
@@ -2803,6 +3504,8 @@ var nl = {
2803
3504
  changed: "Gewijzigd door {{user}} op {{date}}.",
2804
3505
  reason: "Notitie: {{reason}}",
2805
3506
  waiting: "{{count}} gebeurtenissen wachten op het hervatten.",
3507
+ "stopped-was-off-hint": "Hij stond uit toen hij stopte: de noodstop opheffen zet hem weer uit. Hervatten zet hem aan.",
3508
+ "stopped-was-on-hint": "Hij stond niet uit toen hij stopte: de noodstop opheffen laat hem weer werken, net als Hervatten.",
2806
3509
  action: {
2807
3510
  active: "Hervatten",
2808
3511
  paused: "Pauzeren",
@@ -2890,6 +3593,44 @@ var nl = {
2890
3593
  },
2891
3594
  "input-label-search": "Account"
2892
3595
  },
3596
+ "consultation-routes": {
3597
+ title: "Routes van raadplegingen",
3598
+ 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.",
3599
+ "load-failed": "De routes van raadplegingen konden niet worden gelezen.",
3600
+ route: {
3601
+ "asker-decides": "Degene die het vroeg, beslist",
3602
+ "subject-agent-rights": "Goedkeurders beslissen, rechten van de agent",
3603
+ "subject-asker-rights": "Goedkeurders beslissen, rechten van de vrager"
3604
+ },
3605
+ explain: {
3606
+ "asker-decides": "Degene die het vroeg, beslist in de eigen chat; het loopt met diens eigen rechten.",
3607
+ "subject-agent-rights": "De goedkeurders van het onderwerp, behalve degene die het vroeg, beslissen; het loopt met de eigen rechten van de agent.",
3608
+ "subject-asker-rights": "De goedkeurders van het onderwerp beslissen; het loopt later met de rechten van degene die het vroeg."
3609
+ },
3610
+ on: "Aan",
3611
+ off: "Uit",
3612
+ code: "Zoals de raadplegingen toestaan",
3613
+ overridden: "Overschreven",
3614
+ "not-allowed": "Niet toegestaan",
3615
+ "not-allowed-hint": "Geen raadpleging van deze agent staat deze route toe, dus die blijft uit en kan niet aan.",
3616
+ "subject-types": "Voor: {{types}}",
3617
+ action: {
3618
+ on: "Aanzetten",
3619
+ off: "Uitzetten",
3620
+ code: "Terug naar wat de raadplegingen toestaan"
3621
+ },
3622
+ "explain-change": {
3623
+ on: "Raadplegingen gebruiken deze route weer voor nieuwe voorstellen. Voorstellen die er al zijn, houden hun route.",
3624
+ 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.",
3625
+ "code-on": "De raadplegingen beslissen weer: een ervan staat deze route toe, dus die staat aan.",
3626
+ "code-off": "De raadplegingen beslissen weer: geen ervan staat deze route toe, dus die blijft uit."
3627
+ },
3628
+ confirm: {
3629
+ on: "Aanzetten bevestigen",
3630
+ off: "Uitzetten bevestigen",
3631
+ code: "Bevestigen"
3632
+ }
3633
+ },
2893
3634
  "run-config": "Runconfiguratie",
2894
3635
  "run-now": "Nu uitvoeren",
2895
3636
  runs: "Runs",
@@ -2927,7 +3668,7 @@ var nl = {
2927
3668
  instructions: "Instructies",
2928
3669
  "instructions-hint": "Wat de agent doet en hoe hij antwoordt.",
2929
3670
  autonomy: "Autonomie",
2930
- "autonomy-hint": "Alleen Uitvoeren staat wijzigingen toe, en elke wijziging vraagt nog steeds om goedkeuring.",
3671
+ "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.",
2931
3672
  "required-policy": "Vereiste policy",
2932
3673
  "required-policy-hint": "Optioneel. Alleen gebruikers die aan deze policy voldoen zien de agent.",
2933
3674
  profile: "Modelprofiel",
@@ -2989,7 +3730,26 @@ var nl = {
2989
3730
  "in-code": "In deze groep in de code",
2990
3731
  "shadow-variant": "Een schaduwvariant werkt alleen voor beheerders en hoort bij geen groep."
2991
3732
  },
2992
- "catalog-unavailable": "De bouwstenen van agentruns konden niet worden gelezen, dus waar deze agent aan werkt en zijn groepen kun je nu niet wijzigen. Opslaan laat ze zoals ze zijn."
3733
+ metadata: {
3734
+ title: "Applicatievelden",
3735
+ hint: "De applicatie bewaart hier haar eigen gegevens over agents. Elk veld heeft een editor van de applicatie, die het zelf opslaat.",
3736
+ "save-first": "Sla de agent eerst op; daarna verschijnen zijn velden hier.",
3737
+ loading: "De velden worden geladen",
3738
+ "load-failed": "De velden van deze agent konden niet worden geladen.",
3739
+ "no-editor": "De applicatie toont geen editor voor dit veld.",
3740
+ "read-only": "Ingesteld in de code van de applicatie; het kan hier niet veranderen.",
3741
+ saved: "Opgeslagen.",
3742
+ removed: "Verwijderd.",
3743
+ source: {
3744
+ code: "Uit de code",
3745
+ override: "Hier gewijzigd, boven de waarde in de code",
3746
+ data: "Opgeslagen bij de agent",
3747
+ none: "Geen waarde"
3748
+ }
3749
+ },
3750
+ "catalog-unavailable": "De bouwstenen van agentruns konden niet worden gelezen, dus waar deze agent aan werkt en zijn groepen kun je nu niet wijzigen. Opslaan laat ze zoals ze zijn.",
3751
+ "starts-in-shadow": "In schaduw beginnen",
3752
+ "starts-in-shadow-hint": "Zodra de agent run-instellingen heeft, werken zijn runs in zijn schaduwthreads, waar niemand een melding krijgt en niets wordt uitgevoerd, tot je hem live zet in de lijst met agents."
2993
3753
  },
2994
3754
  effect: {
2995
3755
  "read-only": "Alleen lezen",
@@ -3347,7 +4107,10 @@ var nl = {
3347
4107
  agent: "Runinstellingen:",
3348
4108
  skill: "Vaardigheid {{id}}:",
3349
4109
  candidate: "Kandidaat van vaardigheid {{id}}:",
3350
- trigger: "Trigger {{id}}:"
4110
+ trigger: "Trigger {{id}}:",
4111
+ consultation: "Raadpleging over {{id}}:",
4112
+ "hand-off": "Overdracht over {{id}}:",
4113
+ "trigger-candidate": "Kandidaat van trigger {{id}}:"
3351
4114
  },
3352
4115
  code: {
3353
4116
  "unknown-agent": "de agent kan niet meer zelfstandig werken.",
@@ -3363,7 +4126,29 @@ var nl = {
3363
4126
  "unknown-skill": "de vaardigheid bestaat niet meer.",
3364
4127
  "invalid-schedule": "het schema of de tijdzone is niet geldig.",
3365
4128
  invalid: "een waarde is niet geldig.",
3366
- "not-worked-on": "het gaat over een soort object, of de hele applicatie, waaraan de agent niet werkt."
4129
+ "not-worked-on": "het gaat over een soort object, of de hele applicatie, waaraan de agent niet werkt.",
4130
+ "unknown-subject-type": "de soort object bestaat niet meer.",
4131
+ "unknown-agent-policy": "het beleid dat vragers nodig hebben, wordt niet meer aangeboden.",
4132
+ "conflicts-with-tool": "een andere tool heeft al de naam van haar tool.",
4133
+ "not-consultable": "de applicatie laat beheerders geen raadplegingen meer aan deze agent toevoegen.",
4134
+ "route-not-allowed": "een route is niet meer toegestaan en valt weg.",
4135
+ "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.",
4136
+ "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.",
4137
+ "no-approver": "de route met het account van de agent valt weg, omdat het goedkeuringsbeleid alleen degene die een voorstel veroorzaakte laat beslissen.",
4138
+ "limit-above-ceiling": "een grens ligt boven wat de applicatie toestaat, dus die van de applicatie geldt.",
4139
+ "requests-not-allowed": "de applicatie staat geen verzoeken meer toe, dus ze neemt er geen aan.",
4140
+ "mcp-not-allowed": "de applicatie biedt raadplegingen niet meer aan MCP-clients aan, dus die zien haar niet.",
4141
+ "tools-not-allowed": "een gekozen tool hoort niet meer bij de eigen tools van de agent en valt weg; zonder tools krijgt de agent er geen enkele tool.",
4142
+ "no-asset-source": "de instructies komen uit de teksten van de applicatie, die de applicatie niet meer aanbiedt.",
4143
+ "asset-missing": "de applicatie heeft de tekst met de instructies niet meer in deze versie.",
4144
+ "asset-changed": "de tekst met de instructies is veranderd sinds hij is opgeslagen en wordt daarom niet gebruikt. Lees de tekst opnieuw en sla hem op als volgende versie.",
4145
+ "asset-invalid": "de tekst van de applicatie is niet te gebruiken als instructies.",
4146
+ "asset-unavailable": "de teksten van de applicatie waren niet te lezen; ze worden zo opnieuw gelezen.",
4147
+ "outside-ceiling": "de applicatie staat het niet meer toe.",
4148
+ "unknown-source": "een agent die mag overdragen kan niet meer zelfstandig werken.",
4149
+ "unknown-live-agent": "de agent die deze schaduwvariant volgt kan niet meer zelfstandig werken.",
4150
+ "live-agent-not-live": "de agent die deze schaduwvariant volgt is geen live agent.",
4151
+ "too-many-variants": "de agent die hij volgt heeft meer schaduwvarianten dan de applicatie toestaat."
3367
4152
  }
3368
4153
  },
3369
4154
  "field-errors": {
@@ -3380,7 +4165,11 @@ var nl = {
3380
4165
  "instructions-for-model": "Zonder vaste regels werkt het model met deze instructies; beschrijf wat het moet doen.",
3381
4166
  "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.",
3382
4167
  "megabytes-up-to": "Vul een grootte in boven 0 en hooguit {{max}} MB.",
3383
- "megabytes-positive": "Vul een grootte in boven 0 MB."
4168
+ "megabytes-positive": "Vul een grootte in boven 0 MB.",
4169
+ "not-allowed": "De applicatie staat dit niet toe.",
4170
+ "routes-required": "Kies minstens één route, of laat hem alleen antwoorden.",
4171
+ "tools-not-allowed": "Een gekozen tool valt buiten de eigen tools van de agent. Haal het vinkje weg, of voeg de tool eerst aan de agent toe.",
4172
+ locked: "Een agentpakket vergrendelt dit veld. Ontkoppel het onderdeel eerst om het te wijzigen."
3384
4173
  },
3385
4174
  settings: {
3386
4175
  title: "Runinstellingen",
@@ -3623,6 +4412,24 @@ var nl = {
3623
4412
  "set-hint": "Telkens één run voor elk object in een verzameling, zoals de actieve projecten.",
3624
4413
  "every-division": "Elke divisie",
3625
4414
  dropped: "Dit schema draaide voor de hele applicatie, waaraan de agent niet meer werkt. Kies een verzameling objecten."
4415
+ },
4416
+ "saved-candidate": "De nieuwe versie vuurt in schaduw naast de live versie, die blijft werken.",
4417
+ apply: "Hoe de wijziging ingaat",
4418
+ "apply-live": "Direct toepassen",
4419
+ "apply-live-hint": "De nieuwe versie vervangt de live versie meteen, in de modus van de trigger.",
4420
+ "apply-shadow": "Eerst in schaduw beoordelen naast de live versie",
4421
+ "apply-shadow-hint": "De nieuwe versie vuurt naast de live versie in de schaduwthreads van de agent, waar niets wordt uitgevoerd; vergelijk ze en promoveer of verwerp hem daarna.",
4422
+ versions: "Versies",
4423
+ candidate: {
4424
+ explain: "Versie {{version}} vuurt in schaduw naast de live versie: zijn runs werken in de schaduwthreads van de agent, en de live versie blijft werken.",
4425
+ "out-of-effect": "De kandidaat vuurt niet: hij past niet meer bij de code ({{problem}}). De live versie blijft werken.",
4426
+ changes: "Wat de kandidaat verandert",
4427
+ "no-changes": "De kandidaat heeft dezelfde definitie als de live versie.",
4428
+ change: "{{candidate}} (live: {{live}})",
4429
+ comparison: "Live versie en kandidaat van trigger {{trigger}}",
4430
+ paired: "Sinds {{date}} startten beide een run op {{count}} dezelfde gebeurtenissen, alleen de live versie op {{liveOnly}} en alleen de kandidaat op {{candidateOnly}}.",
4431
+ promoted: "De kandidaat is nu de live versie van de trigger.",
4432
+ none: "geen"
3626
4433
  }
3627
4434
  },
3628
4435
  "way-of-working": "Werkwijze",
@@ -3758,7 +4565,14 @@ var nl = {
3758
4565
  "configured-off": "Nu uitvoeren: niet zolang de code van de applicatie de agent uitschakelt.",
3759
4566
  "no-settings": "Nu uitvoeren: pas als de agent runinstellingen heeft.",
3760
4567
  "no-catalog": "Nu uitvoeren: pas als de runcatalogus gelezen kan worden."
3761
- }
4568
+ },
4569
+ consultations: "Als een andere assistent hem raadpleegt",
4570
+ "no-consultations": "Nog geen andere assistent kan hem raadplegen.",
4571
+ "consultation-proposes": "Antwoordt en stelt voor",
4572
+ "consultation-answers": "Antwoordt alleen",
4573
+ "asked-by-none": "Nog geen agent vraagt het",
4574
+ "asked-by-one": "Gevraagd door 1 agent",
4575
+ "asked-by": "Gevraagd door {{count}} agents"
3762
4576
  },
3763
4577
  skills: {
3764
4578
  "code-rules": "Vaste regels in de code van de applicatie",
@@ -3841,8 +4655,235 @@ var nl = {
3841
4655
  "edit-trigger": "Trigger wijzigen",
3842
4656
  "edit-skill": "Vaardigheid wijzigen",
3843
4657
  "edit-trigger-named": "Trigger {{trigger}} bewerken",
3844
- "edit-skill-named": "Vaardigheid {{skill}} bewerken"
4658
+ "edit-skill-named": "Vaardigheid {{skill}} bewerken",
4659
+ "edit-consultation": "Raadpleging wijzigen",
4660
+ "edit-consultation-named": "De raadpleging over {{type}} bewerken"
3845
4661
  }
4662
+ },
4663
+ consultations: {
4664
+ title: "Raadplegingen",
4665
+ 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.",
4666
+ add: "Raadpleging toevoegen",
4667
+ empty: "Niemand kan deze agent nog raadplegen.",
4668
+ closed: {
4669
+ application: "De applicatie laat beheerders geen raadplegingen toevoegen; die komen uit haar code.",
4670
+ agent: "Deze agent staat in de code en laat beheerders geen raadplegingen toevoegen.",
4671
+ "needs-settings": "Geef de agent runinstellingen voordat je raadplegingen toevoegt.",
4672
+ limit: "Deze agent heeft al zoveel raadplegingen als is toegestaan ({{max}}).",
4673
+ "no-types": "Elke soort object waaraan deze agent werkt, heeft al een raadpleging."
4674
+ },
4675
+ requests: "Neemt verzoeken aan",
4676
+ mcp: "Aangeboden aan MCP-clients",
4677
+ "no-description": "Geen beschrijving.",
4678
+ askers: "Gevraagd door:",
4679
+ "open-asker": "De editor van {{agent}} openen",
4680
+ "no-askers": "Nog geen agent vraagt het. Selecteer de tool bij de tools van een agent die het moet vragen.",
4681
+ "code-hint": "Toegestaan in code; hier veranderen alleen de routeschakelaars hieronder iets.",
4682
+ "limits-value": "Hooguit {{calls}} toolaanroepen, {{seconds}} seconden, {{chars}} tekens en {{history}} berichten uit de thread",
4683
+ "tools-label": "Tools:",
4684
+ "tools-all": "alle tools van de agent",
4685
+ "tools-none": "geen, want geen gekozen tool hoort nog bij de eigen tools van de agent",
4686
+ "edit-named": "De raadpleging over {{type}} bewerken",
4687
+ "remove-named": "De raadpleging over {{type}} verwijderen",
4688
+ "remove-explain": "Haar tools verdwijnen; voorstellen die ze deed, kunnen nog worden beslist.",
4689
+ added: "De raadpleging is toegevoegd. Ze antwoordt zodra een agent die vraagt haar tool selecteert.",
4690
+ saved: "De raadpleging is opgeslagen.",
4691
+ removed: "De raadpleging is verwijderd.",
4692
+ roles: {
4693
+ reader: "Lezer",
4694
+ participant: "Deelnemer",
4695
+ approver: "Goedkeurder"
4696
+ },
4697
+ "roles-lower": {
4698
+ reader: "lezer",
4699
+ participant: "deelnemer",
4700
+ approver: "goedkeurder"
4701
+ },
4702
+ summary: {
4703
+ ask: "Mensen die minstens {{role}} van het object zijn, mogen het vragen.",
4704
+ "asker-policy": "Ze hebben ook {{policy}} nodig.",
4705
+ "asker-policy-agent": "Ze hebben ook het beleid nodig dat de agent vereist, of anders toegang tot de assistent.",
4706
+ "read-only": "De agent antwoordt alleen en stelt niets voor.",
4707
+ proposes: "De agent mag wijzigingen voorstellen als degene die het vroeg minstens {{role}} is: {{routes}}.",
4708
+ "proposes-code": "De agent mag wijzigingen voorstellen: {{routes}}."
4709
+ },
4710
+ routes: {
4711
+ "asker-decides": "Degene die het vroeg, beslist in de eigen chat",
4712
+ "subject-asker-rights": "De goedkeurders van het object beslissen, met de rechten van degene die het vroeg",
4713
+ "subject-agent-rights": "De goedkeurders van het object beslissen, met het technische account van deze agent"
4714
+ },
4715
+ "routes-hint": {
4716
+ "asker-decides": "Goedkeuren voert het meteen uit met diens eigen rechten.",
4717
+ "subject-asker-rights": "Het wacht bij het object en loopt later met de rechten van degene die het vroeg.",
4718
+ "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."
4719
+ },
4720
+ "route-blocks": {
4721
+ "not-in-ceiling": "De applicatie staat deze route niet toe.",
4722
+ system: "Niet voor de hele applicatie.",
4723
+ "agent-answers-to-person": "Niet voor een agent die verantwoording aflegt aan de verantwoordelijke van het object.",
4724
+ "agent-has-no-rights": "Niet voor een agent die voor zichzelf antwoordt: hij heeft geen eigen rechten om uit te lenen."
4725
+ },
4726
+ limits: {
4727
+ "tool-calls": "Toolaanroepen",
4728
+ "timeout-seconds": "Tijdslimiet in seconden",
4729
+ "answer-chars": "Langste antwoord in tekens",
4730
+ "history-messages": "Berichten uit de thread die hij leest"
4731
+ },
4732
+ form: {
4733
+ "new-title": "Nieuwe raadpleging",
4734
+ "edit-title": "Raadpleging over {{type}}, versie {{version}}",
4735
+ what: "Waarover mogen andere assistenten hem raadplegen?",
4736
+ "subject-type": "Soort object",
4737
+ "subject-type-hint": "Alleen soorten objecten waaraan de agent werkt en waarover hij nog geen raadpleging heeft.",
4738
+ description: "Wanneer je hem raadpleegt",
4739
+ "description-hint": "De assistent die vraagt, leest dit om te bepalen wanneer hij deze agent raadpleegt.",
4740
+ instructions: "Instructies bij een raadpleging",
4741
+ "instructions-hint": "Optioneel. Waar de agent op let als hij antwoordt, na de eigen regels van het platform voor raadplegingen.",
4742
+ who: "Wie mag het vragen?",
4743
+ "minimum-role": "Degene die het vraagt is minstens",
4744
+ "role-hint": {
4745
+ reader: "Iedereen die het object mag lezen.",
4746
+ participant: "Mensen die aan het object werken.",
4747
+ approver: "Mensen die wijzigingen aan het object goedkeuren."
4748
+ },
4749
+ "asker-policy": "Beleid dat de persoon nodig heeft",
4750
+ "asker-policy-agent": "Het beleid dat de agent vereist",
4751
+ "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.",
4752
+ "do": "Wat mag hij doen?",
4753
+ answer: "Alleen antwoorden",
4754
+ "answer-hint": "Hij antwoordt met de rechten van degene die het vroeg en stelt niets voor.",
4755
+ propose: "Antwoorden en wijzigingen voorstellen",
4756
+ "propose-hint": "Hij mag ook wijzigingen voorstellen; de routes hieronder bepalen wie erover beslist.",
4757
+ "answers-only": "De applicatie laat raadplegingen alleen antwoorden.",
4758
+ routes: "Wie beslist over zijn voorstellen?",
4759
+ "routes-hint": "Kies er minstens één. Van de twee routes bij het object kies je er hooguit één.",
4760
+ "proposal-role": "Rol nodig voor voorstellen",
4761
+ "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.",
4762
+ "agent-policy": "Het goedkeuringsbeleid van de agent",
4763
+ "policy-warning": {
4764
+ "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.",
4765
+ "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."
4766
+ },
4767
+ advanced: "Geavanceerd: tools, grenzen, verzoeken en classificatie",
4768
+ limits: "Grenzen van één raadpleging",
4769
+ "limits-hint": "Leeg begint bij de standaard binnen wat de applicatie toestaat.",
4770
+ "limit-range": "Van {{min}} tot en met {{max}}.",
4771
+ requests: "Ook verzoeken aannemen",
4772
+ "requests-hint": "De assistent die vraagt, mag deze agent ook vragen een run te starten, met de persoon als initiatiefnemer.",
4773
+ "requests-closed": "De applicatie staat geen verzoeken toe.",
4774
+ mcp: "Aanbieden aan MCP-clients",
4775
+ "mcp-hint": "Externe MCP-clients mogen hem ook raadplegen, met de rechten van hun persoon.",
4776
+ "mcp-closed": "De applicatie biedt raadplegingen niet aan MCP-clients aan.",
4777
+ "classification-hint": "Hoe gevoelig zijn antwoorden zijn in het gesprek dat vroeg. Zonder geldt de classificatie van de agent.",
4778
+ tools: "Tools die hij mag gebruiken",
4779
+ "tools-hint": "De eigen tools van de agent; selecteer er een paar om ze voor deze raadpleging te beperken. Niets geselecteerd: alle tools van de agent. Wijzigingen hebben nog steeds een route nodig.",
4780
+ "tool-not-covered": "Hoort niet meer bij de eigen tools van de agent.",
4781
+ "in-effect": "Een raadpleging werkt zodra ze is opgeslagen; ze antwoordt zodra een agent die vraagt haar tool selecteert.",
4782
+ "starts-off": "Uit beginnen",
4783
+ "starts-off-hint": "Hij wordt niet aangeboden tot je hem aanzet in de lijst, bijvoorbeeld na een beoordeling.",
4784
+ "starts-off-ceiling": "Een nieuwe raadpleging begint uit: de applicatie wil elke raadpleging beoordeeld hebben voordat hij wordt aangeboden. Zet hem aan in de lijst."
4785
+ },
4786
+ "off-badge": "Uit",
4787
+ "off-explain": "Uit: vragende agents krijgen geen van zijn tools tot je hem aanzet.",
4788
+ "switch-on": "Aanzetten",
4789
+ "switch-off": "Uitzetten",
4790
+ "switch-on-named": "Raadpleging over {{type}} aanzetten",
4791
+ "switch-off-named": "Raadpleging over {{type}} uitzetten",
4792
+ "switched-on": "De raadpleging staat aan: agents die vragen krijgen zijn tools.",
4793
+ "switched-off": "De raadpleging staat uit: agents die vragen krijgen geen van zijn tools."
4794
+ }
4795
+ },
4796
+ "hand-offs": {
4797
+ title: "Overdrachten",
4798
+ description: "Andere agents kunnen in hun runs werk aan een object aan deze agent overdragen, die er dan in een eigen run met eigen goedkeuringen aan werkt. De applicatie bepaalt in haar code welke agents gekoppeld mogen worden; hier koppel je ze daarbinnen.",
4799
+ loading: "Overdrachten laden…",
4800
+ "load-failed": "De overdrachten konden niet geladen worden.",
4801
+ add: "Overdracht toevoegen",
4802
+ empty: "Nog geen agent kan werk aan deze agent overdragen.",
4803
+ closed: {
4804
+ application: "De applicatie laat beheerders geen agents aan deze agent koppelen; haar overdrachten komen uit haar code.",
4805
+ "needs-settings": "Geef de agent runinstellingen voordat je agents eraan koppelt.",
4806
+ limit: "Deze agent neemt zoveel overdrachten aan als toegestaan ({{max}}).",
4807
+ "no-types": "Elke soort object waarover de applicatie deze agent laat koppelen heeft al een overdracht."
4808
+ },
4809
+ notifies: "Laat de bron weten hoe het afliep",
4810
+ "no-description": "Geen beschrijving.",
4811
+ from: "Van:",
4812
+ "limit-value": "Hoogstens {{max}} per bron en object per dag",
4813
+ "code-hint": "Aangenomen in code; dit kan hier niet veranderen.",
4814
+ changed: "Gewijzigd door {{user}} op {{date}}",
4815
+ "edit-named": "De overdracht over {{type}} bewerken",
4816
+ "remove-named": "De overdracht over {{type}} verwijderen",
4817
+ "remove-explain": "Het hulpmiddel verdwijnt uit de volgende runs van de bronnen; runs die het startte maken het af.",
4818
+ added: "De overdracht is toegevoegd. Een bron gebruikt hem zodra zijn hulpmiddelen het hulpmiddel ervan selecteren.",
4819
+ saved: "De overdracht is opgeslagen.",
4820
+ removed: "De overdracht is verwijderd.",
4821
+ problems: {
4822
+ invalid: "Buiten werking: een opgeslagen waarde is niet geldig.",
4823
+ "outside-ceiling": "Buiten werking: de applicatie laat deze agents niet meer over deze soort object koppelen.",
4824
+ "unknown-agent": "Buiten werking: deze agent kan niet meer zelfstandig werken.",
4825
+ "unknown-source": "Buiten werking: een agent die mag overdragen kan niet meer zelfstandig werken.",
4826
+ "not-worked-on": "Buiten werking: deze agent werkt niet aan deze soort object.",
4827
+ "conflicts-with-code": "Buiten werking: de applicatie neemt overdrachten over deze soort object nu in code aan.",
4828
+ "limit-above-ceiling": "Buiten werking: de daglimiet ligt boven wat de applicatie toestaat."
4829
+ },
4830
+ form: {
4831
+ "new-title": "Nieuwe overdracht",
4832
+ "edit-title": "Overdracht over {{type}}, versie {{version}}",
4833
+ "subject-type": "Soort object",
4834
+ "subject-type-hint": "De soorten object waarover de applicatie deze agent laat koppelen.",
4835
+ sources: "Agents die mogen overdragen",
4836
+ "no-sources": "De applicatie staat nog geen zelfstandig werkende agent toe om over deze soort object over te dragen.",
4837
+ "source-not-allowed": "Niet meer toegestaan; haal hem weg.",
4838
+ "sources-hint": "Alleen de agents die de applicatie toestaat; een hier gemaakte agent telt mee zodra hij runinstellingen heeft.",
4839
+ "sources-admin": "De applicatie staat ook agents toe die in het beheer gemaakt zijn.",
4840
+ description: "Beschrijving voor de bronnen",
4841
+ "description-hint": "Wanneer een bron werk moet overdragen, in een of twee zinnen.",
4842
+ notify: "Geef de bron een vervolg wanneer de run van deze agent eindigt",
4843
+ "notify-hint": "De bron hoort de uitkomst en het aantal voorstellen, en de samenvatting van de run wanneer beide aan hetzelfde object werken.",
4844
+ limit: "Overdrachten per bron en object per dag",
4845
+ "limit-hint": "1 tot en met {{max}}; 5 als je het leeg laat.",
4846
+ "in-effect": "Hij werkt zodra hij opgeslagen is. Het model van een bron krijgt het hulpmiddel ervan wanneer de hulpmiddelen van de bron het selecteren."
4847
+ }
4848
+ },
4849
+ "shadow-variants": {
4850
+ title: "Schaduwvarianten",
4851
+ description: "Een schaduwvariant krijgt elke gebeurtenis van deze agent en werkt eraan in schaduw, in threads die alleen beheerders zien: hij meldt niemand iets en niets wat hij voorstelt wordt uitgevoerd. Vergelijk hem met deze agent in de evaluatie.",
4852
+ loading: "Schaduwvarianten laden…",
4853
+ "load-failed": "De schaduwvarianten konden niet geladen worden.",
4854
+ add: "Nieuwe schaduwvariant",
4855
+ empty: "Deze agent heeft geen schaduwvarianten.",
4856
+ closed: {
4857
+ "not-allowed": "De applicatie laat beheerders geen schaduwvarianten van deze agent maken.",
4858
+ limit: "Deze agent heeft zoveel schaduwvarianten als toegestaan ({{max}})."
4859
+ },
4860
+ source: {
4861
+ code: "In code",
4862
+ data: "Hier gemaakt"
4863
+ },
4864
+ "needs-settings": "Heeft runinstellingen nodig",
4865
+ "in-effect": "Krijgt de gebeurtenissen van deze agent",
4866
+ open: "Runconfiguratie",
4867
+ "set-up": "Runs instellen",
4868
+ "open-named": "De runconfiguratie van {{name}} openen",
4869
+ problems: {
4870
+ invalid: "Buiten werking: een opgeslagen waarde is niet geldig.",
4871
+ "outside-ceiling": "Buiten werking: de applicatie laat beheerders geen schaduwvarianten van deze agent meer maken.",
4872
+ "unknown-live-agent": "Buiten werking: de agent die hij volgt kan niet meer zelfstandig werken.",
4873
+ "live-agent-not-live": "Buiten werking: de agent die hij volgt is geen live agent.",
4874
+ "too-many-variants": "Buiten werking: de agent die hij volgt heeft meer schaduwvarianten dan de applicatie toestaat."
4875
+ },
4876
+ form: {
4877
+ title: "Nieuwe schaduwvariant",
4878
+ copies: "Hij begint met de hulpmiddelen, MCP-servers en het werkgebied van deze agent; daarna volgen zijn eigen runinstellingen. Hij wordt nooit in de chat aangeboden en zijn schaduwmodus kan niet veranderen.",
4879
+ id: "Id",
4880
+ "id-hint": "Kleine letters, cijfers en streepjes; dit kan later niet veranderen.",
4881
+ name: "Naam",
4882
+ "default-name": "{{name}} (variant)",
4883
+ description: "Beschrijving",
4884
+ instructions: "Instructies",
4885
+ "instructions-hint": "Ze beginnen als de instructies van deze agent; verander wat de variant moet proberen.",
4886
+ create: "Variant maken"
3846
4887
  }
3847
4888
  },
3848
4889
  runs: {
@@ -3875,6 +4916,225 @@ var nl = {
3875
4916
  id: "Account-ID {{id}}",
3876
4917
  "copy-id": "Account-ID van {{name}} kopiëren",
3877
4918
  "id-copied": "Account-ID gekopieerd"
4919
+ },
4920
+ "instruction-assets": {
4921
+ source: "Waar komen de instructies vandaan?",
4922
+ "source-inline": "Hier geschreven",
4923
+ "source-inline-hint": "Typ de instructies in dit formulier.",
4924
+ "source-asset": "Tekst van de applicatie",
4925
+ "source-asset-hint": "Instructies die de applicatie meelevert of bewaart, in een vaste versie. Een nieuwe versie wordt pas gebruikt als je hem opslaat.",
4926
+ "not-offered": "De applicatie biedt haar teksten niet meer aan; schrijf de instructies hier zodat dit blijft werken.",
4927
+ loading: "De teksten van de applicatie laden…",
4928
+ asset: "Tekst",
4929
+ "asset-hint": "De applicatie toont de teksten die je kunt kiezen, elk in een vaste versie.",
4930
+ choose: "Kies een tekst",
4931
+ option: "{{asset}}, versie {{version}}",
4932
+ deprecated: "Vervangen door de applicatie",
4933
+ "deprecated-by": "Vervangen door {{asset}}",
4934
+ "none-listed": "De applicatie toont geen teksten; vul de id en versie in die je van haar kreeg.",
4935
+ "asset-id": "Id van de tekst",
4936
+ version: "Versie",
4937
+ read: "Tekst lezen",
4938
+ reading: "De tekst lezen…",
4939
+ reference: "Gebruikt {{asset}}, versie {{version}}.",
4940
+ hash: "Hash {{hash}}",
4941
+ newer: "Versie {{version}} van deze tekst is beschikbaar. Kies hem en sla op om hem te gebruiken; tot dan blijft de huidige versie in gebruik.",
4942
+ text: "Tekst van de instructies",
4943
+ "text-hint": "Alleen lezen: deze tekst is van de applicatie. Opslaan bewaart welke tekst en versie, nooit een kopie.",
4944
+ "agent-problem": "De agent werkt niet:",
4945
+ problems: {
4946
+ "no-asset-source": "De applicatie biedt haar teksten niet meer aan; de instructies zijn niet beschikbaar.",
4947
+ "asset-missing": "De applicatie heeft deze tekst niet meer in deze versie.",
4948
+ "asset-changed": "De tekst is veranderd sinds hij is opgeslagen en wordt daarom niet gebruikt. Lees hem opnieuw en sla op om de nieuwe tekst te gebruiken.",
4949
+ "asset-invalid": "Deze tekst is niet te gebruiken als instructies.",
4950
+ "asset-unavailable": "De teksten van de applicatie waren niet te lezen; ze worden zo opnieuw gelezen."
4951
+ },
4952
+ errors: {
4953
+ required: "Kies een tekst en lees hem eerst.",
4954
+ "not-found": "De applicatie heeft deze tekst niet in deze versie.",
4955
+ changed: "De tekst is veranderd sinds je hem las. Lees hem opnieuw voordat je opslaat.",
4956
+ invalid: "Vul een id in met kleine letters, cijfers en streepjes, en een versie van 1 of hoger. Mogelijk staat de applicatie deze tekst ook niet toe als instructies.",
4957
+ "not-allowed": "De applicatie biedt haar teksten hier niet aan."
4958
+ }
4959
+ },
4960
+ packages: {
4961
+ "export": "Als pakket exporteren",
4962
+ "export-named": "{{name}} als pakket exporteren",
4963
+ "import": "Pakket importeren",
4964
+ "linked-badge": "Pakket {{package}} {{version}}",
4965
+ "delete-locked": "De agent hoort bij pakket {{package}}. Ontkoppel de agent eerst om hem te verwijderen.",
4966
+ "remove-locked": "Pakket {{package}} vergrendelt dit onderdeel. Ontkoppel het eerst om het te verwijderen.",
4967
+ lock: {
4968
+ linked: "Gekoppeld aan pakket {{package}}, versie {{version}}.",
4969
+ "agent-linked": "Deze agent komt uit pakket {{package}}, versie {{version}}.",
4970
+ whole: "Het pakket vergrendelt het als geheel: het verandert met de volgende versie van het pakket.",
4971
+ fields: "Vergrendeld: {{fields}}.",
4972
+ "nothing-locked": "Er is niets van vergrendeld; de volgende versie van het pakket overschrijft een wijziging die hier is gemaakt.",
4973
+ field: "Vergrendeld door pakket {{package}}, versie {{version}}",
4974
+ unlink: "Ontkoppelen",
4975
+ "unlink-agent": "De agent ontkoppelen",
4976
+ "unlink-explain": "Ontkoppeld is dit onderdeel lokaal: het verandert hier weer, en latere versies van {{package}} laten het zoals het is, tenzij een import de versie van het pakket weer neemt.",
4977
+ "unlink-agent-explain": "Ontkoppeld is elk onderdeel van de agent lokaal: het verandert hier weer, en latere versies van {{package}} laten de agent zoals hij is, tenzij een import de versie van het pakket weer neemt.",
4978
+ "confirm-unlink": "Ontkoppelen"
4979
+ },
4980
+ parts: {
4981
+ agent: "Agent",
4982
+ "run-settings": "Runinstellingen",
4983
+ skill: "Vaardigheid {{name}}",
4984
+ trigger: "Trigger {{name}}",
4985
+ consultation: "Raadpleging over {{name}}",
4986
+ "hand-off": "Overdracht over {{name}}",
4987
+ metadata: "Veld {{name}}"
4988
+ },
4989
+ outcomes: {
4990
+ created: "Nieuw",
4991
+ changed: "Gewijzigd",
4992
+ unchanged: "Ongewijzigd",
4993
+ "kept-local": "Lokaal gehouden",
4994
+ "left-behind": "Achtergelaten",
4995
+ refused: "Geweigerd"
4996
+ },
4997
+ "outcome-explain": {
4998
+ created: "De import voegt het toe.",
4999
+ changed: "De import vervangt het door de versie van het pakket.",
5000
+ unchanged: "Het is gelijk aan de versie van het pakket.",
5001
+ "kept-local": "Het is hier ontkoppeld, dus de import laat het zoals het is, tenzij je de versie van het pakket neemt.",
5002
+ "left-behind": "Het pakket bevat deze agent niet meer: hij blijft hier, ontkoppeld.",
5003
+ refused: "De import weigert het, en daarmee het hele pakket."
5004
+ },
5005
+ "changed-locally": "Lokaal gewijzigd",
5006
+ "changed-locally-hint": "Iemand heeft het hier gewijzigd sinds het is geïmporteerd; de import overschrijft die wijziging.",
5007
+ "export-dialog": {
5008
+ title: "Agents als pakket exporteren",
5009
+ close: "Sluiten",
5010
+ agents: "Agents in het pakket",
5011
+ "agents-hint": "Het pakket bevat precies deze agents, elk met zijn runinstellingen, vaardigheden, triggers, raadplegingen, overdrachten, velden en groepen; nooit runs, geschiedenis, accounts of geheimen.",
5012
+ "agents-required": "Kies minstens één agent.",
5013
+ "too-many": "Een pakket bevat hoogstens {{max}} agents.",
5014
+ "package-id": "Pakket-id",
5015
+ "package-id-hint": "Kleine letters, cijfers en streepjes. Een host werkt de agents die hij uit hetzelfde pakket-id importeerde bij.",
5016
+ "package-id-default": "Leeg: {{id}}",
5017
+ version: "Versie",
5018
+ "version-hint": "Een heel getal vanaf 1. Leeg: de volgende versie na die deze host importeerde, anders 1.",
5019
+ description: "Beschrijving",
5020
+ "description-hint": "Optioneel: waarvoor het pakket is, voor wie het importeert.",
5021
+ locks: "Vergrendelingen",
5022
+ "locks-hint": "Waar het pakket wordt geïmporteerd, staat een vergrendeld onderdeel alleen-lezen en weigert opslaan het te wijzigen tot een beheerder het ontkoppelt.",
5023
+ "lock-none": "Niet vergrendeld",
5024
+ "lock-whole": "Helemaal",
5025
+ "lock-fields": "Gekozen velden",
5026
+ "lock-choice": "{{part}} vergrendelen",
5027
+ "lock-fields-of": "Te vergrendelen velden van {{part}}",
5028
+ "loading-parts": "De onderdelen van de agents lezen…",
5029
+ "parts-failed": "De onderdelen van de agents konden niet gelezen worden.",
5030
+ "no-parts": "Niets van deze agent gaat als gegevens mee.",
5031
+ references: "Verwijzingen buiten het pakket",
5032
+ "references-hint": "Deze agents zitten niet in het pakket, dus ze moeten bestaan waar het wordt geïmporteerd.",
5033
+ add: "{{agent}} toevoegen",
5034
+ download: "Pakket downloaden",
5035
+ downloading: "Exporteren…",
5036
+ downloaded: "Het pakket is gedownload als {{file}}.",
5037
+ reference: {
5038
+ "hand-off-source": "{{referenced}} draagt werk over aan {{agent}} ({{part}}).",
5039
+ "shadow-of": "{{agent}} is een schaduwvariant van {{referenced}}.",
5040
+ "consultation-asker": "{{referenced}} raadpleegt {{agent}} ({{part}}).",
5041
+ "shadow-variant": "{{referenced}} is een schaduwvariant van {{agent}} en krijgt zijn triggers."
5042
+ }
5043
+ },
5044
+ "import-dialog": {
5045
+ title: "Een agentpakket importeren",
5046
+ close: "Sluiten",
5047
+ file: "Pakketbestand",
5048
+ "file-hint": "Een JSON-bestand van hoogstens 1 MB, zoals een export het schrijft.",
5049
+ "file-chosen": "Gelezen uit {{name}}.",
5050
+ paste: "Of plak het pakket",
5051
+ "paste-hint": "De JSON van het pakket.",
5052
+ "invalid-json": "Dit is geen pakket: de JSON ervan kan niet gelezen worden.",
5053
+ "too-large": "Een pakket is hoogstens 1 MB.",
5054
+ "no-package": "Kies eerst een pakketbestand of plak een pakket.",
5055
+ preview: "Het pakket controleren",
5056
+ previewing: "Controleren…",
5057
+ "preview-again": "Opnieuw controleren",
5058
+ "preview-title": "Wat de import doet",
5059
+ summary: "Pakket {{package}}, versie {{version}}",
5060
+ "agent-heading": "Agent {{agent}}",
5061
+ "column-part": "Onderdeel",
5062
+ "column-outcome": "Uitkomst",
5063
+ "column-details": "Details",
5064
+ "column-relink": "Versie van het pakket",
5065
+ relink: "De versie van het pakket van {{part}} nemen",
5066
+ "relink-hint": "Koppelt het onderdeel weer: de import overschrijft de lokale versie en koppelt het weer aan het pakket.",
5067
+ account: "Technisch account van {{agent}}",
5068
+ "account-hint": "Accounts gaan nooit mee: kies het account op deze host waaraan de agent verantwoording aflegt.",
5069
+ apply: "Gewijzigde vaardigheden en triggers",
5070
+ "apply-live": "Direct van kracht",
5071
+ "apply-live-hint": "Elke wijziging wordt de live versie, zoals bij opslaan.",
5072
+ "apply-shadow": "Eerst in schaduw draaien",
5073
+ "apply-shadow-hint": "Elke wijziging wordt een kandidaat naast de live versie, om te vergelijken en te promoveren.",
5074
+ "apply-new-hint": "Nieuwe vaardigheden en triggers beginnen hoe dan ook in schaduw.",
5075
+ refused: "De import weigert {{count}} onderdelen. Herstel het pakket of de host en controleer opnieuw.",
5076
+ "options-changed": "De keuzes zijn gewijzigd sinds de controle; controleer opnieuw voordat je importeert.",
5077
+ "import": "Importeren",
5078
+ importing: "Importeren…",
5079
+ imported: "Het pakket is geïmporteerd.",
5080
+ "result-title": "Wat de import deed",
5081
+ done: "Klaar",
5082
+ "agent-exists": "Op deze host bestaat al een agent met dit id die niet aan dit pakket gekoppeld is. Neem hem over, zodat het pakket zijn configuratie vervangt en hem koppelt, of verwijder hem eerst.",
5083
+ "agent-exists-other-package": "Een agent met dit id hoort op deze host bij pakket {{package}}. Ontkoppel hem eerst van dat pakket en neem hem daarna over of verwijder hem.",
5084
+ "agent-exists-in-code": "Op deze host heeft een agent in code dit id; de agent van het pakket kan hem niet vervangen.",
5085
+ "take-over": "De bestaande agent overnemen",
5086
+ "take-over-hint": "Het pakket vervangt zijn configuratie en koppelt hem.",
5087
+ "refused-one": "De import weigert {{count}} onderdeel. Herstel het pakket of de host en controleer opnieuw."
5088
+ },
5089
+ fields: {
5090
+ "display-name": "Naam",
5091
+ description: "Omschrijving",
5092
+ instructions: "Instructies",
5093
+ "tool-selectors": "Tools",
5094
+ "required-policy": "Vereiste policy",
5095
+ autonomy: "Autonomie",
5096
+ "offered-in-chat": "Gebruik in de chat",
5097
+ "works-on": "Waaraan hij werkt",
5098
+ profile: "Modelprofiel",
5099
+ "data-classification": "Dataclassificatie",
5100
+ accountability: "Legt verantwoording af aan",
5101
+ "delegate-from-initiator": "Rechten van de persoon die een run start",
5102
+ "allow-gateway-reads": "Lezen via de datagateway",
5103
+ "elevated-reads": "Lezen met de rechten van het account",
5104
+ "approval-policy": "Goedkeuringsbeleid",
5105
+ "retry-count": "Nieuwe pogingen na een fout",
5106
+ "daily-budget": "Daglimieten",
5107
+ "max-concurrent-runs": "Runs tegelijk",
5108
+ "max-runs-per-subject-per-day": "Runs per onderwerp per dag",
5109
+ "max-tokens-per-run": "Tokens per run",
5110
+ "triage-profile": "Triageprofiel",
5111
+ "rule-handler": "Werkwijze",
5112
+ files: "Bestanden",
5113
+ tools: "Tools",
5114
+ skill: "Vaardigheid",
5115
+ source: "Wanneer hij start",
5116
+ event: "Gebeurtenis",
5117
+ filters: "Filters",
5118
+ cron: "Schema",
5119
+ "time-zone": "Tijdzone",
5120
+ "subject-set": "Onderwerpen",
5121
+ message: "Bericht aan elke run",
5122
+ conflict: "Terwijl een run bezig is",
5123
+ "debounce-seconds": "Wachten op meer gebeurtenissen",
5124
+ "minimum-role": "Rol van de persoon die vraagt",
5125
+ "asker-policy": "Policy van de persoon die vraagt",
5126
+ routes: "Routes",
5127
+ "proposal-role": "Rol voordat hij voorstelt",
5128
+ "proposal-policy": "Goedkeuringsbeleid van zijn voorstellen",
5129
+ limits: "Limieten",
5130
+ "allow-requests": "Verzoeken",
5131
+ "expose-to-mcp": "MCP-clients",
5132
+ sources: "Agents die mogen overdragen",
5133
+ "notify-source": "Laat de bron weten hoe het afliep",
5134
+ "max-per-subject-per-day": "Overdrachten per bron en object per dag",
5135
+ value: "Waarde"
5136
+ },
5137
+ "reset-locked": "Pakket {{package}} vergrendelt velden van de definitie. Ontkoppel ze eerst om de agent terug te zetten."
3878
5138
  }
3879
5139
  },
3880
5140
  "page-context": {
@@ -3980,6 +5240,7 @@ var nl = {
3980
5240
  inbox: {
3981
5241
  title: "Voorstellen om te beslissen",
3982
5242
  description: "Voorstellen van agents die op jouw besluit wachten, de eerst verlopende bovenaan.",
5243
+ "description-grouped": "Voorstellen van agents die op jouw besluit wachten, gegroepeerd per object; de groep met het eerst verlopende voorstel staat bovenaan.",
3983
5244
  empty: "Er wachten geen voorstellen op jou.",
3984
5245
  select: "Dit voorstel selecteren",
3985
5246
  "select-all": "Alles selecteren",
@@ -4010,6 +5271,10 @@ var nl = {
4010
5271
  "re-execute": "Opnieuw uitvoeren",
4011
5272
  "mark-resolved": "Als afgehandeld markeren",
4012
5273
  "unknown-hint": "De uitvoering stopte zonder bekende uitkomst. Controleer of het gebeurd is voordat je het opnieuw uitvoert.",
5274
+ "hand-to-application": "Opnieuw aan de applicatie geven",
5275
+ "unknown-application-hint": "De applicatie heeft niet bevestigd dat ze dit heeft uitgevoerd. Controleer in de applicatie of het gebeurd is voordat je het opnieuw overdraagt.",
5276
+ "awaiting-application-hint": "De applicatie voert dit goedgekeurde voorstel uit en meldt zich als het klaar is.",
5277
+ "report-due": "Melding verwacht {{date}}",
4013
5278
  mode: {
4014
5279
  inline: "De run wacht",
4015
5280
  deferred: "Later beslissen"
@@ -4022,6 +5287,7 @@ var nl = {
4022
5287
  withdrawn: "Ingetrokken",
4023
5288
  stale: "Verouderd",
4024
5289
  executing: "Wordt uitgevoerd",
5290
+ "awaiting-application": "Bij de applicatie",
4025
5291
  executed: "Uitgevoerd",
4026
5292
  "execution-failed": "Mislukt",
4027
5293
  "execution-unknown": "Uitkomst onbekend",
@@ -4029,7 +5295,22 @@ var nl = {
4029
5295
  shadow: "Schaduw"
4030
5296
  },
4031
5297
  "from-consultation": "Uit een raadpleging",
4032
- "from-consultation-hint": "Een andere assistent raadpleegde de agent voor deze persoon; het voorstel draait alleen met de rechten van die persoon.",
5298
+ "from-consultation-hint": "Een andere assistent raadpleegde de agent voor iemand, en de agent stelde dit voor.",
5299
+ consultation: {
5300
+ "asked-by": "Gevraagd door {{name}}",
5301
+ "the-asker": "degene die het vroeg",
5302
+ route: {
5303
+ "asker-decides": "Degene die het vroeg, beslist in de eigen chat; het loopt met diens eigen rechten.",
5304
+ "subject-agent-rights": "De goedkeurders van het onderwerp, behalve degene die het vroeg, beslissen; het loopt met de eigen rechten van de agent.",
5305
+ "subject-asker-rights": "De goedkeurders van het onderwerp beslissen; het loopt met de rechten van degene die het vroeg."
5306
+ },
5307
+ "waiting-for-asker": "Wacht tot {{name}} beslist in de eigen chat.",
5308
+ "four-eyes": "Jij vroeg hierom, dus een andere goedkeurder beslist; het loopt met de eigen rechten van de agent.",
5309
+ "runs-with": {
5310
+ agent: "Loopt met de rechten van de agent",
5311
+ accountable: "Loopt met de rechten van het technische account"
5312
+ }
5313
+ },
4033
5314
  "give-feedback": "Feedback geven",
4034
5315
  "change-feedback": "Feedback wijzigen",
4035
5316
  "your-feedback": "Jouw feedback: {{category}}",
@@ -4108,6 +5389,11 @@ var nl = {
4108
5389
  running: "Bezig",
4109
5390
  completed: "Beantwoord",
4110
5391
  failed: "Niet beantwoord"
5392
+ },
5393
+ routes: {
5394
+ "asker-decides": "Vrager beslist: {{count}}",
5395
+ "subject-agent-rights": "Goedkeurders, rechten van de agent: {{count}}",
5396
+ "subject-asker-rights": "Goedkeurders, rechten van de vrager: {{count}}"
4111
5397
  }
4112
5398
  },
4113
5399
  "object-agents": {
@@ -4486,6 +5772,20 @@ class NhAssistantTransport {
4486
5772
  return () => abort.abort();
4487
5773
  });
4488
5774
  }
5775
+ /**
5776
+ * A cold request with a JSON body that answers the response's text and headers, for an endpoint that
5777
+ * answers a file with details in a header, such as the export of an agent package. It aborts on
5778
+ * unsubscribe and errors as `json` does: with the code and field errors of a refused request's error
5779
+ * body, the endpoint's status mapping without one, and `assistant-network` when the request did not
5780
+ * reach the server.
5781
+ */
5782
+ file(method, path, body, accept, statusCodes = {}) {
5783
+ return new Observable(subscriber => {
5784
+ const abort = new AbortController();
5785
+ void this.executeFile(method, path, body, accept, statusCodes, abort.signal, subscriber);
5786
+ return () => abort.abort();
5787
+ });
5788
+ }
4489
5789
  async fetch(method, path, accept, body, signal) {
4490
5790
  const init = await this.createInit(method, accept, body, signal);
4491
5791
  return this.fetchFn(this.url(path), init);
@@ -4581,6 +5881,33 @@ class NhAssistantTransport {
4581
5881
  }
4582
5882
  return { code: statusCodes[response.status] ?? nhAssistantCodeForStatus(response.status), fieldErrors };
4583
5883
  }
5884
+ async executeFile(method, path, body, accept, statusCodes, signal, subscriber) {
5885
+ let response;
5886
+ try {
5887
+ response = await this.fetch(method, path, accept, body, signal);
5888
+ }
5889
+ catch {
5890
+ if (!signal.aborted) {
5891
+ subscriber.error(createApiError(0, nhAssistantCodeForStatus(0)));
5892
+ }
5893
+ return;
5894
+ }
5895
+ if (!response.ok) {
5896
+ const failure = await this.failure(response, statusCodes);
5897
+ subscriber.error(createApiError(response.status, failure.code, failure.fieldErrors));
5898
+ return;
5899
+ }
5900
+ try {
5901
+ const text = await response.text();
5902
+ subscriber.next({ text, headers: response.headers });
5903
+ subscriber.complete();
5904
+ }
5905
+ catch {
5906
+ if (!signal.aborted) {
5907
+ subscriber.error(createApiError(response.status, NhAssistantClientErrorCodes.streamInterrupted));
5908
+ }
5909
+ }
5910
+ }
4584
5911
  async executeJson(method, path, body, statusCodes, signal, subscriber) {
4585
5912
  let response;
4586
5913
  try {
@@ -4930,6 +6257,8 @@ const adminStatusCodes = {
4930
6257
  const maxAccountIds = 50;
4931
6258
  /** The longest account id the server reads; a longer id names no account. */
4932
6259
  const maxAccountIdLength = 256;
6260
+ /** The header of the agent package export that lists the references to agents outside the selection. */
6261
+ const packageWarningsHeader = 'X-NewHeap-Package-Warnings';
4933
6262
  /**
4934
6263
  * Client for the assistant administration endpoints (`admin/*`). The server requires the
4935
6264
  * access policy and the admin policy; show the administration only when
@@ -5003,6 +6332,15 @@ class NhAssistantAdminApiService {
5003
6332
  setServiceAccount(agentId, request) {
5004
6333
  return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/service-account`, request);
5005
6334
  }
6335
+ /**
6336
+ * Switches the routes of the agent's consultations on, off or back to the setting in code; a route
6337
+ * left out keeps its switch. Code is the ceiling: switching on a route that no consultation in code
6338
+ * allows fails with `assistant-consult-route-not-allowed`. Returns the agent's state with its
6339
+ * `consultationRoutes`.
6340
+ */
6341
+ setConsultationRoutes(agentId, request) {
6342
+ return this.request('POST', `admin/agents/${encodeURIComponent(agentId)}/consultation-routes`, request);
6343
+ }
5006
6344
  /**
5007
6345
  * Puts an agent, in code or created here, in exactly `groups` of the run catalog's `agentGroups`
5008
6346
  * and out of the others. The choice wins over the agent's `InGroup` in code. Fails with a field error
@@ -5011,6 +6349,29 @@ class NhAssistantAdminApiService {
5011
6349
  setAgentGroups(agentId, groups) {
5012
6350
  return this.request('PUT', `admin/agents/${encodeURIComponent(agentId)}/groups`, { groups });
5013
6351
  }
6352
+ /**
6353
+ * Every entry of agent metadata the application registers, with the agent's value in effect, where
6354
+ * it comes from and whether it changes here (`GET admin/agents/{id}/metadata`).
6355
+ */
6356
+ getAgentMetadata(agentId) {
6357
+ return this.request('GET', `${agentPath(agentId)}/metadata`);
6358
+ }
6359
+ /**
6360
+ * Saves the agent's value of one metadata entry after the checks in code: field errors `value` or
6361
+ * `value.<field>`. For an agent created here it makes the agent's next version (`expectedVersion` is
6362
+ * the agent's version); for an agent in code only an editable entry changes, as an override with a
6363
+ * version of its own (`assistant-metadata-read-only` otherwise).
6364
+ */
6365
+ saveAgentMetadata(agentId, name, request) {
6366
+ return this.request('PUT', metadataPath(agentId, name), request);
6367
+ }
6368
+ /**
6369
+ * Removes the agent's stored value of one metadata entry, so an agent in code uses its value in code
6370
+ * again; answers the entry as it is now.
6371
+ */
6372
+ removeAgentMetadata(agentId, name, expectedVersion) {
6373
+ return this.request('DELETE', withQuery$1(metadataPath(agentId, name), { expectedVersion }));
6374
+ }
5014
6375
  /** Deletes an admin agent. Code agents cannot be deleted; stop them instead. */
5015
6376
  deleteAgent(agentId) {
5016
6377
  return this.request('DELETE', `admin/agents/${encodeURIComponent(agentId)}`);
@@ -5134,6 +6495,21 @@ class NhAssistantAdminApiService {
5134
6495
  getRunCatalog() {
5135
6496
  return this.request('GET', 'admin/run-catalog');
5136
6497
  }
6498
+ /**
6499
+ * The application's assets an administrator may choose as instructions, without their content
6500
+ * (`GET admin/instruction-assets`). Fails with `assistant-instructions-asset-unavailable` when the
6501
+ * application's source fails.
6502
+ */
6503
+ listInstructionAssets() {
6504
+ return this.request('GET', 'admin/instruction-assets');
6505
+ }
6506
+ /**
6507
+ * The text of one asset, read-only, with the hash a reference stores. Fails with
6508
+ * `assistant-instructions-asset-not-found` for an asset or version the application does not have.
6509
+ */
6510
+ getInstructionAsset(assetId, version) {
6511
+ return this.request('GET', `admin/instruction-assets/${encodeURIComponent(assetId)}/versions/${encodeURIComponent(String(version))}`);
6512
+ }
5137
6513
  /**
5138
6514
  * Accounts whose name or e-mail address contains `query` (2 to 100 characters), at most `limit`.
5139
6515
  * Fails with `assistant-account-search-unavailable` when the application offers no search; the
@@ -5184,7 +6560,10 @@ class NhAssistantAdminApiService {
5184
6560
  getAgentRuns(agentId, filter = {}) {
5185
6561
  return this.request('GET', withQuery$1(`${agentPath(agentId)}/runs`, filter));
5186
6562
  }
5187
- /** Removes the run settings; while data skills or triggers belong to the agent, `assistant-run-settings-in-use`. */
6563
+ /**
6564
+ * Removes the run settings; while data skills, triggers, consultations or hand-offs defined as data
6565
+ * belong to the agent, `assistant-run-settings-in-use`.
6566
+ */
5188
6567
  removeRunSettings(agentId, removal = {}) {
5189
6568
  return this.request('DELETE', withQuery$1(`${agentPath(agentId)}/run-settings`, removal));
5190
6569
  }
@@ -5215,10 +6594,30 @@ class NhAssistantAdminApiService {
5215
6594
  compareSkillCandidate(agentId, skillId, filter = {}) {
5216
6595
  return this.request('GET', withQuery$1(`${skillPath(agentId, skillId)}/candidate/comparison`, filter));
5217
6596
  }
5218
- /** Adds a trigger defined as data, which starts in shadow, or changes one in the mode it has. */
6597
+ /**
6598
+ * Adds a trigger defined as data, which starts in shadow, or stores its next version: with `apply`
6599
+ * `live` (default) it takes effect at once in the trigger's mode; with `shadow` it becomes the
6600
+ * candidate that fires next to the live version until it is promoted or discarded.
6601
+ */
5219
6602
  saveDataTrigger(agentId, triggerId, request) {
5220
6603
  return this.request('PUT', triggerPath(agentId, triggerId), request);
5221
6604
  }
6605
+ /** Every version of a trigger defined as data, newest first, with its definition. */
6606
+ getDataTriggerVersions(agentId, triggerId) {
6607
+ return this.request('GET', `${triggerPath(agentId, triggerId)}/versions`);
6608
+ }
6609
+ /** Makes the candidate the live version of its trigger, in the trigger's mode. */
6610
+ promoteTriggerCandidate(agentId, triggerId, request) {
6611
+ return this.request('POST', `${triggerPath(agentId, triggerId)}/candidate/promote`, request);
6612
+ }
6613
+ /** Discards the candidate of a trigger; it stays as history and fires no more. */
6614
+ discardTriggerCandidate(agentId, triggerId, request) {
6615
+ return this.request('POST', `${triggerPath(agentId, triggerId)}/candidate/discard`, request);
6616
+ }
6617
+ /** Compares the trigger's candidate with its live version on the runs they started in the period. */
6618
+ compareTriggerCandidate(agentId, triggerId, filter = {}) {
6619
+ return this.request('GET', withQuery$1(`${triggerPath(agentId, triggerId)}/candidate/comparison`, filter));
6620
+ }
5222
6621
  removeDataTrigger(agentId, triggerId, removal = {}) {
5223
6622
  return this.request('DELETE', withQuery$1(triggerPath(agentId, triggerId), removal));
5224
6623
  }
@@ -5226,6 +6625,120 @@ class NhAssistantAdminApiService {
5226
6625
  setDataTriggerShadow(agentId, triggerId, request) {
5227
6626
  return this.request('POST', `${triggerPath(agentId, triggerId)}/shadow`, request);
5228
6627
  }
6628
+ /**
6629
+ * Adds or changes the consultation defined as data of an agent about one subject type, within the
6630
+ * agent's `consultationCeiling`. It is in effect once saved and answers when an asking agent selects
6631
+ * its consult tool. An agent that may get none fails with `assistant-consultations-not-allowed`, an
6632
+ * agent created here without run settings with `assistant-agent-not-configured`, a type the agent
6633
+ * allows consultation about in code with `assistant-consultation-in-code`, more than the ceiling's
6634
+ * `maxConsultations` with `assistant-configuration-limit`, a stale `expectedVersion` with
6635
+ * `assistant-version-conflict` and invalid input with field errors, such as `routes: not-allowed` for
6636
+ * a route outside the ceiling.
6637
+ */
6638
+ saveDataConsultation(agentId, subjectType, request) {
6639
+ return this.request('PUT', consultationPath(agentId, subjectType), request);
6640
+ }
6641
+ /**
6642
+ * Switches a consultation defined as data on or off, without a new version. Off, it is not offered,
6643
+ * while its recorded proposals can still be decided. Fails with `assistant-consultation-not-found`
6644
+ * without one and with `assistant-consultation-in-code` for a consultation in code.
6645
+ */
6646
+ setDataConsultationState(agentId, subjectType, request) {
6647
+ return this.request('POST', `${consultationPath(agentId, subjectType)}/state`, request);
6648
+ }
6649
+ /**
6650
+ * Removes a consultation defined as data: its tools disappear, while its recorded proposals can still
6651
+ * be decided. Fails with `assistant-consultation-not-found` without one and with
6652
+ * `assistant-consultation-in-code` for a consultation in code.
6653
+ */
6654
+ removeDataConsultation(agentId, subjectType, removal = {}) {
6655
+ return this.request('DELETE', withQuery$1(consultationPath(agentId, subjectType), removal));
6656
+ }
6657
+ /**
6658
+ * The hand-offs the agent accepts, in code and as data with their problems, and what the ceiling in
6659
+ * code (`UseHandOffsAsData`) lets administrators add; `ceiling` is `null` when it may accept none.
6660
+ */
6661
+ getAgentHandOffs(agentId) {
6662
+ return this.request('GET', `${agentPath(agentId)}/hand-offs`);
6663
+ }
6664
+ /**
6665
+ * Adds or changes the hand-off defined as data that the agent accepts about one subject type, within
6666
+ * the ceiling: in effect once saved, as one in code. An agent the ceiling connects to no agent fails
6667
+ * with `assistant-handoffs-not-allowed`, a type it accepts in code with `assistant-handoff-in-code`,
6668
+ * an agent without run configuration with `assistant-agent-not-configured`, more than the ceiling's
6669
+ * `maxHandOffs` with `assistant-configuration-limit`, a stale `expectedVersion` with
6670
+ * `assistant-version-conflict` and invalid input with field errors, such as `sources: not-allowed`
6671
+ * for a source outside the ceiling.
6672
+ */
6673
+ saveDataHandOff(agentId, subjectType, request) {
6674
+ return this.request('PUT', handOffPath(agentId, subjectType), request);
6675
+ }
6676
+ /**
6677
+ * Removes a hand-off defined as data; its tool disappears from the sources' next turns. Fails with
6678
+ * `assistant-handoff-not-found` without one and with `assistant-handoff-in-code` for one in code.
6679
+ */
6680
+ removeDataHandOff(agentId, subjectType, removal = {}) {
6681
+ return this.request('DELETE', withQuery$1(handOffPath(agentId, subjectType), removal));
6682
+ }
6683
+ /**
6684
+ * The agent's shadow variants, in code and created as data, and whether administrators may create
6685
+ * more (`UseShadowVariantsAsData`). Create a data variant with `createAgent` and `shadowOf`.
6686
+ */
6687
+ getShadowVariants(agentId) {
6688
+ return this.request('GET', `${agentPath(agentId)}/shadow-variants`);
6689
+ }
6690
+ /**
6691
+ * Exports exactly `agentIds` (1 to 20) as one agent package (`POST admin/agent-packages/export`):
6692
+ * agents created here whole, agents in code as an overlay of what data changes on them; never
6693
+ * history, candidates, runs, run state, shadow overrides, MCP servers, the technical account or
6694
+ * secrets. The options set the package id, version and locks; left out, the id of the package the
6695
+ * first agent is linked to and its next version, otherwise the first agent's id and 1. Answers the
6696
+ * package, its JSON exactly as the server wrote it for the download, and every reference to an agent
6697
+ * outside the selection, which must exist where the package is imported. Fails with
6698
+ * `assistant-agent-not-found` for an unknown agent and with field errors for invalid options; the
6699
+ * server audits the export.
6700
+ */
6701
+ exportAgentPackage(agentIds, options = {}) {
6702
+ return this.transport.file('POST', 'admin/agent-packages/export', { agentIds: [...agentIds], options }, 'application/json', adminStatusCodes).pipe(map(file => {
6703
+ let agentPackage;
6704
+ try {
6705
+ agentPackage = JSON.parse(file.text);
6706
+ }
6707
+ catch {
6708
+ throw new NhAssistantApiError(200, NhAssistantClientErrorCodes.invalidResponse, nhAssistantErrorMessageKey(NhAssistantClientErrorCodes.invalidResponse));
6709
+ }
6710
+ return { package: agentPackage, json: file.text, warnings: packageWarnings(file.headers.get(packageWarningsHeader)) };
6711
+ }));
6712
+ }
6713
+ /**
6714
+ * What importing the package would do, per agent and part (`POST admin/agent-packages/preview`):
6715
+ * `created`, `changed`, `unchanged`, `kept-local`, `left-behind` or `refused` with the field
6716
+ * errors of the save validators, after one check of the whole package against this host as it would
6717
+ * be after the import. Changes nothing. The server reads the package strictly: a package it does not
6718
+ * read fails with `assistant-package-format-unsupported`, one above 1 MB or 20 agents with
6719
+ * `assistant-package-too-large`.
6720
+ */
6721
+ previewAgentPackageImport(agentPackage, options = {}) {
6722
+ return this.request('POST', 'admin/agent-packages/preview', { package: agentPackage, options });
6723
+ }
6724
+ /**
6725
+ * Imports the package in one transaction (`POST admin/agent-packages/import`): every agent and part
6726
+ * of it, or nothing. Fails as `previewAgentPackageImport` does, and with `assistant-package-refused`
6727
+ * and the field error `parts: invalid` when the check refuses a part; preview again to see which part
6728
+ * and why. Every part is audited as its save.
6729
+ */
6730
+ importAgentPackage(agentPackage, options = {}) {
6731
+ return this.request('POST', 'admin/agent-packages/import', { package: agentPackage, options });
6732
+ }
6733
+ /**
6734
+ * Unlinks one part of the agent, or without `part` the whole agent, from its package
6735
+ * (`POST admin/agents/{id}/package/unlink`): its locks no longer hold and the next upgrade keeps it as
6736
+ * `kept-local` unless the import relinks it. Fails with `assistant-package-not-linked` for an agent
6737
+ * or part without a link and with the field error `part: invalid` for an unknown part key.
6738
+ */
6739
+ unlinkAgentPackage(agentId, request = {}) {
6740
+ return this.request('POST', `${agentPath(agentId)}/package/unlink`, request);
6741
+ }
5229
6742
  download(path) {
5230
6743
  return this.transport.download(path, 'application/x-ndjson', adminStatusCodes);
5231
6744
  }
@@ -5253,14 +6766,54 @@ function skillPath(agentId, skillId) {
5253
6766
  function triggerPath(agentId, triggerId) {
5254
6767
  return `${agentPath(agentId)}/triggers/${encodeURIComponent(triggerId)}`;
5255
6768
  }
5256
- /** Appends the filter values that are set as query parameters. */
5257
- function withQuery$1(path, filter) {
5258
- const query = new URLSearchParams();
5259
- for (const [key, value] of Object.entries(filter)) {
5260
- if (value !== undefined && value !== null && value !== '') {
5261
- query.set(key, String(value));
5262
- }
5263
- }
6769
+ function consultationPath(agentId, subjectType) {
6770
+ return `${agentPath(agentId)}/consultations/${encodeURIComponent(subjectType)}`;
6771
+ }
6772
+ function handOffPath(agentId, subjectType) {
6773
+ return `${agentPath(agentId)}/hand-offs/${encodeURIComponent(subjectType)}`;
6774
+ }
6775
+ function metadataPath(agentId, name) {
6776
+ return `${agentPath(agentId)}/metadata/${encodeURIComponent(name)}`;
6777
+ }
6778
+ /**
6779
+ * The references to agents outside an exported selection, from the export's header: a JSON array,
6780
+ * of which only entries with a safe code and string ids are kept. Without the header, none.
6781
+ */
6782
+ function packageWarnings(header) {
6783
+ if (!header) {
6784
+ return [];
6785
+ }
6786
+ let items;
6787
+ try {
6788
+ items = JSON.parse(header);
6789
+ }
6790
+ catch {
6791
+ return [];
6792
+ }
6793
+ if (!Array.isArray(items)) {
6794
+ return [];
6795
+ }
6796
+ const warnings = [];
6797
+ for (const item of items) {
6798
+ const record = item && typeof item === 'object' ? item : null;
6799
+ if (record
6800
+ && typeof record['agentId'] === 'string'
6801
+ && typeof record['part'] === 'string'
6802
+ && typeof record['referencedAgentId'] === 'string'
6803
+ && nhAssistantIsSafeCode(record['code'])) {
6804
+ warnings.push({ agentId: record['agentId'], part: record['part'], code: record['code'], referencedAgentId: record['referencedAgentId'] });
6805
+ }
6806
+ }
6807
+ return warnings;
6808
+ }
6809
+ /** Appends the filter values that are set as query parameters. */
6810
+ function withQuery$1(path, filter) {
6811
+ const query = new URLSearchParams();
6812
+ for (const [key, value] of Object.entries(filter)) {
6813
+ if (value !== undefined && value !== null && value !== '') {
6814
+ query.set(key, String(value));
6815
+ }
6816
+ }
5264
6817
  const suffix = query.toString();
5265
6818
  return suffix ? `${path}?${suffix}` : path;
5266
6819
  }
@@ -6087,18 +7640,32 @@ class NhAssistantPushService {
6087
7640
  this.subscribedState = signal(false, ...(ngDevMode ? [{ debugName: "subscribedState" }] : []));
6088
7641
  this.busyState = signal(false, ...(ngDevMode ? [{ debugName: "busyState" }] : []));
6089
7642
  this.openSubject = new Subject();
7643
+ this.openRunSubject = new Subject();
6090
7644
  this.revision = 0;
6091
7645
  this.onWorkerMessage = (event) => {
6092
7646
  const data = event.data;
6093
7647
  if (data?.type === openConversationMessage && typeof data.conversationId === 'string') {
6094
- this.openSubject.next(data.conversationId);
7648
+ this.openNotification(data.conversationId, typeof data.runId === 'string' ? data.runId : undefined);
6095
7649
  }
6096
7650
  };
6097
7651
  /** The caller's server-side choice, or `null` before it was loaded. */
6098
7652
  this.settings = this.settingsState.asReadonly();
6099
7653
  this.busy = this.busyState.asReadonly();
6100
- /** Conversations a clicked notification asks to open. */
7654
+ /**
7655
+ * Conversations a clicked notification asks to open; the assistant panel opens them. A
7656
+ * notification about the proposals of a run goes to `openRun$` instead while the application
7657
+ * subscribes to it.
7658
+ */
6101
7659
  this.openConversation$ = this.openSubject.asObservable();
7660
+ /**
7661
+ * Runs whose proposals a clicked notification is about, for the application to open its inbox of
7662
+ * the run, for example `nh-assistant-agent-inbox` with `[runId]`, which lists every proposal of the
7663
+ * run the person may decide. While the application subscribes, such a click emits the run here
7664
+ * instead of opening the conversation in the panel; without a subscriber it opens the conversation
7665
+ * as before. Subscribe in the application shell, so a notification that opens a new window finds
7666
+ * the subscription.
7667
+ */
7668
+ this.openRun$ = this.openRunSubject.asObservable();
6102
7669
  this.state = computed(() => {
6103
7670
  const settings = this.settingsState();
6104
7671
  if (!settings?.pushAvailable || !this.isSupported()) {
@@ -6118,12 +7685,25 @@ class NhAssistantPushService {
6118
7685
  navigator.serviceWorker.removeEventListener('message', this.onWorkerMessage);
6119
7686
  }
6120
7687
  this.openSubject.complete();
7688
+ this.openRunSubject.complete();
6121
7689
  });
6122
7690
  if (this.browser && this.isSupported()) {
6123
7691
  navigator.serviceWorker.addEventListener('message', this.onWorkerMessage);
6124
7692
  navigator.serviceWorker.startMessages();
6125
7693
  }
6126
7694
  }
7695
+ /**
7696
+ * Opens what a clicked notification is about: the run through `openRun$` when the notification
7697
+ * names one and the application subscribes, otherwise the conversation through
7698
+ * `openConversation$`. The bundled worker and the panel's notification fragments call it.
7699
+ */
7700
+ openNotification(conversationId, runId) {
7701
+ if (runId && this.openRunSubject.observed) {
7702
+ this.openRunSubject.next(runId);
7703
+ return;
7704
+ }
7705
+ this.openSubject.next(conversationId);
7706
+ }
6127
7707
  /**
6128
7708
  * Loads the user's choice and, when permission was granted before, renews this browser's
6129
7709
  * subscription, which also moves it to the current user and to a rotated server key.
@@ -6298,31 +7878,111 @@ function sameKey(current, expected) {
6298
7878
  /** The longest file name a file reference takes. */
6299
7879
  const NH_ASSISTANT_MAX_FILE_NAME_LENGTH = 256;
6300
7880
  const unknownMediaType = 'application/octet-stream';
6301
- /** The media types the platform names, with the extensions a file picker offers and a short label. */
7881
+ const zipAliases = ['application/zip', 'application/x-zip-compressed'];
7882
+ /**
7883
+ * The media types the platform names, with the extensions a file picker offers and a short label.
7884
+ * The extensions are the same as the server's table of upload media types.
7885
+ */
6302
7886
  const knownTypes = {
6303
7887
  'application/pdf': { extensions: ['.pdf'], label: 'PDF' },
6304
7888
  'image/png': { extensions: ['.png'], label: 'PNG' },
6305
7889
  'image/jpeg': { extensions: ['.jpg', '.jpeg'], label: 'JPEG' },
7890
+ 'image/gif': { extensions: ['.gif'], label: 'GIF' },
7891
+ 'image/webp': { extensions: ['.webp'], label: 'WebP' },
6306
7892
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': { extensions: ['.docx'], label: 'Word' },
6307
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { extensions: ['.xlsx'], label: 'Excel' }
7893
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { extensions: ['.xlsx'], label: 'Excel' },
7894
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': { extensions: ['.pptx'], label: 'PowerPoint' },
7895
+ 'application/msword': { extensions: ['.doc'], label: 'Word' },
7896
+ 'application/vnd.ms-excel': { extensions: ['.xls'], label: 'Excel' },
7897
+ 'text/csv': { extensions: ['.csv'], label: 'CSV' },
7898
+ 'text/tab-separated-values': { extensions: ['.tsv'], label: 'TSV' },
7899
+ 'text/plain': { extensions: ['.txt'], label: 'Text' },
7900
+ 'text/markdown': { extensions: ['.md', '.markdown'], label: 'Markdown' },
7901
+ 'application/json': { extensions: ['.json'], label: 'JSON' },
7902
+ 'application/xml': { extensions: ['.xml'], label: 'XML' }
6308
7903
  };
7904
+ /** Types that say nothing about the content, whatever the file's extension. */
7905
+ const genericTypes = new Set([unknownMediaType, 'binary/octet-stream', 'application/unknown']);
6309
7906
  /**
6310
- * The media type of a chosen file, lowercase and without parameters. A browser that does not know
6311
- * the type, as happens for Office documents, gives none; the extension of a known type then names
6312
- * it. Otherwise `application/octet-stream`.
7907
+ * The types browsers commonly give a file of an extension instead of its own type: the program
7908
+ * that opens it, as Windows does with `application/vnd.ms-excel` for `.csv`, an outdated name or
7909
+ * the container format.
6313
7910
  */
6314
- function nhAssistantMediaTypeOf(file) {
6315
- const declared = file.type.split(';')[0].trim().toLowerCase();
6316
- if (declared.length > 0 && declared !== unknownMediaType) {
6317
- return declared;
6318
- }
6319
- const name = file.name.toLowerCase();
7911
+ const aliasesByExtension = {
7912
+ '.csv': [
7913
+ 'application/vnd.ms-excel',
7914
+ 'application/csv',
7915
+ 'application/x-csv',
7916
+ 'text/x-csv',
7917
+ 'text/comma-separated-values',
7918
+ 'text/x-comma-separated-values'
7919
+ ],
7920
+ '.md': ['text/x-markdown'],
7921
+ '.markdown': ['text/x-markdown'],
7922
+ '.jpg': ['image/jpg', 'image/pjpeg'],
7923
+ '.jpeg': ['image/jpg', 'image/pjpeg'],
7924
+ '.png': ['image/x-png'],
7925
+ '.docx': zipAliases,
7926
+ '.xlsx': zipAliases,
7927
+ '.pptx': zipAliases,
7928
+ // Browsers send the older name of XML; an application that accepts only it keeps receiving it.
7929
+ '.xml': ['text/xml']
7930
+ };
7931
+ /** The extension of a file name in lowercase, such as `.csv`; empty without one. */
7932
+ function extensionOf(name) {
7933
+ const base = name.slice(Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')) + 1);
7934
+ const dot = base.lastIndexOf('.');
7935
+ return dot > 0 || (dot === 0 && base.length > 1) ? base.slice(dot).toLowerCase() : '';
7936
+ }
7937
+ /** The application's extensions (`AgentUploads.mappedExtensions`) whose type is accepted, lowercase. */
7938
+ function acceptedMappings(acceptedMediaTypes, mappedExtensions) {
7939
+ return (mappedExtensions ?? [])
7940
+ .map(mapping => ({ extension: mapping.extension.toLowerCase(), mediaType: mapping.mediaType.toLowerCase() }))
7941
+ .filter(mapping => acceptedMediaTypes.includes(mapping.mediaType));
7942
+ }
7943
+ /** The platform's media type of an extension, or `null`. */
7944
+ function knownMediaTypeOf(extension) {
6320
7945
  for (const [mediaType, known] of Object.entries(knownTypes)) {
6321
- if (known.extensions.some(extension => name.endsWith(extension))) {
7946
+ if (known.extensions.includes(extension)) {
6322
7947
  return mediaType;
6323
7948
  }
6324
7949
  }
6325
- return unknownMediaType;
7950
+ return null;
7951
+ }
7952
+ /**
7953
+ * The accepted type an extension names: the application's mapping, otherwise the platform's table;
7954
+ * `null` when neither names an accepted type.
7955
+ */
7956
+ function mediaTypeOfExtension(extension, acceptedMediaTypes, mappings) {
7957
+ if (extension.length === 0) {
7958
+ return null;
7959
+ }
7960
+ const mapped = mappings.find(mapping => mapping.extension === extension);
7961
+ if (mapped) {
7962
+ return mapped.mediaType;
7963
+ }
7964
+ const known = knownMediaTypeOf(extension);
7965
+ return known && acceptedMediaTypes.includes(known) ? known : null;
7966
+ }
7967
+ /**
7968
+ * The media type a chosen file uploads as, lowercase and without parameters, by the same rule as the
7969
+ * server. A browser gives no type, or a generic one, for a file its system does not know, and some
7970
+ * systems name an extension after the program that opens it, such as `application/vnd.ms-excel` for
7971
+ * a `.csv` file; the file name's extension then names the type, but only a type of
7972
+ * `acceptedMediaTypes`: the type the application mapped the extension to (`mappedExtensions`),
7973
+ * otherwise the platform's. A specific type stays as it is, so a type that is not accepted is refused
7974
+ * whatever the extension. Without a type and an accepted extension, `application/octet-stream`.
7975
+ */
7976
+ function nhAssistantMediaTypeOf(file, acceptedMediaTypes, mappedExtensions) {
7977
+ const declared = file.type.split(';')[0].trim().toLowerCase();
7978
+ const extension = extensionOf(file.name);
7979
+ if (declared.length === 0 || genericTypes.has(declared) || (aliasesByExtension[extension] ?? []).includes(declared)) {
7980
+ const derived = mediaTypeOfExtension(extension, acceptedMediaTypes, acceptedMappings(acceptedMediaTypes, mappedExtensions));
7981
+ if (derived) {
7982
+ return derived;
7983
+ }
7984
+ }
7985
+ return declared.length > 0 ? declared : unknownMediaType;
6326
7986
  }
6327
7987
  /**
6328
7988
  * The failure code of a file before it is uploaded, or `null` when it may be: the most files of one
@@ -6344,11 +8004,19 @@ function nhAssistantFileProblem(file, mediaType, uploads, attached) {
6344
8004
  }
6345
8005
  return null;
6346
8006
  }
6347
- /** The `accept` attribute of a file input for these media types: each type and its known extensions. */
6348
- function nhAssistantAcceptAttribute(mediaTypes) {
6349
- return mediaTypes
6350
- .flatMap(mediaType => [mediaType, ...(knownTypes[mediaType]?.extensions ?? [])])
6351
- .join(',');
8007
+ /**
8008
+ * The `accept` attribute of a file input for these accepted media types: each type and the extensions
8009
+ * that name it, those the application mapped to it (`mappedExtensions`) and those of the platform's
8010
+ * table that the application did not map to another accepted type.
8011
+ */
8012
+ function nhAssistantAcceptAttribute(mediaTypes, mappedExtensions) {
8013
+ const mappings = acceptedMappings(mediaTypes, mappedExtensions);
8014
+ const values = mediaTypes.flatMap(mediaType => [
8015
+ mediaType,
8016
+ ...mappings.filter(mapping => mapping.mediaType === mediaType).map(mapping => mapping.extension),
8017
+ ...(knownTypes[mediaType]?.extensions ?? []).filter(extension => !mappings.some(mapping => mapping.extension === extension))
8018
+ ]);
8019
+ return [...new Set(values)].join(',');
6352
8020
  }
6353
8021
  /** A short name of a media type, such as `PDF` or `Word`; otherwise its subtype in capitals. */
6354
8022
  function nhAssistantFileTypeLabel(mediaType) {
@@ -6473,7 +8141,11 @@ function applyNhAssistantEvent(conversation, event, clientMessageId) {
6473
8141
  };
6474
8142
  }
6475
8143
  }
6476
- /** Records the user's approval decision locally until the server state is reloaded. */
8144
+ /**
8145
+ * Records the user's approval decision locally until the server state is reloaded. A consulted
8146
+ * agent's proposal that the user left for the subject's approvers (`leave`) closes here as the server
8147
+ * closes it, rejected in this conversation, and can no longer be left; the waiting tool call goes on.
8148
+ */
6477
8149
  function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
6478
8150
  const approval = conversation.messages
6479
8151
  .flatMap(message => message.parts)
@@ -6483,7 +8155,7 @@ function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
6483
8155
  const messages = conversation.messages.map(message => ({
6484
8156
  ...message,
6485
8157
  parts: message.parts.map(part => part.type === 'approval' && part.approvalId === approvalId
6486
- ? { ...part, status: decision === 'approve' ? 'approved' : 'rejected' }
8158
+ ? decidedApproval(part, decision)
6487
8159
  : part)
6488
8160
  }));
6489
8161
  let updated = {
@@ -6497,15 +8169,24 @@ function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
6497
8169
  if (awaiting) {
6498
8170
  updated = updateToolCall(updated, awaiting.invocationId, part => ({
6499
8171
  ...part,
6500
- status: decision === 'approve' ? 'running' : 'rejected'
8172
+ status: decision === 'reject' ? 'rejected' : 'running'
6501
8173
  }));
6502
8174
  }
6503
8175
  }
6504
8176
  return updated;
6505
8177
  }
8178
+ /** An approval part after the user's decision. */
8179
+ function decidedApproval(part, decision) {
8180
+ const decided = { ...part, status: decision === 'approve' ? 'approved' : 'rejected' };
8181
+ if (decision === 'leave' && part.consultation) {
8182
+ decided.consultation = { ...part.consultation, leaveRoute: null };
8183
+ }
8184
+ return decided;
8185
+ }
6506
8186
  /**
6507
- * Applies a live update of another session: `message.created` adds a participant's message,
6508
- * the turn events behave exactly like the starting request's stream. Unknown types are ignored.
8187
+ * Applies a live update of another session: `message.created` adds a participant's or the
8188
+ * application's message once, where its sequence number puts it; the turn events behave exactly
8189
+ * like the starting request's stream. Unknown types are ignored.
6509
8190
  */
6510
8191
  function applyNhAssistantLiveEvent(conversation, event) {
6511
8192
  if (event.type === 'message.created') {
@@ -6513,7 +8194,7 @@ function applyNhAssistantLiveEvent(conversation, event) {
6513
8194
  if (!message?.id || conversation.messages.some(existing => existing.id === message.id)) {
6514
8195
  return conversation;
6515
8196
  }
6516
- return { ...conversation, messages: [...conversation.messages, message] };
8197
+ return { ...conversation, messages: insertBySequence(conversation.messages, message) };
6517
8198
  }
6518
8199
  if (!NH_ASSISTANT_SSE_EVENT_TYPES.includes(event.type)) {
6519
8200
  return conversation;
@@ -6560,6 +8241,26 @@ function conversationStatusFor(status) {
6560
8241
  return 'failed';
6561
8242
  }
6562
8243
  }
8244
+ /**
8245
+ * Places a stored message before the messages at the end that have a higher sequence number. A
8246
+ * message without a number, such as an optimistic message or the answer a running turn is still
8247
+ * writing, counts as earlier: the server numbers a turn's messages when the turn starts, so a message
8248
+ * stored during the turn follows its answer. A message without a number of its own goes last.
8249
+ */
8250
+ function insertBySequence(messages, message) {
8251
+ const sequence = message.sequence;
8252
+ let index = messages.length;
8253
+ if (typeof sequence === 'number' && sequence > 0) {
8254
+ while (index > 0) {
8255
+ const previous = messages[index - 1].sequence;
8256
+ if (typeof previous !== 'number' || previous <= sequence) {
8257
+ break;
8258
+ }
8259
+ index--;
8260
+ }
8261
+ }
8262
+ return [...messages.slice(0, index), message, ...messages.slice(index)];
8263
+ }
6563
8264
  function createAssistantMessage(id) {
6564
8265
  return { id, role: 'assistant', createdAt: new Date().toISOString(), parts: [] };
6565
8266
  }
@@ -6815,6 +8516,8 @@ const NH_ASSISTANT_NO_ANSWER_NOTICE_CODE = 'assistant-no-answer';
6815
8516
  */
6816
8517
  const NH_ASSISTANT_MESSAGE_QUEUED_NOTICE_CODE = 'assistant-message-queued';
6817
8518
  const fourEyesRequiredCode = 'assistant-four-eyes-required';
8519
+ /** A consultation's proposal in the consulted thread that the person who asked decides in their own chat. */
8520
+ const askerDecidesCode = 'assistant-consult-asker-decides';
6818
8521
  /** True when a conversation has messages the caller has not read. A running turn is not unread yet. */
6819
8522
  function nhAssistantIsUnread(summary) {
6820
8523
  if (summary.status === 'running' || summary.lastReadSequence === undefined) {
@@ -6928,6 +8631,12 @@ class NhAssistantStore {
6928
8631
  /** Non-blocking remark about the latest completed turn; shown only while no error is shown. */
6929
8632
  this.notice = computed(() => this.activeSession()?.notice ?? null, ...(ngDevMode ? [{ debugName: "notice" }] : []));
6930
8633
  this.lastUsage = computed(() => this.activeSession()?.lastUsage ?? null, ...(ngDevMode ? [{ debugName: "lastUsage" }] : []));
8634
+ /**
8635
+ * The answer the running turn of the open conversation writes, while this tab streams the turn or
8636
+ * follows it live; `null` otherwise. Pass it to `nh-assistant-thread` as `writingMessageId`, so
8637
+ * the working indicator stays under that answer when a message arrives after it during the turn.
8638
+ */
8639
+ this.writingMessageId = computed(() => this.activeSession()?.writingMessageId ?? null, ...(ngDevMode ? [{ debugName: "writingMessageId" }] : []));
6931
8640
  /** Text of a message the server did not accept, so the composer can offer it again. */
6932
8641
  this.restoredDraft = this.restoredDraftState.asReadonly();
6933
8642
  /** Page context that the next message would send, for the transparency chip. */
@@ -7012,7 +8721,7 @@ class NhAssistantStore {
7012
8721
  const decision = decisions.get(approval.approvalId);
7013
8722
  rights.set(approval.approvalId, {
7014
8723
  canDecide: decision?.canDecide === true,
7015
- waitingFor: decision?.reasonCode === fourEyesRequiredCode ? 'other-approver' : 'approver',
8724
+ waitingFor: waitingForOf(decision?.reasonCode),
7016
8725
  decisionOwner: null
7017
8726
  });
7018
8727
  }
@@ -7515,8 +9224,11 @@ class NhAssistantStore {
7515
9224
  /**
7516
9225
  * Approves or rejects an approval of the open conversation: `approvalId`, or the pending approval
7517
9226
  * when it is left out. A proposal of an agent's run is decided with its proposal hash through the
7518
- * agent-run endpoint; other approvals resume their turn as a stream. Ignores calls the current
7519
- * user may not make and repeated calls while a decision is in flight.
9227
+ * agent-run endpoint; other approvals resume their turn as a stream. `leave` leaves a consulted
9228
+ * agent's proposal that has a `consultation.leaveRoute` for the subject's approvers; it resumes the
9229
+ * turn like a decision and reads the conversation again, which then names the proposal that waits
9230
+ * at the subject. Ignores calls the current user may not make, `leave` for other approvals and
9231
+ * repeated calls while a decision is in flight.
7520
9232
  */
7521
9233
  decide(decision, reason, approvalId) {
7522
9234
  const session = this.activeSession();
@@ -7530,9 +9242,15 @@ class NhAssistantStore {
7530
9242
  if (!approval || this.approvalRights().get(approval.approvalId)?.canDecide !== true) {
7531
9243
  return;
7532
9244
  }
9245
+ if (decision === 'leave' && !approval.consultation?.leaveRoute) {
9246
+ // Only a consulted agent's proposal with a route at the subject can be left for its approvers.
9247
+ return;
9248
+ }
7533
9249
  const proposal = conversation.thread?.decisions.find(item => item.approvalId === approval.approvalId);
7534
9250
  if (proposal?.runId) {
7535
- void this.decideProposal(conversation.id, approval, decision, reason);
9251
+ if (decision !== 'leave') {
9252
+ void this.decideProposal(conversation.id, approval, decision, reason);
9253
+ }
7536
9254
  return;
7537
9255
  }
7538
9256
  if (conversation.pendingApproval?.approvalId !== approval.approvalId) {
@@ -7564,7 +9282,8 @@ class NhAssistantStore {
7564
9282
  },
7565
9283
  complete: () => {
7566
9284
  this.patchSession(conversationId, current => ({ ...current, deciding: false }));
7567
- this.afterTurn(conversationId, failed);
9285
+ // A proposal left for the subject's approvers names the one that waits there only once read again.
9286
+ this.afterTurn(conversationId, failed || decision === 'leave');
7568
9287
  }
7569
9288
  });
7570
9289
  }
@@ -7638,7 +9357,7 @@ class NhAssistantStore {
7638
9357
  if (this.sessionsState().get(conversationId)?.streaming) {
7639
9358
  this.streams.get(conversationId)?.unsubscribe();
7640
9359
  this.streams.delete(conversationId);
7641
- this.patchSession(conversationId, current => ({ ...current, streaming: false, deciding: false }));
9360
+ this.patchSession(conversationId, current => ({ ...current, streaming: false, deciding: false, writingMessageId: null }));
7642
9361
  void this.reloadSession(conversationId);
7643
9362
  }
7644
9363
  }, cancelGracePeriodMs));
@@ -7811,7 +9530,7 @@ class NhAssistantStore {
7811
9530
  const added = [];
7812
9531
  const pending = [];
7813
9532
  for (const file of files) {
7814
- const mediaType = nhAssistantMediaTypeOf(file);
9533
+ const mediaType = nhAssistantMediaTypeOf(file, uploads.acceptedMediaTypes, uploads.mappedExtensions);
7815
9534
  const problem = nhAssistantFileProblem(file, mediaType, uploads, attached);
7816
9535
  const attachment = {
7817
9536
  id: createClientMessageId(),
@@ -8122,12 +9841,12 @@ class NhAssistantStore {
8122
9841
  }
8123
9842
  runStream(conversationId, stream, handlers) {
8124
9843
  this.streams.get(conversationId)?.unsubscribe();
8125
- this.patchSession(conversationId, session => ({ ...session, streaming: true }));
9844
+ this.patchSession(conversationId, session => ({ ...session, streaming: true, writingMessageId: null }));
8126
9845
  const finish = () => {
8127
9846
  clearTimeout(this.cancelTimers.get(conversationId));
8128
9847
  this.cancelTimers.delete(conversationId);
8129
9848
  this.streams.delete(conversationId);
8130
- this.patchSession(conversationId, session => ({ ...session, streaming: false }));
9849
+ this.patchSession(conversationId, session => ({ ...session, streaming: false, writingMessageId: null }));
8131
9850
  handlers.complete();
8132
9851
  };
8133
9852
  const subscription = stream.subscribe({
@@ -8172,7 +9891,7 @@ class NhAssistantStore {
8172
9891
  notice = completionNotice(conversation, event.data.errorCode);
8173
9892
  }
8174
9893
  }
8175
- return { ...session, conversation, error, notice, lastUsage };
9894
+ return { ...session, conversation, error, notice, lastUsage, writingMessageId: writingAnswerAfter(session.writingMessageId, event) };
8176
9895
  });
8177
9896
  }
8178
9897
  afterTurn(conversationId, reload) {
@@ -8260,7 +9979,8 @@ class NhAssistantStore {
8260
9979
  const wasRunning = session.conversation.status === 'running';
8261
9980
  this.patchSession(change.conversationId, current => ({
8262
9981
  ...current,
8263
- conversation: applyNhAssistantConversationChange(current.conversation, change)
9982
+ conversation: applyNhAssistantConversationChange(current.conversation, change),
9983
+ writingMessageId: change.status === 'running' ? current.writingMessageId : null
8264
9984
  }));
8265
9985
  if (wasRunning && change.status !== 'running') {
8266
9986
  // Another session ended its turn; the snapshot holds the exact answer and approvals.
@@ -8283,18 +10003,27 @@ class NhAssistantStore {
8283
10003
  this.draftErrorState.set(clientError(NhAssistantClientErrorCodes.conversationRemoved));
8284
10004
  }
8285
10005
  }
10006
+ /**
10007
+ * Applies a live turn event or message to a conversation this tab shows. While the tab streams a
10008
+ * turn of the conversation, its stream brings the turn's events and its own message, so it applies
10009
+ * only messages that others stored meanwhile: the application's and other people's.
10010
+ */
8286
10011
  onLiveEvent(event) {
8287
10012
  const session = this.sessionsState().get(event.conversationId);
8288
10013
  if (event.type === 'turn.started') {
8289
10014
  this.patchSummary(event.conversationId, summary => ({ ...summary, status: 'running', activeActorId: event.actorId }));
8290
10015
  }
8291
- if (!session || session.streaming) {
8292
- // This tab streams the turn itself, or does not show the conversation.
10016
+ if (!session) {
10017
+ return;
10018
+ }
10019
+ if (session.streaming && !isMessageOfOthers(session.conversation, event)) {
8293
10020
  return;
8294
10021
  }
8295
10022
  this.patchSession(event.conversationId, current => ({
8296
10023
  ...current,
8297
- conversation: applyNhAssistantLiveEvent(current.conversation, event)
10024
+ conversation: applyNhAssistantLiveEvent(current.conversation, event),
10025
+ // A turn this tab follows live names its answer; while the tab streams, its stream does.
10026
+ writingMessageId: current.streaming ? current.writingMessageId : writingAnswerAfter(current.writingMessageId, event)
8298
10027
  }));
8299
10028
  }
8300
10029
  /**
@@ -8346,8 +10075,8 @@ class NhAssistantStore {
8346
10075
  const next = new Map(sessions);
8347
10076
  const existing = next.get(conversation.id);
8348
10077
  next.set(conversation.id, existing
8349
- ? { ...existing, conversation }
8350
- : { conversation, streaming: false, deciding: false, error: null, notice: null, lastUsage: null });
10078
+ ? { ...existing, conversation, writingMessageId: conversation.status === 'running' ? existing.writingMessageId : null }
10079
+ : { conversation, streaming: false, deciding: false, error: null, notice: null, lastUsage: null, writingMessageId: null });
8351
10080
  if (next.size > maxSessions) {
8352
10081
  const activeId = this.activeIdState();
8353
10082
  for (const [id, session] of next) {
@@ -8476,16 +10205,59 @@ function messageQueuedNotice(fileCount) {
8476
10205
  messageKey: fileCount > 0 ? 'nh-assistant.notices.message-queued-with-files' : 'nh-assistant.notices.message-queued'
8477
10206
  };
8478
10207
  }
8479
- /** A completed turn with a server code, or without any answer text, explains itself with a notice. */
10208
+ /**
10209
+ * The answer a turn writes after `event`: `turn.started` names it, `turn.completed` and `error` end
10210
+ * the turn, and every other event leaves it as it is.
10211
+ */
10212
+ function writingAnswerAfter(current, event) {
10213
+ switch (event.type) {
10214
+ case 'turn.started':
10215
+ return event.data?.assistantMessageId ?? null;
10216
+ case 'turn.completed':
10217
+ case 'error':
10218
+ return null;
10219
+ default:
10220
+ return current;
10221
+ }
10222
+ }
10223
+ /**
10224
+ * A completed turn with a server code, or without any answer text, explains itself with a notice.
10225
+ * Another person's message that arrived while the turn ran does not end this tab's turn.
10226
+ */
8480
10227
  function completionNotice(conversation, errorCode) {
8481
10228
  if (errorCode) {
8482
10229
  return clientError(errorCode);
8483
10230
  }
8484
- if (!nhAssistantLatestTurnHasText(conversation)) {
10231
+ const ownTurn = { ...conversation, messages: conversation.messages.filter(message => !isOtherPersonsMessage(conversation, message)) };
10232
+ if (!nhAssistantLatestTurnHasText(ownTurn)) {
8485
10233
  return { code: NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, messageKey: 'nh-assistant.notices.no-answer' };
8486
10234
  }
8487
10235
  return null;
8488
10236
  }
10237
+ /**
10238
+ * True for a live `message.created` of a message that this tab did not write: the application's, or
10239
+ * a user message of another writer. A user message is this tab's own when the current user wrote it,
10240
+ * and when the tab does not know the current user, so a turn's own message never shows twice.
10241
+ */
10242
+ function isMessageOfOthers(conversation, event) {
10243
+ if (event.type !== 'message.created') {
10244
+ return false;
10245
+ }
10246
+ const message = event.data;
10247
+ if (!message?.id) {
10248
+ return false;
10249
+ }
10250
+ if (message.role === 'application') {
10251
+ return true;
10252
+ }
10253
+ return message.role === 'user' && isOtherPersonsMessage(conversation, message, event.actorId);
10254
+ }
10255
+ /** True for a user message that a known writer other than the current user wrote. */
10256
+ function isOtherPersonsMessage(conversation, message, fallbackAuthor) {
10257
+ const author = message.authorActorId ?? fallbackAuthor;
10258
+ const currentActorId = conversation.currentActorId;
10259
+ return message.role === 'user' && !!author && !!currentActorId && author !== currentActorId;
10260
+ }
8489
10261
  /** The approvals of a conversation that still wait for a decision, each once. */
8490
10262
  /** Every approval of the conversation once, by approval id; later parts win. */
8491
10263
  function approvalParts(conversation) {
@@ -8513,6 +10285,20 @@ function pendingApprovalParts(conversation) {
8513
10285
  }
8514
10286
  return [...approvals.values()];
8515
10287
  }
10288
+ /**
10289
+ * Who decides an open proposal of an agent thread the caller may not decide, by the server's reason:
10290
+ * the person who consulted the agent, another approver for four-eyes, otherwise an approver.
10291
+ */
10292
+ function waitingForOf(reasonCode) {
10293
+ switch (reasonCode) {
10294
+ case askerDecidesCode:
10295
+ return 'asker';
10296
+ case fourEyesRequiredCode:
10297
+ return 'other-approver';
10298
+ default:
10299
+ return 'approver';
10300
+ }
10301
+ }
8516
10302
  /**
8517
10303
  * Shows the decision of an agent's proposal until the reloaded snapshot arrives: the approval's new
8518
10304
  * status, no open decision for it and, for the approval the conversation waited for, no pending one.
@@ -9190,6 +10976,7 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
9190
10976
  'assistant-run-settings-in-code',
9191
10977
  'assistant-run-settings-in-use',
9192
10978
  'assistant-skill-candidate-not-found',
10979
+ 'assistant-trigger-candidate-not-found',
9193
10980
  'assistant-skill-version-gone',
9194
10981
  'assistant-account-search-unavailable',
9195
10982
  'assistant-handoff-unavailable',
@@ -9246,6 +11033,26 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
9246
11033
  'assistant-consult-timeout',
9247
11034
  'assistant-consult-failed',
9248
11035
  'assistant-consult-read-only',
11036
+ 'assistant-consult-tool-not-selected',
11037
+ 'assistant-consult-proposal-refused',
11038
+ 'assistant-consult-asker-decides',
11039
+ 'assistant-consult-route-not-allowed',
11040
+ 'assistant-consult-proposal-moved',
11041
+ // Consultations defined as data in the administration
11042
+ 'assistant-consultation-in-code',
11043
+ 'assistant-consultation-not-found',
11044
+ 'assistant-consultations-not-allowed',
11045
+ // Hand-offs defined as data and shadow variants created in the administration
11046
+ 'assistant-handoffs-not-allowed',
11047
+ 'assistant-handoff-in-code',
11048
+ 'assistant-handoff-not-found',
11049
+ 'assistant-shadow-variants-not-allowed',
11050
+ // Agent packages: their format and the parts they lock
11051
+ 'assistant-package-format-unsupported',
11052
+ 'assistant-package-too-large',
11053
+ 'assistant-package-refused',
11054
+ 'assistant-package-locked',
11055
+ 'assistant-package-not-linked',
9249
11056
  // Preferences and administration
9250
11057
  'assistant-validation',
9251
11058
  'assistant-instructions-too-long',
@@ -9256,6 +11063,13 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
9256
11063
  'assistant-agent-exists',
9257
11064
  'assistant-code-agent-not-deletable',
9258
11065
  'assistant-agent-not-code',
11066
+ // Agent metadata registered by the application
11067
+ 'assistant-metadata-entry-not-found',
11068
+ 'assistant-metadata-read-only',
11069
+ // Instructions from the application's text assets
11070
+ 'assistant-instructions-asset-not-found',
11071
+ 'assistant-instructions-asset-unavailable',
11072
+ 'assistant-agent-instructions-unavailable',
9259
11073
  'assistant-mcp-server-not-found',
9260
11074
  'assistant-mcp-server-exists',
9261
11075
  'assistant-mcp-tool-not-found',
@@ -9300,6 +11114,12 @@ const NH_ASSISTANT_ERROR_CODES = [
9300
11114
  const NH_ASSISTANT_JOIN_FRAGMENT = 'nh-assistant-join';
9301
11115
  /** Fragment a clicked notification opens: `#nh-assistant-conversation=<id>`. */
9302
11116
  const NH_ASSISTANT_CONVERSATION_FRAGMENT = 'nh-assistant-conversation';
11117
+ /**
11118
+ * Fragment a clicked notification about the proposals of a run opens:
11119
+ * `#nh-assistant-run=<runId>.<conversationId>`. The run goes to `NhAssistantPushService.openRun$`
11120
+ * while the application subscribes; otherwise the panel opens the conversation.
11121
+ */
11122
+ const NH_ASSISTANT_RUN_FRAGMENT = 'nh-assistant-run';
9303
11123
  /** Builds the default invitation link: the current page with the join fragment. */
9304
11124
  function nhAssistantShareLink(conversationId, token) {
9305
11125
  const location = globalThis.location;
@@ -9337,7 +11157,8 @@ const builtInPaths = {
9337
11157
  bell: 'M6 16V11a6 6 0 0 1 12 0v5l2 2H4zM10 20a2 2 0 0 0 4 0',
9338
11158
  leave: 'M10 4H5v16h5M14 8l4 4-4 4M18 12H9',
9339
11159
  attach: 'M19 11.5l-7.6 7.6a4.6 4.6 0 0 1-6.5-6.5l8.3-8.3a3 3 0 0 1 4.3 4.3l-8.2 8.2a1.5 1.5 0 0 1-2.1-2.1l7.4-7.4',
9340
- file: 'M6 3h8l4 4v14H6zM14 3v4h4'
11160
+ file: 'M6 3h8l4 4v14H6zM14 3v4h4',
11161
+ lock: 'M6 11h12v9H6zM8.5 11V8a3.5 3.5 0 0 1 7 0v3M12 15v2'
9341
11162
  };
9342
11163
  /** Decorative icon. The surrounding control provides the accessible name. */
9343
11164
  class NhAssistantIconComponent {
@@ -9722,8 +11543,11 @@ class NhAssistantComposerComponent {
9722
11543
  /** True while a file of the next message still uploads. */
9723
11544
  this.uploading = computed(() => this.attachments().some(attachment => attachment.state === 'uploading'), ...(ngDevMode ? [{ debugName: "uploading" }] : []));
9724
11545
  this.canSend = computed(() => !this.disabled() && !this.sendDisabled() && this.length() > 0 && !this.tooLong() && !this.uploading(), ...(ngDevMode ? [{ debugName: "canSend" }] : []));
9725
- /** The `accept` attribute of the file input. */
9726
- this.accept = computed(() => nhAssistantAcceptAttribute(this.uploads()?.acceptedMediaTypes ?? []), ...(ngDevMode ? [{ debugName: "accept" }] : []));
11546
+ /** The `accept` attribute of the file input, with the extensions the application mapped. */
11547
+ this.accept = computed(() => {
11548
+ const uploads = this.uploads();
11549
+ return nhAssistantAcceptAttribute(uploads?.acceptedMediaTypes ?? [], uploads?.mappedExtensions);
11550
+ }, ...(ngDevMode ? [{ debugName: "accept" }] : []));
9727
11551
  /** The values the attachment texts name: the accepted types, the largest size and the most files. */
9728
11552
  this.uploadParams = computed(() => {
9729
11553
  const uploads = this.uploads();
@@ -10342,6 +12166,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
10342
12166
  args: [{ name: 'nhAssistantMarkdown', standalone: true }]
10343
12167
  }] });
10344
12168
 
12169
+ /**
12170
+ * The name of a subject with the name of its type, linked to where the application shows the
12171
+ * subject (internal). The host's `subjectLinks` builder wins over the server's link; a link within
12172
+ * the application navigates through the router, an `https` link leaves it, and anything else shows
12173
+ * no link. Ctrl-, Cmd-, Shift- and middle-clicks keep the browser's behavior, such as a new tab.
12174
+ * A name that already says the type, as "The whole application" does for the application as a
12175
+ * whole, is shown once.
12176
+ */
12177
+ class NhAssistantSubjectLinkComponent {
12178
+ constructor() {
12179
+ this.config = inject(NH_ASSISTANT_CONFIG, { optional: true });
12180
+ this.router = inject(Router, { optional: true });
12181
+ this.locationStrategy = inject(LocationStrategy, { optional: true });
12182
+ this.injector = inject(EnvironmentInjector);
12183
+ this.subjectType = input.required(...(ngDevMode ? [{ debugName: "subjectType" }] : []));
12184
+ this.subjectId = input.required(...(ngDevMode ? [{ debugName: "subjectId" }] : []));
12185
+ /** The text people read, usually the subject's display name. */
12186
+ this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
12187
+ /** The name of the subject type, such as "Project"; nothing is shown without one. */
12188
+ this.typeName = input(null, ...(ngDevMode ? [{ debugName: "typeName" }] : []));
12189
+ /** The server's link to the subject. */
12190
+ this.link = input(null, ...(ngDevMode ? [{ debugName: "link" }] : []));
12191
+ /** The type's name, unless the subject's name is the type's name itself, as for the whole application. */
12192
+ this.shownTypeName = computed(() => {
12193
+ const type = this.typeName()?.trim();
12194
+ if (!type) {
12195
+ return null;
12196
+ }
12197
+ return type.toLocaleLowerCase() === this.label().trim().toLocaleLowerCase() ? null : type;
12198
+ }, ...(ngDevMode ? [{ debugName: "shownTypeName" }] : []));
12199
+ this.target = computed(() => {
12200
+ const builder = this.config?.subjectLinks?.[this.subjectType()];
12201
+ const subject = { type: this.subjectType(), id: this.subjectId() };
12202
+ const custom = builder ? runInInjectionContext(this.injector, () => builder(subject)) : undefined;
12203
+ if (custom === null) {
12204
+ return null;
12205
+ }
12206
+ if (Array.isArray(custom)) {
12207
+ return this.routeTarget(this.router ? this.router.serializeUrl(this.router.createUrlTree([...custom])) : null);
12208
+ }
12209
+ return this.urlTarget(typeof custom === 'string' ? custom : this.link() ?? null);
12210
+ }, ...(ngDevMode ? [{ debugName: "target" }] : []));
12211
+ }
12212
+ open(event, target) {
12213
+ nhAssistantOpenLink(event, target, this.router);
12214
+ }
12215
+ urlTarget(url) {
12216
+ return nhAssistantLinkTarget(url, this.router, this.locationStrategy);
12217
+ }
12218
+ routeTarget(url) {
12219
+ return nhAssistantRouteTarget(url, this.router, this.locationStrategy);
12220
+ }
12221
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12222
+ 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: `
12223
+ @if (shownTypeName(); as type) {
12224
+ <!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
12225
+ <span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
12226
+ }
12227
+ @if (target(); as link) {
12228
+ <a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
12229
+ } @else {
12230
+ <span class="nh-assistant-subject-name">{{ label() }}</span>
12231
+ }
12232
+ `, 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 }); }
12233
+ }
12234
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, decorators: [{
12235
+ type: Component,
12236
+ args: [{ selector: 'nh-assistant-subject-link', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
12237
+ @if (shownTypeName(); as type) {
12238
+ <!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
12239
+ <span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
12240
+ }
12241
+ @if (target(); as link) {
12242
+ <a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
12243
+ } @else {
12244
+ <span class="nh-assistant-subject-name">{{ label() }}</span>
12245
+ }
12246
+ `, 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"] }]
12247
+ }], 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 }] }] } });
12248
+ /**
12249
+ * Where a link the server sent leads (internal): a path within the application, which the router
12250
+ * opens, an `https` address elsewhere, or `null` for anything else, so no other scheme reaches an
12251
+ * anchor. Subject links and the links of application messages follow this rule.
12252
+ */
12253
+ function nhAssistantLinkTarget(url, router, locationStrategy) {
12254
+ if (!url) {
12255
+ return null;
12256
+ }
12257
+ if (url.startsWith('/') && !url.startsWith('//') && !url.startsWith('/\\')) {
12258
+ return nhAssistantRouteTarget(url, router, locationStrategy);
12259
+ }
12260
+ return /^https:\/\/[^/\\\s]+/i.test(url) ? { href: url, route: null } : null;
12261
+ }
12262
+ /** A route of the application as the browser shows it and as the router opens it (internal). */
12263
+ function nhAssistantRouteTarget(url, router, locationStrategy) {
12264
+ if (!url) {
12265
+ return null;
12266
+ }
12267
+ return {
12268
+ href: locationStrategy ? locationStrategy.prepareExternalUrl(url) : url,
12269
+ route: router ? url : null
12270
+ };
12271
+ }
12272
+ /**
12273
+ * Opens a route of the application through the router on a plain click (internal). Ctrl-, Cmd-,
12274
+ * Shift-, Alt- and middle-clicks, and addresses outside the application, keep the browser's behavior.
12275
+ */
12276
+ function nhAssistantOpenLink(event, target, router) {
12277
+ if (!target.route || !router || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
12278
+ return;
12279
+ }
12280
+ event.preventDefault();
12281
+ void router.navigateByUrl(target.route);
12282
+ }
12283
+
12284
+ /**
12285
+ * The link of a message the application posted (internal): a path within the application opens
12286
+ * through the router, an `https` address leaves it, and anything else shows nothing, by the same rule
12287
+ * as subject links.
12288
+ */
12289
+ class NhAssistantMessageLinkComponent {
12290
+ constructor() {
12291
+ this.router = inject(Router, { optional: true });
12292
+ this.locationStrategy = inject(LocationStrategy, { optional: true });
12293
+ /** A path within the application or an `https` address. */
12294
+ this.url = input.required(...(ngDevMode ? [{ debugName: "url" }] : []));
12295
+ /** The text people read. */
12296
+ this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
12297
+ this.target = computed(() => nhAssistantLinkTarget(this.url(), this.router, this.locationStrategy), ...(ngDevMode ? [{ debugName: "target" }] : []));
12298
+ }
12299
+ open(event, target) {
12300
+ nhAssistantOpenLink(event, target, this.router);
12301
+ }
12302
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantMessageLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12303
+ 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: `
12304
+ @if (target(); as link) {
12305
+ <a class="nh-assistant-message-link" [href]="link.href" (click)="open($event, link)">
12306
+ <nh-assistant-icon name="link" />{{ label() }}
12307
+ </a>
12308
+ }
12309
+ `, 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 }); }
12310
+ }
12311
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantMessageLinkComponent, decorators: [{
12312
+ type: Component,
12313
+ args: [{ selector: 'nh-assistant-message-link', standalone: true, imports: [NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
12314
+ @if (target(); as link) {
12315
+ <a class="nh-assistant-message-link" [href]="link.href" (click)="open($event, link)">
12316
+ <nh-assistant-icon name="link" />{{ label() }}
12317
+ </a>
12318
+ }
12319
+ `, 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"] }]
12320
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }] } });
12321
+
10345
12322
  /**
10346
12323
  * Groups consecutive tool calls of a message, and consecutive files. Text and approvals break a
10347
12324
  * group, so an approval always stays visible. A tool group's key is its first invocation id, so it
@@ -10526,10 +12503,16 @@ function formatNhAssistantCountdown(milliseconds) {
10526
12503
  * proposed arguments and a countdown to expiry. A decision is emitted at most once until
10527
12504
  * the host reports that it is no longer deciding. After the user rejected an agent's proposal
10528
12505
  * (`canGiveFeedback`), a low-key action asks what was wrong. A proposal that closed because it no
10529
- * longer fits shows why, such as "Already done", with the application's explanation.
12506
+ * longer fits shows why, such as "Already done", with the application's explanation. A proposal of
12507
+ * another agent the assistant consulted (`consultation`) names that agent and the subject, offers the
12508
+ * agent's answer and says that approving runs it with the user's own rights; with a
12509
+ * `consultation.leaveRoute` a third action leaves it for the subject's approvers (`leave`), after which
12510
+ * the card says that it waits for them.
10530
12511
  */
10531
12512
  class NhAssistantApprovalCardComponent {
10532
12513
  constructor() {
12514
+ /** Names the consulted agent as the status does; the card also works outside `provideNhAssistant`. */
12515
+ this.store = inject(NhAssistantStore, { optional: true });
10533
12516
  this.approval = input.required(...(ngDevMode ? [{ debugName: "approval" }] : []));
10534
12517
  /** True while the host submits a decision; disables both buttons. */
10535
12518
  this.deciding = input(false, ...(ngDevMode ? [{ debugName: "deciding" }] : []));
@@ -10554,6 +12537,8 @@ class NhAssistantApprovalCardComponent {
10554
12537
  this.decide = output();
10555
12538
  this.now = signal(Date.now(), ...(ngDevMode ? [{ debugName: "now" }] : []));
10556
12539
  this.submitted = signal(false, ...(ngDevMode ? [{ debugName: "submitted" }] : []));
12540
+ /** The decision this card sent last, so a proposal left for the approvers reads as such at once. */
12541
+ this.chosen = signal(null, ...(ngDevMode ? [{ debugName: "chosen" }] : []));
10557
12542
  /** The feedback question is expanded. */
10558
12543
  this.feedbackOpen = signal(false, ...(ngDevMode ? [{ debugName: "feedbackOpen" }] : []));
10559
12544
  /** The feedback was stored; the question thanks the person and the action disappears. */
@@ -10563,11 +12548,45 @@ class NhAssistantApprovalCardComponent {
10563
12548
  this.expired = computed(() => this.approval().status === 'expired' ||
10564
12549
  (this.approval().status === 'pending' && this.remainingMs() <= 0), ...(ngDevMode ? [{ debugName: "expired" }] : []));
10565
12550
  this.effectiveStatus = computed(() => this.expired() ? 'expired' : this.approval().status, ...(ngDevMode ? [{ debugName: "effectiveStatus" }] : []));
12551
+ /** Where a consulted agent's proposal comes from; `null` for the conversation's own proposals. */
12552
+ this.consultation = computed(() => this.approval().consultation ?? null, ...(ngDevMode ? [{ debugName: "consultation" }] : []));
12553
+ /**
12554
+ * The translation keys of the consulted agent's name: the name the assistant's status gives it,
12555
+ * then the convention `nh-assistant.agents.{id}.name`; the id when neither translates.
12556
+ */
12557
+ this.consultedAgentKeys = computed(() => {
12558
+ const consultation = this.consultation();
12559
+ if (!consultation) {
12560
+ return [];
12561
+ }
12562
+ const convention = `nh-assistant.agents.${consultation.agentId}.name`;
12563
+ const known = this.store?.agents().find(agent => agent.id === consultation.agentId)?.displayNameKey;
12564
+ return known && known !== convention ? [known, convention] : [convention];
12565
+ }, ...(ngDevMode ? [{ debugName: "consultedAgentKeys" }] : []));
12566
+ /** The subject the consulted agent was asked about, by name or else by id. */
12567
+ this.consultedSubject = computed(() => {
12568
+ const consultation = this.consultation();
12569
+ return consultation ? consultation.subjectDisplayName ?? consultation.subjectId : null;
12570
+ }, ...(ngDevMode ? [{ debugName: "consultedSubject" }] : []));
12571
+ /**
12572
+ * The user left the consulted agent's proposal for the subject's approvers: the server names the
12573
+ * proposal that waits there, or this card just sent the decision and it was accepted.
12574
+ */
12575
+ this.leftForApprovers = computed(() => {
12576
+ const consultation = this.consultation();
12577
+ return consultation !== null
12578
+ && (!!consultation.movedToApprovalId || (this.chosen() === 'leave' && this.approval().status !== 'pending'));
12579
+ }, ...(ngDevMode ? [{ debugName: "leftForApprovers" }] : []));
12580
+ /** The status the card shows: `moved` for a proposal left for the subject's approvers. */
12581
+ this.shownStatus = computed(() => this.leftForApprovers() ? 'moved' : this.effectiveStatus(), ...(ngDevMode ? [{ debugName: "shownStatus" }] : []));
10566
12582
  /**
10567
12583
  * Translation key of the status: the kind of a stale proposal, "replaced" for a superseded one,
10568
- * otherwise the status itself.
12584
+ * "left for approvers" for a consulted agent's proposal the user left, otherwise the status itself.
10569
12585
  */
10570
12586
  this.statusKey = computed(() => {
12587
+ if (this.leftForApprovers()) {
12588
+ return 'nh-assistant.approval.consultation.moved-status';
12589
+ }
10571
12590
  const kind = this.approval().staleKind;
10572
12591
  if (this.effectiveStatus() === 'stale' && kind) {
10573
12592
  return `nh-assistant.approval.stale-kind.${kind}`;
@@ -10581,8 +12600,11 @@ class NhAssistantApprovalCardComponent {
10581
12600
  /** The application's explanation of a stale proposal, such as who already did the work. */
10582
12601
  this.staleExplanation = computed(() => this.effectiveStatus() === 'stale' ? this.approval().staleExplanation ?? null : null, ...(ngDevMode ? [{ debugName: "staleExplanation" }] : []));
10583
12602
  this.actionable = computed(() => this.effectiveStatus() === 'pending', ...(ngDevMode ? [{ debugName: "actionable" }] : []));
10584
- this.succeeded = computed(() => ['approved', 'executing', 'executed', 'resolved'].includes(this.effectiveStatus()), ...(ngDevMode ? [{ debugName: "succeeded" }] : []));
12603
+ this.succeeded = computed(() => ['approved', 'executing', 'awaiting-application', 'executed', 'resolved'].includes(this.effectiveStatus()), ...(ngDevMode ? [{ debugName: "succeeded" }] : []));
10585
12604
  this.disabled = computed(() => !this.actionable() || !this.canDecide() || this.deciding() || this.submitted(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
12605
+ /** The route at the subject the pending proposal may be left for; `null` when it can only be approved or rejected. */
12606
+ this.leaveRoute = computed(() => this.actionable() ? this.consultation()?.leaveRoute ?? null : null, ...(ngDevMode ? [{ debugName: "leaveRoute" }] : []));
12607
+ this.leaveHintId = `nh-assistant-approval-leave-${nextId$5++}`;
10586
12608
  this.countdown = computed(() => formatNhAssistantCountdown(this.remainingMs()), ...(ngDevMode ? [{ debugName: "countdown" }] : []));
10587
12609
  this.presentedSummary = computed(() => this.approval().presentation?.summary ?? null, ...(ngDevMode ? [{ debugName: "presentedSummary" }] : []));
10588
12610
  this.feedbackAvailable = computed(() => this.canGiveFeedback() && this.effectiveStatus() === 'rejected', ...(ngDevMode ? [{ debugName: "feedbackAvailable" }] : []));
@@ -10595,6 +12617,8 @@ class NhAssistantApprovalCardComponent {
10595
12617
  return 'nh-assistant.approval.waiting-for-approver';
10596
12618
  case 'other-approver':
10597
12619
  return 'nh-assistant.approval.waiting-for-other-approver';
12620
+ case 'asker':
12621
+ return 'nh-assistant.approval.waiting-for-asker';
10598
12622
  default:
10599
12623
  return this.decisionOwner() ? 'nh-assistant.approval.waiting-for' : 'nh-assistant.approval.waiting-for-participant';
10600
12624
  }
@@ -10620,11 +12644,13 @@ class NhAssistantApprovalCardComponent {
10620
12644
  }
10621
12645
  });
10622
12646
  }
12647
+ /** Emits a decision; `leave` only for a consulted agent's proposal with a route at the subject. */
10623
12648
  choose(decision) {
10624
- if (this.disabled()) {
12649
+ if (this.disabled() || (decision === 'leave' && this.leaveRoute() === null)) {
10625
12650
  return;
10626
12651
  }
10627
12652
  this.submitted.set(true);
12653
+ this.chosen.set(decision);
10628
12654
  this.decide.emit(decision);
10629
12655
  }
10630
12656
  toggleFeedback() {
@@ -10639,13 +12665,13 @@ class NhAssistantApprovalCardComponent {
10639
12665
  this.feedbackToggle()?.nativeElement.focus();
10640
12666
  }
10641
12667
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantApprovalCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10642
- 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 }); }
12668
+ 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 }); }
10643
12669
  }
10644
12670
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantApprovalCardComponent, decorators: [{
10645
12671
  type: Component,
10646
- args: [{ selector: 'nh-assistant-approval-card', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent, NhAssistantProposalFeedbackComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
10647
- '[attr.data-status]': 'effectiveStatus()'
10648
- }, 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"] }]
12672
+ args: [{ selector: 'nh-assistant-approval-card', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent, NhAssistantProposalFeedbackComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
12673
+ '[attr.data-status]': 'shownStatus()'
12674
+ }, 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"] }]
10649
12675
  }], 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 }] }] } });
10650
12676
 
10651
12677
  let nextId$4 = 0;
@@ -10827,9 +12853,12 @@ const stickToBottomDistance = 120;
10827
12853
  * The messages of a conversation as a live log. Assistant text renders as sanitized
10828
12854
  * Markdown, consecutive tool calls as one collapsible group that counts along, and
10829
12855
  * approvals as cards. The files a person attached show by name, type and size. Messages a
10830
- * trigger wrote into an agent thread read as events, not as a person. While a turn runs
10831
- * without visible progress, a working indicator shows the elapsed time. The thread follows
10832
- * new content while the user is at the bottom.
12856
+ * trigger wrote into an agent thread read as events, not as a person, and a message the application
12857
+ * posted reads as the application's, with its sender, title, Markdown text and link, and a label when
12858
+ * the assistant follows it as an instruction. While a turn runs without visible progress, a working
12859
+ * indicator shows the elapsed time: under the answer `writingMessageId` names, also when the
12860
+ * application's or another person's message arrived after it, and at the end without it. The thread
12861
+ * follows new content while the user is at the bottom.
10833
12862
  */
10834
12863
  class NhAssistantThreadComponent {
10835
12864
  /** The type and size of an attached file, in the current language. */
@@ -10877,6 +12906,13 @@ class NhAssistantThreadComponent {
10877
12906
  * card of a rejected proposal ask what was wrong.
10878
12907
  */
10879
12908
  this.approvalRights = input(null, ...(ngDevMode ? [{ debugName: "approvalRights" }] : []));
12909
+ /**
12910
+ * The answer the running turn writes, for example `NhAssistantStore.writingMessageId`. The working
12911
+ * indicator stays under that answer, also when the application's or a colleague's message arrives
12912
+ * after it during the turn. Without it, or when it names no message of `messages`, the indicator
12913
+ * shows at the end of the thread.
12914
+ */
12915
+ this.writingMessageId = input(null, ...(ngDevMode ? [{ debugName: "writingMessageId" }] : []));
10880
12916
  /** The decision about an approval card, without the approval it belongs to. */
10881
12917
  this.approvalDecision = output();
10882
12918
  /** The decision about an approval card together with its approval id. */
@@ -10892,14 +12928,16 @@ class NhAssistantThreadComponent {
10892
12928
  /**
10893
12929
  * True while the turn runs and nothing else shows progress: before the first part and
10894
12930
  * between tool calls while the model decides what to do next. Streaming text and a
10895
- * running tool group show their own progress; an approval waits for the user.
12931
+ * running tool group show their own progress; an approval waits for the user. With
12932
+ * `writingMessageId`, the answer it names decides, as if the messages after it were not there.
10896
12933
  */
10897
12934
  this.working = computed(() => {
10898
12935
  if (!this.streaming()) {
10899
12936
  return false;
10900
12937
  }
10901
- const last = this.messages()[this.messages().length - 1];
10902
- if (!last || last.role === 'user' || last.parts.length === 0) {
12938
+ const messages = this.messages();
12939
+ const last = this.answerBeingWritten() ?? messages[messages.length - 1];
12940
+ if (!last || last.role === 'user' || last.role === 'application' || last.parts.length === 0) {
10903
12941
  return true;
10904
12942
  }
10905
12943
  const lastPart = last.parts[last.parts.length - 1];
@@ -10907,6 +12945,19 @@ class NhAssistantThreadComponent {
10907
12945
  && lastPart.status !== 'running'
10908
12946
  && lastPart.status !== 'awaiting-approval';
10909
12947
  }, ...(ngDevMode ? [{ debugName: "working" }] : []));
12948
+ /**
12949
+ * The message in whose row the working indicator shows: the answer `writingMessageId` names.
12950
+ * `null` puts the indicator at the end of the thread.
12951
+ */
12952
+ this.workingAfterId = computed(() => this.answerBeingWritten()?.id ?? null, ...(ngDevMode ? [{ debugName: "workingAfterId" }] : []));
12953
+ /** While a turn runs: the answer `writingMessageId` names, when `messages` holds it. */
12954
+ this.answerBeingWritten = computed(() => {
12955
+ const writingMessageId = this.writingMessageId();
12956
+ if (!this.streaming() || !writingMessageId) {
12957
+ return null;
12958
+ }
12959
+ return this.messages().find(message => message.id === writingMessageId) ?? null;
12960
+ }, ...(ngDevMode ? [{ debugName: "answerBeingWritten" }] : []));
10910
12961
  /** Whole seconds since the running turn started. */
10911
12962
  this.elapsedSeconds = computed(() => {
10912
12963
  const startedAt = this.turnStartedAt();
@@ -10948,6 +12999,10 @@ class NhAssistantThreadComponent {
10948
12999
  isTrigger(message) {
10949
13000
  return message.role === 'user' && message.authorKind === 'trigger';
10950
13001
  }
13002
+ /** True for a message the application posted into the conversation. */
13003
+ isApplication(message) {
13004
+ return message.role === 'application';
13005
+ }
10951
13006
  /** True for an assistant message the agent's rules wrote without a model. */
10952
13007
  isRule(message) {
10953
13008
  return message.role === 'assistant' && message.authorKind === 'rule';
@@ -10992,7 +13047,7 @@ class NhAssistantThreadComponent {
10992
13047
  }
10993
13048
  }
10994
13049
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantThreadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10995
- 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 }); }
13050
+ 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 }); }
10996
13051
  }
10997
13052
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantThreadComponent, decorators: [{
10998
13053
  type: Component,
@@ -11002,12 +13057,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
11002
13057
  TranslatePipe,
11003
13058
  NhAssistantIconComponent,
11004
13059
  NhAssistantMarkdownPipe,
13060
+ NhAssistantMessageLinkComponent,
11005
13061
  NhAssistantPartGroupsPipe,
11006
13062
  NhAssistantToolCallGroupComponent,
11007
13063
  NhAssistantApprovalCardComponent,
11008
13064
  NhAssistantConnectionRequiredComponent
11009
- ], 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"] }]
11010
- }], 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 }] }] } });
13065
+ ], 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"] }]
13066
+ }], 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 }] }] } });
11011
13067
 
11012
13068
  let nextId$1 = 0;
11013
13069
  /**
@@ -11196,7 +13252,9 @@ class NhAssistantPanelComponent {
11196
13252
  }
11197
13253
  /**
11198
13254
  * Opens the panel for an invitation link or a clicked notification in the URL fragment and
11199
- * removes the fragment, so a reload or a shared screenshot does not reuse the token.
13255
+ * removes the fragment, so a reload or a shared screenshot does not reuse the token. A clicked
13256
+ * notification about the proposals of a run goes to `NhAssistantPushService.openRun$` while the
13257
+ * application subscribes, and otherwise opens its conversation.
11200
13258
  */
11201
13259
  openFromLocation() {
11202
13260
  const location = globalThis.location;
@@ -11204,7 +13262,7 @@ class NhAssistantPanelComponent {
11204
13262
  const separatorIndex = hash.indexOf('=');
11205
13263
  const name = separatorIndex < 0 ? hash : hash.slice(0, separatorIndex);
11206
13264
  const value = separatorIndex < 0 ? '' : hash.slice(separatorIndex + 1);
11207
- if (!value || (name !== NH_ASSISTANT_JOIN_FRAGMENT && name !== NH_ASSISTANT_CONVERSATION_FRAGMENT)) {
13265
+ if (!value || (name !== NH_ASSISTANT_JOIN_FRAGMENT && name !== NH_ASSISTANT_CONVERSATION_FRAGMENT && name !== NH_ASSISTANT_RUN_FRAGMENT)) {
11208
13266
  return;
11209
13267
  }
11210
13268
  globalThis.history?.replaceState(globalThis.history.state, '', location.pathname + location.search);
@@ -11216,6 +13274,10 @@ class NhAssistantPanelComponent {
11216
13274
  if (tokenIndex <= 0) {
11217
13275
  return;
11218
13276
  }
13277
+ if (name === NH_ASSISTANT_RUN_FRAGMENT) {
13278
+ this.push.openNotification(decodeURIComponent(value.slice(tokenIndex + 1)), decodeURIComponent(value.slice(0, tokenIndex)));
13279
+ return;
13280
+ }
11219
13281
  const conversationId = decodeURIComponent(value.slice(0, tokenIndex));
11220
13282
  const token = decodeURIComponent(value.slice(tokenIndex + 1));
11221
13283
  this.panel.open();
@@ -11232,7 +13294,7 @@ class NhAssistantPanelComponent {
11232
13294
  void this.store.cancel();
11233
13295
  }
11234
13296
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11235
- 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 }); }
13297
+ 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 }); }
11236
13298
  }
11237
13299
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantPanelComponent, decorators: [{
11238
13300
  type: Component,
@@ -11248,7 +13310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
11248
13310
  NhAssistantPreferencesComponent,
11249
13311
  NhAssistantShareComponent,
11250
13312
  NhAssistantThreadComponent
11251
- ], 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"] }]
13313
+ ], 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"] }]
11252
13314
  }], ctorParameters: () => [], propDecorators: { drawer: [{ type: i0.ViewChild, args: ['drawer', { isSignal: true }] }] } });
11253
13315
 
11254
13316
  /**
@@ -11573,102 +13635,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
11573
13635
  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"] }]
11574
13636
  }], 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"] }] } });
11575
13637
 
11576
- /**
11577
- * The name of a subject with the name of its type, linked to where the application shows the
11578
- * subject (internal). The host's `subjectLinks` builder wins over the server's link; a link within
11579
- * the application navigates through the router, an `https` link leaves it, and anything else shows
11580
- * no link. Ctrl-, Cmd-, Shift- and middle-clicks keep the browser's behavior, such as a new tab.
11581
- * A name that already says the type, as "The whole application" does for the application as a
11582
- * whole, is shown once.
11583
- */
11584
- class NhAssistantSubjectLinkComponent {
11585
- constructor() {
11586
- this.config = inject(NH_ASSISTANT_CONFIG, { optional: true });
11587
- this.router = inject(Router, { optional: true });
11588
- this.locationStrategy = inject(LocationStrategy, { optional: true });
11589
- this.injector = inject(EnvironmentInjector);
11590
- this.subjectType = input.required(...(ngDevMode ? [{ debugName: "subjectType" }] : []));
11591
- this.subjectId = input.required(...(ngDevMode ? [{ debugName: "subjectId" }] : []));
11592
- /** The text people read, usually the subject's display name. */
11593
- this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
11594
- /** The name of the subject type, such as "Project"; nothing is shown without one. */
11595
- this.typeName = input(null, ...(ngDevMode ? [{ debugName: "typeName" }] : []));
11596
- /** The server's link to the subject. */
11597
- this.link = input(null, ...(ngDevMode ? [{ debugName: "link" }] : []));
11598
- /** The type's name, unless the subject's name is the type's name itself, as for the whole application. */
11599
- this.shownTypeName = computed(() => {
11600
- const type = this.typeName()?.trim();
11601
- if (!type) {
11602
- return null;
11603
- }
11604
- return type.toLocaleLowerCase() === this.label().trim().toLocaleLowerCase() ? null : type;
11605
- }, ...(ngDevMode ? [{ debugName: "shownTypeName" }] : []));
11606
- this.target = computed(() => {
11607
- const builder = this.config?.subjectLinks?.[this.subjectType()];
11608
- const subject = { type: this.subjectType(), id: this.subjectId() };
11609
- const custom = builder ? runInInjectionContext(this.injector, () => builder(subject)) : undefined;
11610
- if (custom === null) {
11611
- return null;
11612
- }
11613
- if (Array.isArray(custom)) {
11614
- return this.routeTarget(this.router ? this.router.serializeUrl(this.router.createUrlTree([...custom])) : null);
11615
- }
11616
- return this.urlTarget(typeof custom === 'string' ? custom : this.link() ?? null);
11617
- }, ...(ngDevMode ? [{ debugName: "target" }] : []));
11618
- }
11619
- open(event, target) {
11620
- if (!target.route || !this.router || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
11621
- return;
11622
- }
11623
- event.preventDefault();
11624
- void this.router.navigateByUrl(target.route);
11625
- }
11626
- urlTarget(url) {
11627
- if (!url) {
11628
- return null;
11629
- }
11630
- if (url.startsWith('/') && !url.startsWith('//') && !url.startsWith('/\\')) {
11631
- return this.routeTarget(url);
11632
- }
11633
- return /^https:\/\/[^/\\\s]+/i.test(url) ? { href: url, route: null } : null;
11634
- }
11635
- routeTarget(url) {
11636
- if (!url) {
11637
- return null;
11638
- }
11639
- return {
11640
- href: this.locationStrategy ? this.locationStrategy.prepareExternalUrl(url) : url,
11641
- route: this.router ? url : null
11642
- };
11643
- }
11644
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11645
- 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: `
11646
- @if (shownTypeName(); as type) {
11647
- <!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
11648
- <span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
11649
- }
11650
- @if (target(); as link) {
11651
- <a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
11652
- } @else {
11653
- <span class="nh-assistant-subject-name">{{ label() }}</span>
11654
- }
11655
- `, 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 }); }
11656
- }
11657
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSubjectLinkComponent, decorators: [{
11658
- type: Component,
11659
- args: [{ selector: 'nh-assistant-subject-link', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
11660
- @if (shownTypeName(); as type) {
11661
- <!-- The space keeps the type and the name apart for screen readers; the flex gap shows it. -->
11662
- <span class="nh-assistant-subject-type">{{ type }}</span>{{ ' ' }}
11663
- }
11664
- @if (target(); as link) {
11665
- <a class="nh-assistant-subject-name" [href]="link.href" (click)="open($event, link)">{{ label() }}</a>
11666
- } @else {
11667
- <span class="nh-assistant-subject-name">{{ label() }}</span>
11668
- }
11669
- `, 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"] }]
11670
- }], 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 }] }] } });
11671
-
11672
13638
  /*
11673
13639
  * Public API surface of @newheap/platform-ai-chat.
11674
13640
  */
@@ -11677,5 +13643,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
11677
13643
  * Generated bundle index. Do not edit.
11678
13644
  */
11679
13645
 
11680
- 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 };
13646
+ export { NH_ASSISTANT_ACCESS_POLICY, NH_ASSISTANT_AGENT_PACKAGE_FORMAT, NH_ASSISTANT_AGENT_PACKAGE_FORMAT_VERSION, NH_ASSISTANT_AGENT_PACKAGE_MAX_AGENTS, NH_ASSISTANT_AGENT_PACKAGE_MAX_BYTES, 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_PACKAGE_LOCK_ALL, NH_ASSISTANT_PACKAGE_LOCK_FIELDS, NH_ASSISTANT_PAGE_CONTEXT_LIMITS, NH_ASSISTANT_PANEL_MOBILE_QUERY, NH_ASSISTANT_PANEL_WIDTH, NH_ASSISTANT_RESULT_PREVIEW_LENGTH, NH_ASSISTANT_RUN_FRAGMENT, 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 };
11681
13647
  //# sourceMappingURL=newheap-platform-ai-chat.mjs.map