@newheap/platform-ai-chat 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/admin/index.d.ts +320 -11
- package/agent-runs/index.d.ts +5 -0
- package/fesm2022/newheap-platform-ai-chat-admin.mjs +5792 -3527
- package/fesm2022/newheap-platform-ai-chat-admin.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs +9 -2
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-testing.mjs +2989 -139
- package/fesm2022/newheap-platform-ai-chat-testing.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat.mjs +2237 -90
- package/fesm2022/newheap-platform-ai-chat.mjs.map +1 -1
- package/i18n/en.json +470 -10
- package/i18n/nl.json +470 -10
- package/index.d.ts +1272 -26
- package/package.json +1 -1
- package/push/nh-assistant-push-worker.js +13 -6
- package/testing/index.d.ts +199 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
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';
|
|
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, afterRenderEffect } 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
5
|
import { isPlatformBrowser, DOCUMENT, DatePipe, LocationStrategy, NgTemplateOutlet } from '@angular/common';
|
|
@@ -11,6 +11,7 @@ import * as i1 from '@angular/cdk/scrolling';
|
|
|
11
11
|
import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
|
|
12
12
|
import createDOMPurify from 'dompurify';
|
|
13
13
|
import { Marked } from 'marked';
|
|
14
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
14
15
|
|
|
15
16
|
/*
|
|
16
17
|
* Wire models of the NewHeap assistant HTTP API.
|
|
@@ -26,6 +27,8 @@ const NH_ASSISTANT_SSE_EVENT_TYPES = [
|
|
|
26
27
|
'tool.started',
|
|
27
28
|
'tool.completed',
|
|
28
29
|
'approval.required',
|
|
30
|
+
'question.asked',
|
|
31
|
+
'question.answered',
|
|
29
32
|
'connection.required',
|
|
30
33
|
'turn.completed',
|
|
31
34
|
'error'
|
|
@@ -94,6 +97,38 @@ const NH_ASSISTANT_MAX_FEEDBACK_TEXT = 1_000;
|
|
|
94
97
|
/** Maximum number of proposals one `POST approvals/feedback` request accepts. */
|
|
95
98
|
const NH_ASSISTANT_MAX_BULK_FEEDBACK = 50;
|
|
96
99
|
|
|
100
|
+
/** The `format` of every agent package. */
|
|
101
|
+
const NH_ASSISTANT_AGENT_PACKAGE_FORMAT = 'newheap.assistant.agent-package';
|
|
102
|
+
/** The format version this library reads and writes; a newer one is refused. */
|
|
103
|
+
const NH_ASSISTANT_AGENT_PACKAGE_FORMAT_VERSION = 1;
|
|
104
|
+
/** The largest package in bytes of its UTF-8 JSON: 1 MB (`assistant-package-too-large` above). */
|
|
105
|
+
const NH_ASSISTANT_AGENT_PACKAGE_MAX_BYTES = 1_048_576;
|
|
106
|
+
/** The most agents of one package. */
|
|
107
|
+
const NH_ASSISTANT_AGENT_PACKAGE_MAX_AGENTS = 20;
|
|
108
|
+
/** The lock of a whole part, instead of a list of its fields. */
|
|
109
|
+
const NH_ASSISTANT_PACKAGE_LOCK_ALL = '*';
|
|
110
|
+
/**
|
|
111
|
+
* The fields a package may lock per part kind (`NhAssistantPackageLockFields`). A save that changes a
|
|
112
|
+
* locked field is refused with the field error `{field}: locked`, named as here; `worksOn`,
|
|
113
|
+
* `dailyBudget`, `files` and `limits` each stand for the fields the forms show together. An agent in
|
|
114
|
+
* code carries only the first six fields of `agent`.
|
|
115
|
+
*/
|
|
116
|
+
const NH_ASSISTANT_PACKAGE_LOCK_FIELDS = {
|
|
117
|
+
agent: ['displayName', 'description', 'instructions', 'toolSelectors', 'requiredPolicy', 'autonomy', 'offeredInChat', 'worksOn', 'profile', 'dataClassification'],
|
|
118
|
+
runSettings: [
|
|
119
|
+
'accountability', 'delegateFromInitiator', 'allowGatewayReads', 'elevatedReads', 'approvalPolicy', 'retryCount', 'dailyBudget',
|
|
120
|
+
'maxConcurrentRuns', 'maxRunsPerSubjectPerDay', 'maxTokensPerRun', 'triageProfile', 'ruleHandler', 'files'
|
|
121
|
+
],
|
|
122
|
+
skill: ['description', 'instructions', 'tools', 'profile', 'ruleHandler', 'maxTokensPerRun', 'dailyBudget', 'approvalPolicy', 'dataClassification', 'files'],
|
|
123
|
+
trigger: ['skill', 'source', 'event', 'filters', 'cron', 'timeZone', 'subjectSet', 'message', 'conflict', 'debounceSeconds'],
|
|
124
|
+
consultation: [
|
|
125
|
+
'description', 'instructions', 'minimumRole', 'askerPolicy', 'routes', 'proposalRole', 'proposalPolicy', 'toolSelectors', 'limits',
|
|
126
|
+
'allowRequests', 'exposeToMcp', 'dataClassification'
|
|
127
|
+
],
|
|
128
|
+
handOff: ['sources', 'description', 'notifySource', 'maxPerSubjectPerDay'],
|
|
129
|
+
metadata: ['value']
|
|
130
|
+
};
|
|
131
|
+
|
|
97
132
|
const NH_ASSISTANT_CONFIG = new InjectionToken('NH_ASSISTANT_CONFIG');
|
|
98
133
|
const NH_ASSISTANT_ACCESS_POLICY = new InjectionToken('NH_ASSISTANT_ACCESS_POLICY');
|
|
99
134
|
/**
|
|
@@ -254,7 +289,9 @@ var en = {
|
|
|
254
289
|
running: "The assistant is working",
|
|
255
290
|
"waiting-for-approval": "Waiting for approval",
|
|
256
291
|
"running-by": "{{name}} is working with the assistant…",
|
|
257
|
-
"waiting-for-approval-by": "Waiting for {{name}} to decide…"
|
|
292
|
+
"waiting-for-approval-by": "Waiting for {{name}} to decide…",
|
|
293
|
+
"waiting-for-answer": "Waiting for an answer to the question",
|
|
294
|
+
"waiting-for-answer-by": "Waiting for {{name}} to answer…"
|
|
258
295
|
},
|
|
259
296
|
attach: "Attach files",
|
|
260
297
|
"attach-hint": "{{types}}, up to {{max}} each, at most {{count}} files per message",
|
|
@@ -300,6 +337,7 @@ var en = {
|
|
|
300
337
|
succeeded: "Completed",
|
|
301
338
|
failed: "Failed",
|
|
302
339
|
"awaiting-approval": "Awaiting approval",
|
|
340
|
+
"awaiting-answer": "Awaiting an answer",
|
|
303
341
|
rejected: "Rejected",
|
|
304
342
|
"not-executed": "Not run"
|
|
305
343
|
},
|
|
@@ -318,6 +356,7 @@ var en = {
|
|
|
318
356
|
"tool-group": {
|
|
319
357
|
running: "Calling {{name}}…",
|
|
320
358
|
"awaiting-approval": "Waiting for approval: {{name}}",
|
|
359
|
+
"awaiting-answer": "Waiting for an answer",
|
|
321
360
|
"used-one": "Used 1 tool",
|
|
322
361
|
"used-many": "Used {{count}} tools",
|
|
323
362
|
progress: "{{finished}} of {{total}} done",
|
|
@@ -348,6 +387,7 @@ var en = {
|
|
|
348
387
|
withdrawn: "Withdrawn",
|
|
349
388
|
stale: "Outdated",
|
|
350
389
|
executing: "Running",
|
|
390
|
+
"awaiting-application": "With the application",
|
|
351
391
|
executed: "Done",
|
|
352
392
|
"execution-failed": "Failed",
|
|
353
393
|
"execution-unknown": "Outcome unknown",
|
|
@@ -358,6 +398,12 @@ var en = {
|
|
|
358
398
|
"waiting-for-participant": "Waiting for the participant who started this task to decide.",
|
|
359
399
|
"waiting-for-approver": "Waiting for an approver to decide.",
|
|
360
400
|
"waiting-for-other-approver": "You started this work, so another approver decides.",
|
|
401
|
+
resolve: {
|
|
402
|
+
explanation: "It is not known whether the application carried this out. Check it, then hand it to the application again or mark it as done.",
|
|
403
|
+
"hand-to-application": "Hand to the application again",
|
|
404
|
+
"mark-resolved": "Mark as done",
|
|
405
|
+
resolving: "Submitting your choice"
|
|
406
|
+
},
|
|
361
407
|
"waiting-for-asker": "Waiting for the person who asked to decide in their own chat.",
|
|
362
408
|
"give-feedback": "What was wrong?",
|
|
363
409
|
"stale-kind": {
|
|
@@ -381,6 +427,24 @@ var en = {
|
|
|
381
427
|
moved: "It now waits for the approvers of {{subject}}."
|
|
382
428
|
}
|
|
383
429
|
},
|
|
430
|
+
question: {
|
|
431
|
+
title: "Question",
|
|
432
|
+
status: {
|
|
433
|
+
pending: "Waiting for an answer",
|
|
434
|
+
answered: "Answered",
|
|
435
|
+
expired: "Expired",
|
|
436
|
+
cancelled: "Cancelled"
|
|
437
|
+
},
|
|
438
|
+
choices: "Answers",
|
|
439
|
+
"choose-label": "Answer: {{choice}}",
|
|
440
|
+
"expires-in": "Answer within {{time}}",
|
|
441
|
+
answering: "Submitting your answer",
|
|
442
|
+
"waiting-for": "Waiting for {{name}} to answer.",
|
|
443
|
+
"waiting-for-participant": "Waiting for the person the question is addressed to.",
|
|
444
|
+
answered: "Answer: {{choice}}",
|
|
445
|
+
expired: "Nobody answered in time.",
|
|
446
|
+
cancelled: "The question was withdrawn when the task was stopped."
|
|
447
|
+
},
|
|
384
448
|
"proposal-feedback": {
|
|
385
449
|
legend: "What was wrong? (optional)",
|
|
386
450
|
bulk: "Applies to the {{count}} proposals you rejected.",
|
|
@@ -491,6 +555,7 @@ var en = {
|
|
|
491
555
|
"assistant-message-too-long": "The message is too long. Shorten it and send it again.",
|
|
492
556
|
"assistant-model-unavailable": "The language model is temporarily unavailable. Try again in a moment.",
|
|
493
557
|
"assistant-classification-not-permitted": "The model this agent uses may not receive data of the agent's classification. Ask an administrator to choose a model profile that permits it.",
|
|
558
|
+
"assistant-model-region-denied": "The model this agent uses may not run in the region the application works in. Ask an administrator to choose a model profile that permits the region.",
|
|
494
559
|
"assistant-files-unavailable": "This application gives the assistant no files.",
|
|
495
560
|
"assistant-files-not-accepted": "This agent does not accept files. An administrator can switch files on for it.",
|
|
496
561
|
"assistant-file-reference-invalid": "A file could not be read because its reference is not valid.",
|
|
@@ -584,15 +649,18 @@ var en = {
|
|
|
584
649
|
"assistant-consult-depth-exceeded": "This consultation would ask agents in a loop or nest too deeply.",
|
|
585
650
|
"assistant-consult-budget-exhausted": "The agent's daily budget is spent.",
|
|
586
651
|
"assistant-consult-limit-reached": "You reached the daily number of consultations.",
|
|
652
|
+
"assistant-consult-turn-limit": "The assistant reached the number of consultations for this answer.",
|
|
587
653
|
"assistant-consult-timeout": "The agent did not answer in time.",
|
|
588
654
|
"assistant-consult-failed": "The agent could not answer.",
|
|
589
655
|
"assistant-consult-read-only": "A consultation cannot change anything.",
|
|
656
|
+
"assistant-consult-tool-not-selected": "This consultation does not offer that tool, so nothing ran.",
|
|
590
657
|
"assistant-consult-proposal-refused": "No route at the subject takes this proposal any more. Approve or reject it here.",
|
|
591
658
|
"assistant-consult-asker-decides": "The person who asked decides this proposal in their own chat.",
|
|
592
659
|
"assistant-consult-route-not-allowed": "None of the agent's consultations allows this route, so it cannot be switched on.",
|
|
593
660
|
"assistant-consult-proposal-moved": "The proposal was left for the subject's approvers.",
|
|
594
661
|
"assistant-moved-to-shadow": "The work went to the agent's shadow thread, where a run in shadow takes it.",
|
|
595
662
|
"assistant-shadow-variant": "A shadow variant always works in shadow.",
|
|
663
|
+
"assistant-not-shadow-variant": "Only a shadow variant created here can be promoted onto its live agent.",
|
|
596
664
|
"assistant-service-account-not-used": "This agent does not answer to a technical account.",
|
|
597
665
|
"assistant-service-account-not-found": "No account that may sign in exists with this id.",
|
|
598
666
|
"assistant-skill-in-code": "This skill is part of the code and cannot change here.",
|
|
@@ -601,8 +669,9 @@ var en = {
|
|
|
601
669
|
"assistant-skill-in-use": "A trigger still starts this skill. Change or remove the trigger first.",
|
|
602
670
|
"assistant-configuration-limit": "This agent already has as many skills, triggers or consultations as allowed.",
|
|
603
671
|
"assistant-run-settings-in-code": "This agent is part of the code; its runs are configured there.",
|
|
604
|
-
"assistant-run-settings-in-use": "Skills, triggers or
|
|
672
|
+
"assistant-run-settings-in-use": "Skills, triggers, consultations or hand-offs still belong to this agent. Remove them first.",
|
|
605
673
|
"assistant-skill-candidate-not-found": "This skill has no version being evaluated in shadow.",
|
|
674
|
+
"assistant-trigger-candidate-not-found": "This trigger has no version being evaluated in shadow.",
|
|
606
675
|
"assistant-skill-version-gone": "The skill version this run was for is no longer evaluated.",
|
|
607
676
|
"assistant-account-search-unavailable": "The application offers no account search; enter the account's id.",
|
|
608
677
|
"assistant-mcp-connection-required": "This server needs a connection first. Connect it and try again.",
|
|
@@ -632,7 +701,28 @@ var en = {
|
|
|
632
701
|
"assistant-file-scan-refused": "The file did not pass the scan for harmful content and was not stored.",
|
|
633
702
|
"assistant-consultation-in-code": "The agent allows consultation about this kind of object in code; it cannot change here.",
|
|
634
703
|
"assistant-consultation-not-found": "The consultation was not found.",
|
|
635
|
-
"assistant-consultations-not-allowed": "The application does not let administrators add consultations to this agent."
|
|
704
|
+
"assistant-consultations-not-allowed": "The application does not let administrators add consultations to this agent.",
|
|
705
|
+
"assistant-handoffs-not-allowed": "The application does not let administrators connect agents to this one.",
|
|
706
|
+
"assistant-handoff-in-code": "The agent accepts hand-offs about this kind of object in code; it cannot change here.",
|
|
707
|
+
"assistant-handoff-not-found": "The hand-off was not found.",
|
|
708
|
+
"assistant-shadow-variants-not-allowed": "The application does not let administrators create shadow variants of this agent.",
|
|
709
|
+
"assistant-metadata-entry-not-found": "The application does not register this field of agents.",
|
|
710
|
+
"assistant-metadata-read-only": "The application sets this field of the agent in its code; it cannot change here.",
|
|
711
|
+
"assistant-instructions-asset-not-found": "The application has no such text asset in this version.",
|
|
712
|
+
"assistant-instructions-asset-unavailable": "The application's text assets cannot be read right now. Nothing was saved; try again shortly.",
|
|
713
|
+
"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.",
|
|
714
|
+
"assistant-package-format-unsupported": "This is no agent package this version can read: its format, format version or a property is unknown.",
|
|
715
|
+
"assistant-package-locked": "An agent package locks this. Unlink it from the package first.",
|
|
716
|
+
"assistant-package-too-large": "An agent package is at most 1 MB and holds at most 20 agents.",
|
|
717
|
+
"assistant-package-refused": "The check refused parts of the package, so nothing was imported. Check the package again to see which.",
|
|
718
|
+
"assistant-package-not-linked": "This agent, or this part of it, is not linked to an agent package.",
|
|
719
|
+
"assistant-question-invalid": "The assistant could not ask this question; it continues without it.",
|
|
720
|
+
"assistant-question-not-found": "This question was not found.",
|
|
721
|
+
"assistant-question-not-pending": "This question no longer waits for an answer.",
|
|
722
|
+
"assistant-question-forbidden": "This question is addressed to someone else.",
|
|
723
|
+
"assistant-question-expired": "Nobody answered this question in time. Send your message again to continue.",
|
|
724
|
+
"assistant-question-cancelled": "The question was withdrawn when the task was stopped.",
|
|
725
|
+
"assistant-question-answer-invalid": "Choose one of the answers of the question."
|
|
636
726
|
},
|
|
637
727
|
notices: {
|
|
638
728
|
"no-answer": "The assistant finished without an answer. Try again or rephrase your question.",
|
|
@@ -1016,7 +1106,26 @@ var en = {
|
|
|
1016
1106
|
"in-code": "In this group in code",
|
|
1017
1107
|
"shadow-variant": "A shadow variant works for administrators only and joins no group."
|
|
1018
1108
|
},
|
|
1019
|
-
|
|
1109
|
+
metadata: {
|
|
1110
|
+
title: "Application fields",
|
|
1111
|
+
hint: "The application keeps its own data about agents here. Each field has an editor of the application, which saves it on its own.",
|
|
1112
|
+
"save-first": "Save the agent first; then its fields appear here.",
|
|
1113
|
+
loading: "Loading the fields",
|
|
1114
|
+
"load-failed": "The fields of this agent could not be loaded.",
|
|
1115
|
+
"no-editor": "The application shows no editor for this field.",
|
|
1116
|
+
"read-only": "Set in the application's code; it cannot change here.",
|
|
1117
|
+
saved: "Saved.",
|
|
1118
|
+
removed: "Removed.",
|
|
1119
|
+
source: {
|
|
1120
|
+
code: "From code",
|
|
1121
|
+
override: "Changed here, over the value in code",
|
|
1122
|
+
data: "Stored with the agent",
|
|
1123
|
+
none: "No value"
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
"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.",
|
|
1127
|
+
"starts-in-shadow": "Start in shadow",
|
|
1128
|
+
"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."
|
|
1020
1129
|
},
|
|
1021
1130
|
effect: {
|
|
1022
1131
|
"read-only": "Read only",
|
|
@@ -1375,7 +1484,9 @@ var en = {
|
|
|
1375
1484
|
skill: "Skill {{id}}:",
|
|
1376
1485
|
candidate: "Candidate of skill {{id}}:",
|
|
1377
1486
|
trigger: "Trigger {{id}}:",
|
|
1378
|
-
consultation: "Consultation about {{id}}:"
|
|
1487
|
+
consultation: "Consultation about {{id}}:",
|
|
1488
|
+
"hand-off": "Hand-off about {{id}}:",
|
|
1489
|
+
"trigger-candidate": "Candidate of trigger {{id}}:"
|
|
1379
1490
|
},
|
|
1380
1491
|
code: {
|
|
1381
1492
|
"unknown-agent": "the agent can no longer run on its own.",
|
|
@@ -1402,7 +1513,18 @@ var en = {
|
|
|
1402
1513
|
"no-approver": "the route with the agent's account is left out, because the approval policy lets only the person who caused a proposal decide it.",
|
|
1403
1514
|
"limit-above-ceiling": "a limit is above what the application allows, so the application's applies.",
|
|
1404
1515
|
"requests-not-allowed": "the application no longer allows requests, so it takes none.",
|
|
1405
|
-
"mcp-not-allowed": "the application no longer offers consultations to MCP clients, so they do not see it."
|
|
1516
|
+
"mcp-not-allowed": "the application no longer offers consultations to MCP clients, so they do not see it.",
|
|
1517
|
+
"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.",
|
|
1518
|
+
"no-asset-source": "its instructions come from the application's text assets, which the application no longer offers.",
|
|
1519
|
+
"asset-missing": "the application no longer has the text asset with its instructions in this version.",
|
|
1520
|
+
"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.",
|
|
1521
|
+
"asset-invalid": "the application's text asset cannot be used as instructions.",
|
|
1522
|
+
"asset-unavailable": "the application's text assets could not be read; they are read again shortly.",
|
|
1523
|
+
"outside-ceiling": "the application no longer allows it.",
|
|
1524
|
+
"unknown-source": "an agent that may hand off can no longer run on its own.",
|
|
1525
|
+
"unknown-live-agent": "the agent this shadow variant follows can no longer run on its own.",
|
|
1526
|
+
"live-agent-not-live": "the agent this shadow variant follows is no live agent.",
|
|
1527
|
+
"too-many-variants": "the agent it follows has more shadow variants than the application allows."
|
|
1406
1528
|
}
|
|
1407
1529
|
},
|
|
1408
1530
|
"field-errors": {
|
|
@@ -1421,7 +1543,10 @@ var en = {
|
|
|
1421
1543
|
"megabytes-up-to": "Enter a size above 0 and at most {{max}} MB.",
|
|
1422
1544
|
"megabytes-positive": "Enter a size above 0 MB.",
|
|
1423
1545
|
"not-allowed": "The application does not allow this.",
|
|
1424
|
-
"routes-required": "Choose at least one route, or let it only answer."
|
|
1546
|
+
"routes-required": "Choose at least one route, or let it only answer.",
|
|
1547
|
+
"tools-not-allowed": "A chosen tool is outside the agent's own tools. Clear it, or add the tool to the agent first.",
|
|
1548
|
+
locked: "An agent package locks this field. Unlink the part first to change it.",
|
|
1549
|
+
"region-not-permitted": "This model profile may not run in the region the application works in, nor may its fallbacks. Choose a profile that permits the region."
|
|
1425
1550
|
},
|
|
1426
1551
|
settings: {
|
|
1427
1552
|
title: "Run settings",
|
|
@@ -1664,6 +1789,24 @@ var en = {
|
|
|
1664
1789
|
"set-hint": "One run each time for every object in a set, such as the active projects.",
|
|
1665
1790
|
"every-division": "Every division",
|
|
1666
1791
|
dropped: "This schedule ran for the whole application, which the agent no longer works on. Choose a set of objects."
|
|
1792
|
+
},
|
|
1793
|
+
"saved-candidate": "The new version fires in shadow next to the live version, which keeps working.",
|
|
1794
|
+
apply: "How the change takes effect",
|
|
1795
|
+
"apply-live": "Apply at once",
|
|
1796
|
+
"apply-live-hint": "The new version replaces the live one at once, in the mode the trigger has.",
|
|
1797
|
+
"apply-shadow": "Evaluate in shadow next to the live version first",
|
|
1798
|
+
"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.",
|
|
1799
|
+
versions: "Versions",
|
|
1800
|
+
candidate: {
|
|
1801
|
+
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.",
|
|
1802
|
+
"out-of-effect": "The candidate does not fire: it no longer fits the code ({{problem}}). The live version keeps working.",
|
|
1803
|
+
changes: "What the candidate changes",
|
|
1804
|
+
"no-changes": "The candidate has the same definition as the live version.",
|
|
1805
|
+
change: "{{candidate}} (live: {{live}})",
|
|
1806
|
+
comparison: "Live version and candidate of trigger {{trigger}}",
|
|
1807
|
+
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}}.",
|
|
1808
|
+
promoted: "The candidate is the live version of the trigger now.",
|
|
1809
|
+
none: "none"
|
|
1667
1810
|
}
|
|
1668
1811
|
},
|
|
1669
1812
|
"way-of-working": "Way of working",
|
|
@@ -1914,6 +2057,9 @@ var en = {
|
|
|
1914
2057
|
"no-askers": "No agent asks it yet. Select its tool in the tools of an agent that should ask it.",
|
|
1915
2058
|
"code-hint": "Allowed in code; here only the route switches below change it.",
|
|
1916
2059
|
"limits-value": "At most {{calls}} tool calls, {{seconds}} seconds, {{chars}} characters and {{history}} thread messages",
|
|
2060
|
+
"tools-label": "Tools:",
|
|
2061
|
+
"tools-all": "every tool of the agent",
|
|
2062
|
+
"tools-none": "none, because no chosen tool is among the agent's own tools any more",
|
|
1917
2063
|
"edit-named": "Edit the consultation about {{type}}",
|
|
1918
2064
|
"remove-named": "Delete the consultation about {{type}}",
|
|
1919
2065
|
"remove-explain": "Its tools disappear; proposals it made can still be decided.",
|
|
@@ -1995,7 +2141,7 @@ var en = {
|
|
|
1995
2141
|
"four-eyes": "This approval policy uses four eyes, so the person who asked cannot decide their own proposal in their chat; that route does not apply.",
|
|
1996
2142
|
"initiator-only": "This approval policy lets only the person who caused a proposal decide it, so the route with the agent's technical account is refused."
|
|
1997
2143
|
},
|
|
1998
|
-
advanced: "Advanced: limits, requests and classification",
|
|
2144
|
+
advanced: "Advanced: tools, limits, requests and classification",
|
|
1999
2145
|
limits: "Limits of one consultation",
|
|
2000
2146
|
"limits-hint": "Empty starts at the default within what the application allows.",
|
|
2001
2147
|
"limit-range": "From {{min}} to {{max}}.",
|
|
@@ -2006,8 +2152,128 @@ var en = {
|
|
|
2006
2152
|
"mcp-hint": "External MCP clients may consult it too, with the rights of their person.",
|
|
2007
2153
|
"mcp-closed": "The application does not offer consultations to MCP clients.",
|
|
2008
2154
|
"classification-hint": "How sensitive its answers are in the conversation that asked. Without one, the agent's classification applies.",
|
|
2009
|
-
|
|
2010
|
-
|
|
2155
|
+
tools: "Tools it may use",
|
|
2156
|
+
"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.",
|
|
2157
|
+
"tool-not-covered": "No longer among the agent's own tools.",
|
|
2158
|
+
"in-effect": "A consultation is in effect once saved; it answers once an agent that asks selects its tool.",
|
|
2159
|
+
"starts-off": "Start off",
|
|
2160
|
+
"starts-off-hint": "It is not offered until you switch it on in the list, for example after a review.",
|
|
2161
|
+
"starts-off-ceiling": "A new consultation starts off: the application wants every one reviewed before it is offered. Switch it on in the list."
|
|
2162
|
+
},
|
|
2163
|
+
"off-badge": "Off",
|
|
2164
|
+
"off-explain": "Off: asking agents get none of its tools until you switch it on.",
|
|
2165
|
+
"switch-on": "Switch on",
|
|
2166
|
+
"switch-off": "Switch off",
|
|
2167
|
+
"switch-on-named": "Switch on the consultation about {{type}}",
|
|
2168
|
+
"switch-off-named": "Switch off the consultation about {{type}}",
|
|
2169
|
+
"switched-on": "The consultation is on: agents that ask get its tools.",
|
|
2170
|
+
"switched-off": "The consultation is off: agents that ask get none of its tools."
|
|
2171
|
+
}
|
|
2172
|
+
},
|
|
2173
|
+
"hand-offs": {
|
|
2174
|
+
title: "Hand-offs",
|
|
2175
|
+
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.",
|
|
2176
|
+
loading: "Loading hand-offs…",
|
|
2177
|
+
"load-failed": "The hand-offs could not be loaded.",
|
|
2178
|
+
add: "Add hand-off",
|
|
2179
|
+
empty: "No agent can hand work to this agent yet.",
|
|
2180
|
+
closed: {
|
|
2181
|
+
application: "The application does not let administrators connect agents to this one; its hand-offs come from its code.",
|
|
2182
|
+
"needs-settings": "Give the agent run settings before you connect agents to it.",
|
|
2183
|
+
limit: "This agent accepts as many hand-offs as allowed ({{max}}).",
|
|
2184
|
+
"no-types": "Every kind of object the application lets you connect this agent about already has a hand-off."
|
|
2185
|
+
},
|
|
2186
|
+
notifies: "Tells the source how it ended",
|
|
2187
|
+
"no-description": "No description.",
|
|
2188
|
+
from: "From:",
|
|
2189
|
+
"limit-value": "At most {{max}} per source and object per day",
|
|
2190
|
+
"code-hint": "Accepted in code; it cannot change here.",
|
|
2191
|
+
changed: "Changed by {{user}} on {{date}}",
|
|
2192
|
+
"edit-named": "Edit the hand-off about {{type}}",
|
|
2193
|
+
"remove-named": "Delete the hand-off about {{type}}",
|
|
2194
|
+
"remove-explain": "Its tool disappears from the sources' next runs; runs it started finish.",
|
|
2195
|
+
added: "The hand-off was added. A source uses it once its tools select its tool.",
|
|
2196
|
+
saved: "The hand-off was saved.",
|
|
2197
|
+
removed: "The hand-off was removed.",
|
|
2198
|
+
problems: {
|
|
2199
|
+
invalid: "Out of effect: a stored value is not valid.",
|
|
2200
|
+
"outside-ceiling": "Out of effect: the application no longer lets these agents be connected about this kind of object.",
|
|
2201
|
+
"unknown-agent": "Out of effect: this agent can no longer run on its own.",
|
|
2202
|
+
"unknown-source": "Out of effect: an agent that may hand off can no longer run on its own.",
|
|
2203
|
+
"not-worked-on": "Out of effect: this agent does not work on this kind of object.",
|
|
2204
|
+
"conflicts-with-code": "Out of effect: the application now accepts hand-offs about this kind of object in code.",
|
|
2205
|
+
"limit-above-ceiling": "Out of effect: the daily limit is above what the application allows."
|
|
2206
|
+
},
|
|
2207
|
+
form: {
|
|
2208
|
+
"new-title": "New hand-off",
|
|
2209
|
+
"edit-title": "Hand-off about {{type}}, version {{version}}",
|
|
2210
|
+
"subject-type": "Kind of object",
|
|
2211
|
+
"subject-type-hint": "The kinds of object the application lets you connect this agent about.",
|
|
2212
|
+
sources: "Agents that may hand off",
|
|
2213
|
+
"no-sources": "The application allows no agent that can run on its own to hand off about this kind of object yet.",
|
|
2214
|
+
"source-not-allowed": "No longer allowed; clear it.",
|
|
2215
|
+
"sources-hint": "Only the agents the application allows; an agent created here counts once it has run settings.",
|
|
2216
|
+
"sources-admin": "The application also allows agents created in the administration.",
|
|
2217
|
+
description: "Description for the sources",
|
|
2218
|
+
"description-hint": "When a source should hand work off, in a sentence or two.",
|
|
2219
|
+
notify: "Give the source a follow-up when this agent's run ends",
|
|
2220
|
+
"notify-hint": "The source hears the outcome and the number of proposals, and the run's summary when both work on the same object.",
|
|
2221
|
+
limit: "Hand-offs per source and object per day",
|
|
2222
|
+
"limit-hint": "1 to {{max}}; 5 when left empty.",
|
|
2223
|
+
"in-effect": "It is in effect once saved. A source's model gets its tool when the source's tools select it."
|
|
2224
|
+
}
|
|
2225
|
+
},
|
|
2226
|
+
"shadow-variants": {
|
|
2227
|
+
title: "Shadow variants",
|
|
2228
|
+
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.",
|
|
2229
|
+
loading: "Loading shadow variants…",
|
|
2230
|
+
"load-failed": "The shadow variants could not be loaded.",
|
|
2231
|
+
add: "New shadow variant",
|
|
2232
|
+
empty: "This agent has no shadow variants.",
|
|
2233
|
+
closed: {
|
|
2234
|
+
"not-allowed": "The application does not let administrators create shadow variants of this agent.",
|
|
2235
|
+
limit: "This agent has as many shadow variants as allowed ({{max}})."
|
|
2236
|
+
},
|
|
2237
|
+
source: {
|
|
2238
|
+
code: "In code",
|
|
2239
|
+
data: "Created here"
|
|
2240
|
+
},
|
|
2241
|
+
"needs-settings": "Needs run settings",
|
|
2242
|
+
"in-effect": "Receives this agent's events",
|
|
2243
|
+
open: "Run configuration",
|
|
2244
|
+
"set-up": "Set up runs",
|
|
2245
|
+
"open-named": "Open the run configuration of {{name}}",
|
|
2246
|
+
promote: "Promote onto {{name}}",
|
|
2247
|
+
"promote-named": "Promote {{variant}} onto {{name}}",
|
|
2248
|
+
"promote-confirm": {
|
|
2249
|
+
title: "Promote {{variant}} onto {{name}}?",
|
|
2250
|
+
code: "Its description, instructions, tools, required policy and autonomy become the next version of {{name}}, an agent in code, as an override until it is reset. {{name}} keeps its name, MCP servers, run settings, triggers, state and shadow mode.",
|
|
2251
|
+
admin: "Its description, instructions, tools, required policy, autonomy, profile, classification and what it works on become the next version of {{name}}. {{name}} keeps its name, MCP servers, metadata, run settings, triggers, state and shadow mode.",
|
|
2252
|
+
removed: "The variant is removed afterwards; it never goes live itself.",
|
|
2253
|
+
"move-skills": "Move its skills too",
|
|
2254
|
+
"move-skills-hint": "Each skill becomes the next live version of the skill with the same id, or a new skill that starts in shadow.",
|
|
2255
|
+
confirm: "Promote",
|
|
2256
|
+
promoting: "Promoting…"
|
|
2257
|
+
},
|
|
2258
|
+
promoted: "{{variant}} was promoted onto {{name}}, which is at version {{version}} now.",
|
|
2259
|
+
problems: {
|
|
2260
|
+
invalid: "Out of effect: a stored value is not valid.",
|
|
2261
|
+
"outside-ceiling": "Out of effect: the application no longer lets administrators create shadow variants of this agent.",
|
|
2262
|
+
"unknown-live-agent": "Out of effect: the agent it follows can no longer run on its own.",
|
|
2263
|
+
"live-agent-not-live": "Out of effect: the agent it follows is no live agent.",
|
|
2264
|
+
"too-many-variants": "Out of effect: the agent it follows has more shadow variants than the application allows."
|
|
2265
|
+
},
|
|
2266
|
+
form: {
|
|
2267
|
+
title: "New shadow variant",
|
|
2268
|
+
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.",
|
|
2269
|
+
id: "Id",
|
|
2270
|
+
"id-hint": "Lowercase letters, digits and dashes; it cannot change later.",
|
|
2271
|
+
name: "Name",
|
|
2272
|
+
"default-name": "{{name}} (variant)",
|
|
2273
|
+
description: "Description",
|
|
2274
|
+
instructions: "Instructions",
|
|
2275
|
+
"instructions-hint": "They start as this agent's instructions; change what the variant should try.",
|
|
2276
|
+
create: "Create variant"
|
|
2011
2277
|
}
|
|
2012
2278
|
},
|
|
2013
2279
|
runs: {
|
|
@@ -2040,6 +2306,225 @@ var en = {
|
|
|
2040
2306
|
id: "Account ID {{id}}",
|
|
2041
2307
|
"copy-id": "Copy the account ID of {{name}}",
|
|
2042
2308
|
"id-copied": "Account ID copied"
|
|
2309
|
+
},
|
|
2310
|
+
"instruction-assets": {
|
|
2311
|
+
source: "Where do the instructions come from?",
|
|
2312
|
+
"source-inline": "Written here",
|
|
2313
|
+
"source-inline-hint": "Type the instructions in this form.",
|
|
2314
|
+
"source-asset": "The application's text",
|
|
2315
|
+
"source-asset-hint": "Instructions the application ships or keeps, in an exact version. A new version is used only when you save it.",
|
|
2316
|
+
"not-offered": "The application no longer offers its text assets; write the instructions here to keep this working.",
|
|
2317
|
+
loading: "Loading the application's texts…",
|
|
2318
|
+
asset: "Text",
|
|
2319
|
+
"asset-hint": "The application lists the texts you can choose, each in an exact version.",
|
|
2320
|
+
choose: "Choose a text",
|
|
2321
|
+
option: "{{asset}}, version {{version}}",
|
|
2322
|
+
deprecated: "Replaced by the application",
|
|
2323
|
+
"deprecated-by": "Replaced by {{asset}}",
|
|
2324
|
+
"none-listed": "The application lists no texts; enter the id and version it gave you.",
|
|
2325
|
+
"asset-id": "Text id",
|
|
2326
|
+
version: "Version",
|
|
2327
|
+
read: "Read the text",
|
|
2328
|
+
reading: "Reading the text…",
|
|
2329
|
+
reference: "Uses {{asset}}, version {{version}}.",
|
|
2330
|
+
hash: "Hash {{hash}}",
|
|
2331
|
+
newer: "Version {{version}} of this text is available. Choose it and save to use it; the version in use stays until then.",
|
|
2332
|
+
text: "Text of the instructions",
|
|
2333
|
+
"text-hint": "Read-only: the application owns this text. Saving stores which text and version, never a copy.",
|
|
2334
|
+
"agent-problem": "The agent does not work:",
|
|
2335
|
+
problems: {
|
|
2336
|
+
"no-asset-source": "The application no longer offers its texts; the instructions are not available.",
|
|
2337
|
+
"asset-missing": "The application no longer has this text in this version.",
|
|
2338
|
+
"asset-changed": "The text changed since it was saved, so it is not used. Read it again and save to use the new text.",
|
|
2339
|
+
"asset-invalid": "This text cannot be used as instructions.",
|
|
2340
|
+
"asset-unavailable": "The application's texts could not be read; they are read again shortly."
|
|
2341
|
+
},
|
|
2342
|
+
errors: {
|
|
2343
|
+
required: "Choose a text and read it first.",
|
|
2344
|
+
"not-found": "The application has no such text in this version.",
|
|
2345
|
+
changed: "The text changed since you read it. Read it again before you save.",
|
|
2346
|
+
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.",
|
|
2347
|
+
"not-allowed": "The application does not offer its texts here."
|
|
2348
|
+
}
|
|
2349
|
+
},
|
|
2350
|
+
packages: {
|
|
2351
|
+
"export": "Export as package",
|
|
2352
|
+
"export-named": "Export {{name}} as a package",
|
|
2353
|
+
"import": "Import package",
|
|
2354
|
+
"linked-badge": "Package {{package}} {{version}}",
|
|
2355
|
+
"delete-locked": "The agent belongs to package {{package}}. Unlink the agent first to delete it.",
|
|
2356
|
+
"remove-locked": "Package {{package}} locks this part. Unlink it first to remove it.",
|
|
2357
|
+
lock: {
|
|
2358
|
+
linked: "Linked to package {{package}}, version {{version}}.",
|
|
2359
|
+
"agent-linked": "This agent comes from package {{package}}, version {{version}}.",
|
|
2360
|
+
whole: "The package locks it as a whole: it changes with the package's next version.",
|
|
2361
|
+
fields: "Locked: {{fields}}.",
|
|
2362
|
+
"nothing-locked": "Nothing of it is locked; the package's next version overwrites a change made here.",
|
|
2363
|
+
field: "Locked by package {{package}}, version {{version}}",
|
|
2364
|
+
unlink: "Unlink",
|
|
2365
|
+
"unlink-agent": "Unlink the agent",
|
|
2366
|
+
"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.",
|
|
2367
|
+
"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.",
|
|
2368
|
+
"confirm-unlink": "Unlink"
|
|
2369
|
+
},
|
|
2370
|
+
parts: {
|
|
2371
|
+
agent: "Agent",
|
|
2372
|
+
"run-settings": "Run settings",
|
|
2373
|
+
skill: "Skill {{name}}",
|
|
2374
|
+
trigger: "Trigger {{name}}",
|
|
2375
|
+
consultation: "Consultation about {{name}}",
|
|
2376
|
+
"hand-off": "Hand-off about {{name}}",
|
|
2377
|
+
metadata: "Field {{name}}"
|
|
2378
|
+
},
|
|
2379
|
+
outcomes: {
|
|
2380
|
+
created: "New",
|
|
2381
|
+
changed: "Changed",
|
|
2382
|
+
unchanged: "Unchanged",
|
|
2383
|
+
"kept-local": "Kept local",
|
|
2384
|
+
"left-behind": "Left behind",
|
|
2385
|
+
refused: "Refused"
|
|
2386
|
+
},
|
|
2387
|
+
"outcome-explain": {
|
|
2388
|
+
created: "The import adds it.",
|
|
2389
|
+
changed: "The import replaces it with the package's version.",
|
|
2390
|
+
unchanged: "It is the same as the package's version.",
|
|
2391
|
+
"kept-local": "It was unlinked here, so the import leaves it as it is unless you take the package's version.",
|
|
2392
|
+
"left-behind": "The package no longer holds this agent: it stays here, unlinked.",
|
|
2393
|
+
refused: "The import refuses it, and with it the whole package."
|
|
2394
|
+
},
|
|
2395
|
+
"changed-locally": "Changed locally",
|
|
2396
|
+
"changed-locally-hint": "Someone changed it here since it was imported; the import overwrites that change.",
|
|
2397
|
+
"export-dialog": {
|
|
2398
|
+
title: "Export agents as a package",
|
|
2399
|
+
close: "Close",
|
|
2400
|
+
agents: "Agents in the package",
|
|
2401
|
+
"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.",
|
|
2402
|
+
"agents-required": "Choose at least one agent.",
|
|
2403
|
+
"too-many": "A package holds at most {{max}} agents.",
|
|
2404
|
+
"package-id": "Package id",
|
|
2405
|
+
"package-id-hint": "Lowercase letters, digits and dashes. A host upgrades the agents it imported from the same package id.",
|
|
2406
|
+
"package-id-default": "Empty: {{id}}",
|
|
2407
|
+
version: "Version",
|
|
2408
|
+
"version-hint": "A whole number from 1. Empty: the next version after the one this host imported, otherwise 1.",
|
|
2409
|
+
description: "Description",
|
|
2410
|
+
"description-hint": "Optional: what the package is for, for whoever imports it.",
|
|
2411
|
+
locks: "Locks",
|
|
2412
|
+
"locks-hint": "Where the package is imported, a locked part shows read-only and saving refuses to change it until an administrator unlinks it.",
|
|
2413
|
+
"lock-none": "Not locked",
|
|
2414
|
+
"lock-whole": "All of it",
|
|
2415
|
+
"lock-fields": "Chosen fields",
|
|
2416
|
+
"lock-choice": "Lock {{part}}",
|
|
2417
|
+
"lock-fields-of": "Fields of {{part}} to lock",
|
|
2418
|
+
"loading-parts": "Reading the parts of the agents…",
|
|
2419
|
+
"parts-failed": "The parts of the agents could not be read.",
|
|
2420
|
+
"no-parts": "Nothing of this agent travels as data.",
|
|
2421
|
+
references: "References outside the package",
|
|
2422
|
+
"references-hint": "These agents are not in the package, so they must exist where it is imported.",
|
|
2423
|
+
add: "Add {{agent}}",
|
|
2424
|
+
download: "Download package",
|
|
2425
|
+
downloading: "Exporting…",
|
|
2426
|
+
downloaded: "The package was downloaded as {{file}}.",
|
|
2427
|
+
reference: {
|
|
2428
|
+
"hand-off-source": "{{referenced}} hands work to {{agent}} ({{part}}).",
|
|
2429
|
+
"shadow-of": "{{agent}} is a shadow variant of {{referenced}}.",
|
|
2430
|
+
"consultation-asker": "{{referenced}} consults {{agent}} ({{part}}).",
|
|
2431
|
+
"shadow-variant": "{{referenced}} is a shadow variant of {{agent}} and receives its triggers."
|
|
2432
|
+
}
|
|
2433
|
+
},
|
|
2434
|
+
"import-dialog": {
|
|
2435
|
+
title: "Import an agent package",
|
|
2436
|
+
close: "Close",
|
|
2437
|
+
file: "Package file",
|
|
2438
|
+
"file-hint": "A JSON file of at most 1 MB, as an export writes it.",
|
|
2439
|
+
"file-chosen": "Read from {{name}}.",
|
|
2440
|
+
paste: "Or paste the package",
|
|
2441
|
+
"paste-hint": "The JSON of the package.",
|
|
2442
|
+
"invalid-json": "This is no package: its JSON cannot be read.",
|
|
2443
|
+
"too-large": "A package is at most 1 MB.",
|
|
2444
|
+
"no-package": "Choose a package file or paste a package first.",
|
|
2445
|
+
preview: "Check the package",
|
|
2446
|
+
previewing: "Checking…",
|
|
2447
|
+
"preview-again": "Check again",
|
|
2448
|
+
"preview-title": "What the import does",
|
|
2449
|
+
summary: "Package {{package}}, version {{version}}",
|
|
2450
|
+
"agent-heading": "Agent {{agent}}",
|
|
2451
|
+
"column-part": "Part",
|
|
2452
|
+
"column-outcome": "Outcome",
|
|
2453
|
+
"column-details": "Details",
|
|
2454
|
+
"column-relink": "Package's version",
|
|
2455
|
+
relink: "Take the package's version of {{part}}",
|
|
2456
|
+
"relink-hint": "Relinks the part: the import overwrites the local version and links it to the package again.",
|
|
2457
|
+
account: "Technical account of {{agent}}",
|
|
2458
|
+
"account-hint": "Accounts never travel: choose the account on this host that the agent answers to.",
|
|
2459
|
+
apply: "Changed skills and triggers",
|
|
2460
|
+
"apply-live": "Take effect at once",
|
|
2461
|
+
"apply-live-hint": "Each change becomes the live version, as a save does.",
|
|
2462
|
+
"apply-shadow": "Run in shadow first",
|
|
2463
|
+
"apply-shadow-hint": "Each change becomes a candidate next to the live version, to compare and promote.",
|
|
2464
|
+
"apply-new-hint": "New skills and triggers start in shadow either way.",
|
|
2465
|
+
refused: "The import refuses {{count}} parts. Fix the package or the host, then check again.",
|
|
2466
|
+
"options-changed": "The choices changed since the check; check again before importing.",
|
|
2467
|
+
"import": "Import",
|
|
2468
|
+
importing: "Importing…",
|
|
2469
|
+
imported: "The package was imported.",
|
|
2470
|
+
"result-title": "What the import did",
|
|
2471
|
+
done: "Done",
|
|
2472
|
+
"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.",
|
|
2473
|
+
"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.",
|
|
2474
|
+
"agent-exists-in-code": "An agent in code has this id on this host; the package's agent cannot replace it.",
|
|
2475
|
+
"take-over": "Take over the existing agent",
|
|
2476
|
+
"take-over-hint": "The package replaces its configuration and links it.",
|
|
2477
|
+
"refused-one": "The import refuses {{count}} part. Fix the package or the host, then check again."
|
|
2478
|
+
},
|
|
2479
|
+
fields: {
|
|
2480
|
+
"display-name": "Name",
|
|
2481
|
+
description: "Description",
|
|
2482
|
+
instructions: "Instructions",
|
|
2483
|
+
"tool-selectors": "Tools",
|
|
2484
|
+
"required-policy": "Required policy",
|
|
2485
|
+
autonomy: "Autonomy",
|
|
2486
|
+
"offered-in-chat": "Use in the chat",
|
|
2487
|
+
"works-on": "What it works on",
|
|
2488
|
+
profile: "Model profile",
|
|
2489
|
+
"data-classification": "Data classification",
|
|
2490
|
+
accountability: "Answers to",
|
|
2491
|
+
"delegate-from-initiator": "Rights of the person who starts a run",
|
|
2492
|
+
"allow-gateway-reads": "Reads through the data gateway",
|
|
2493
|
+
"elevated-reads": "Reads with the account's rights",
|
|
2494
|
+
"approval-policy": "Approval policy",
|
|
2495
|
+
"retry-count": "Retries after a failure",
|
|
2496
|
+
"daily-budget": "Daily limits",
|
|
2497
|
+
"max-concurrent-runs": "Runs at the same time",
|
|
2498
|
+
"max-runs-per-subject-per-day": "Runs per subject per day",
|
|
2499
|
+
"max-tokens-per-run": "Tokens per run",
|
|
2500
|
+
"triage-profile": "Triage profile",
|
|
2501
|
+
"rule-handler": "Way of working",
|
|
2502
|
+
files: "Files",
|
|
2503
|
+
tools: "Tools",
|
|
2504
|
+
skill: "Skill",
|
|
2505
|
+
source: "When it starts",
|
|
2506
|
+
event: "Event",
|
|
2507
|
+
filters: "Filters",
|
|
2508
|
+
cron: "Schedule",
|
|
2509
|
+
"time-zone": "Time zone",
|
|
2510
|
+
"subject-set": "Subjects",
|
|
2511
|
+
message: "Message to every run",
|
|
2512
|
+
conflict: "While a run is busy",
|
|
2513
|
+
"debounce-seconds": "Wait for more events",
|
|
2514
|
+
"minimum-role": "Role of the person who asks",
|
|
2515
|
+
"asker-policy": "Policy of the person who asks",
|
|
2516
|
+
routes: "Routes",
|
|
2517
|
+
"proposal-role": "Role before it proposes",
|
|
2518
|
+
"proposal-policy": "Approval policy of its proposals",
|
|
2519
|
+
limits: "Limits",
|
|
2520
|
+
"allow-requests": "Requests",
|
|
2521
|
+
"expose-to-mcp": "MCP clients",
|
|
2522
|
+
sources: "Agents that may hand off",
|
|
2523
|
+
"notify-source": "Tells the source how it ended",
|
|
2524
|
+
"max-per-subject-per-day": "Hand-offs per source and object per day",
|
|
2525
|
+
value: "Value"
|
|
2526
|
+
},
|
|
2527
|
+
"reset-locked": "Package {{package}} locks fields of the definition. Unlink them first to reset the agent."
|
|
2043
2528
|
}
|
|
2044
2529
|
},
|
|
2045
2530
|
"page-context": {
|
|
@@ -2054,6 +2539,11 @@ var en = {
|
|
|
2054
2539
|
waiting: "Waiting for approval",
|
|
2055
2540
|
unread: "Unread"
|
|
2056
2541
|
},
|
|
2542
|
+
document: {
|
|
2543
|
+
"diagram-failed": "This diagram could not be drawn: {{reason}}",
|
|
2544
|
+
"diagram-no-reason": "the renderer gave no reason.",
|
|
2545
|
+
"diagram-not-svg": "the renderer returned no SVG."
|
|
2546
|
+
},
|
|
2057
2547
|
share: {
|
|
2058
2548
|
title: "Share conversation",
|
|
2059
2549
|
"members-title": "People in this conversation",
|
|
@@ -2176,6 +2666,10 @@ var en = {
|
|
|
2176
2666
|
"re-execute": "Run again",
|
|
2177
2667
|
"mark-resolved": "Mark as resolved",
|
|
2178
2668
|
"unknown-hint": "The execution stopped without a known outcome. Check whether it happened before you run it again.",
|
|
2669
|
+
"hand-to-application": "Hand to the application again",
|
|
2670
|
+
"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.",
|
|
2671
|
+
"awaiting-application-hint": "The application carries out this approved proposal and reports back when it is done.",
|
|
2672
|
+
"report-due": "Report due {{date}}",
|
|
2179
2673
|
mode: {
|
|
2180
2674
|
inline: "The run waits",
|
|
2181
2675
|
deferred: "Decide later"
|
|
@@ -2188,6 +2682,7 @@ var en = {
|
|
|
2188
2682
|
withdrawn: "Withdrawn",
|
|
2189
2683
|
stale: "Outdated",
|
|
2190
2684
|
executing: "Running",
|
|
2685
|
+
"awaiting-application": "With the application",
|
|
2191
2686
|
executed: "Done",
|
|
2192
2687
|
"execution-failed": "Failed",
|
|
2193
2688
|
"execution-unknown": "Outcome unknown",
|
|
@@ -2516,7 +3011,9 @@ var nl = {
|
|
|
2516
3011
|
running: "De assistent is bezig",
|
|
2517
3012
|
"waiting-for-approval": "Wacht op goedkeuring",
|
|
2518
3013
|
"running-by": "{{name}} werkt met de assistent…",
|
|
2519
|
-
"waiting-for-approval-by": "Wacht op de beslissing van {{name}}…"
|
|
3014
|
+
"waiting-for-approval-by": "Wacht op de beslissing van {{name}}…",
|
|
3015
|
+
"waiting-for-answer": "Wacht op een antwoord op de vraag",
|
|
3016
|
+
"waiting-for-answer-by": "Wacht op het antwoord van {{name}}…"
|
|
2520
3017
|
},
|
|
2521
3018
|
attach: "Bestanden bijvoegen",
|
|
2522
3019
|
"attach-hint": "{{types}}, elk tot {{max}}, hoogstens {{count}} bestanden per bericht",
|
|
@@ -2562,6 +3059,7 @@ var nl = {
|
|
|
2562
3059
|
succeeded: "Voltooid",
|
|
2563
3060
|
failed: "Mislukt",
|
|
2564
3061
|
"awaiting-approval": "Wacht op goedkeuring",
|
|
3062
|
+
"awaiting-answer": "Wacht op antwoord",
|
|
2565
3063
|
rejected: "Afgewezen",
|
|
2566
3064
|
"not-executed": "Niet uitgevoerd"
|
|
2567
3065
|
},
|
|
@@ -2580,6 +3078,7 @@ var nl = {
|
|
|
2580
3078
|
"tool-group": {
|
|
2581
3079
|
running: "Roept {{name}} aan…",
|
|
2582
3080
|
"awaiting-approval": "Wacht op goedkeuring: {{name}}",
|
|
3081
|
+
"awaiting-answer": "Wacht op een antwoord",
|
|
2583
3082
|
"used-one": "1 tool gebruikt",
|
|
2584
3083
|
"used-many": "{{count}} tools gebruikt",
|
|
2585
3084
|
progress: "{{finished}} van {{total}} klaar",
|
|
@@ -2610,6 +3109,7 @@ var nl = {
|
|
|
2610
3109
|
withdrawn: "Ingetrokken",
|
|
2611
3110
|
stale: "Verouderd",
|
|
2612
3111
|
executing: "Wordt uitgevoerd",
|
|
3112
|
+
"awaiting-application": "Bij de applicatie",
|
|
2613
3113
|
executed: "Uitgevoerd",
|
|
2614
3114
|
"execution-failed": "Mislukt",
|
|
2615
3115
|
"execution-unknown": "Uitkomst onbekend",
|
|
@@ -2620,6 +3120,12 @@ var nl = {
|
|
|
2620
3120
|
"waiting-for-participant": "Wacht op de beslissing van de deelnemer die deze taak startte.",
|
|
2621
3121
|
"waiting-for-approver": "Wacht tot een beslisser hierover beslist.",
|
|
2622
3122
|
"waiting-for-other-approver": "Jij startte dit werk, dus een andere beslisser beslist hierover.",
|
|
3123
|
+
resolve: {
|
|
3124
|
+
explanation: "Het is niet bekend of de applicatie dit heeft uitgevoerd. Controleer het en geef het opnieuw aan de applicatie of markeer het als afgehandeld.",
|
|
3125
|
+
"hand-to-application": "Opnieuw aan de applicatie geven",
|
|
3126
|
+
"mark-resolved": "Markeren als afgehandeld",
|
|
3127
|
+
resolving: "Je keuze wordt verstuurd"
|
|
3128
|
+
},
|
|
2623
3129
|
"waiting-for-asker": "Wacht tot degene die het vroeg, beslist in de eigen chat.",
|
|
2624
3130
|
"give-feedback": "Wat klopte er niet?",
|
|
2625
3131
|
"stale-kind": {
|
|
@@ -2643,6 +3149,24 @@ var nl = {
|
|
|
2643
3149
|
moved: "Het wacht nu op de goedkeurders van {{subject}}."
|
|
2644
3150
|
}
|
|
2645
3151
|
},
|
|
3152
|
+
question: {
|
|
3153
|
+
title: "Vraag",
|
|
3154
|
+
status: {
|
|
3155
|
+
pending: "Wacht op antwoord",
|
|
3156
|
+
answered: "Beantwoord",
|
|
3157
|
+
expired: "Verlopen",
|
|
3158
|
+
cancelled: "Ingetrokken"
|
|
3159
|
+
},
|
|
3160
|
+
choices: "Antwoorden",
|
|
3161
|
+
"choose-label": "Antwoord: {{choice}}",
|
|
3162
|
+
"expires-in": "Antwoord binnen {{time}}",
|
|
3163
|
+
answering: "Je antwoord wordt verstuurd",
|
|
3164
|
+
"waiting-for": "Wacht op het antwoord van {{name}}.",
|
|
3165
|
+
"waiting-for-participant": "Wacht op het antwoord van de persoon aan wie de vraag is gesteld.",
|
|
3166
|
+
answered: "Antwoord: {{choice}}",
|
|
3167
|
+
expired: "Niemand heeft op tijd geantwoord.",
|
|
3168
|
+
cancelled: "De vraag is ingetrokken toen de taak werd gestopt."
|
|
3169
|
+
},
|
|
2646
3170
|
"proposal-feedback": {
|
|
2647
3171
|
legend: "Wat klopte er niet? (optioneel)",
|
|
2648
3172
|
bulk: "Geldt voor de {{count}} voorstellen die je hebt afgewezen.",
|
|
@@ -2753,6 +3277,7 @@ var nl = {
|
|
|
2753
3277
|
"assistant-message-too-long": "Het bericht is te lang. Maak het korter en verstuur het opnieuw.",
|
|
2754
3278
|
"assistant-model-unavailable": "Het taalmodel is tijdelijk niet beschikbaar. Probeer het zo opnieuw.",
|
|
2755
3279
|
"assistant-classification-not-permitted": "Het model dat deze agent gebruikt mag geen gegevens met de classificatie van de agent ontvangen. Vraag een beheerder een modelprofiel te kiezen dat dit toestaat.",
|
|
3280
|
+
"assistant-model-region-denied": "Het model dat deze agent gebruikt mag niet draaien in de regio waarin de applicatie werkt. Vraag een beheerder een modelprofiel te kiezen dat die regio toestaat.",
|
|
2756
3281
|
"assistant-files-unavailable": "Deze applicatie geeft de assistent geen bestanden.",
|
|
2757
3282
|
"assistant-files-not-accepted": "Deze agent neemt geen bestanden aan. Een beheerder kan bestanden voor hem aanzetten.",
|
|
2758
3283
|
"assistant-file-reference-invalid": "Een bestand kon niet worden gelezen omdat de verwijzing ongeldig is.",
|
|
@@ -2846,15 +3371,18 @@ var nl = {
|
|
|
2846
3371
|
"assistant-consult-depth-exceeded": "Deze raadpleging zou agents in een kring of te diep laten vragen.",
|
|
2847
3372
|
"assistant-consult-budget-exhausted": "Het dagbudget van de agent is op.",
|
|
2848
3373
|
"assistant-consult-limit-reached": "Je hebt het aantal raadplegingen voor vandaag bereikt.",
|
|
3374
|
+
"assistant-consult-turn-limit": "De assistent heeft het aantal raadplegingen voor dit antwoord bereikt.",
|
|
2849
3375
|
"assistant-consult-timeout": "De agent antwoordde niet op tijd.",
|
|
2850
3376
|
"assistant-consult-failed": "De agent kon niet antwoorden.",
|
|
2851
3377
|
"assistant-consult-read-only": "Een raadpleging kan niets wijzigen.",
|
|
3378
|
+
"assistant-consult-tool-not-selected": "Deze raadpleging biedt die tool niet aan, dus er is niets uitgevoerd.",
|
|
2852
3379
|
"assistant-consult-proposal-refused": "Geen route bij het onderwerp neemt dit voorstel nog aan. Keur het hier goed of af.",
|
|
2853
3380
|
"assistant-consult-asker-decides": "Degene die het vroeg, beslist over dit voorstel in de eigen chat.",
|
|
2854
3381
|
"assistant-consult-route-not-allowed": "Geen van de raadplegingen van de agent staat deze route toe, dus die kan niet aan.",
|
|
2855
3382
|
"assistant-consult-proposal-moved": "Het voorstel is aan de goedkeurders van het onderwerp gelaten.",
|
|
2856
3383
|
"assistant-moved-to-shadow": "Het werk is naar de schaduwthread van de agent gegaan, waar een run in schaduw het oppakt.",
|
|
2857
3384
|
"assistant-shadow-variant": "Een schaduwvariant werkt altijd in schaduw.",
|
|
3385
|
+
"assistant-not-shadow-variant": "Alleen een hier gemaakte schaduwvariant kan naar zijn live agent worden gepromoveerd.",
|
|
2858
3386
|
"assistant-service-account-not-used": "Deze agent werkt niet onder een technisch account.",
|
|
2859
3387
|
"assistant-service-account-not-found": "Er bestaat geen account met deze id dat mag inloggen.",
|
|
2860
3388
|
"assistant-skill-in-code": "Deze vaardigheid staat in de code en kan hier niet veranderen.",
|
|
@@ -2863,8 +3391,9 @@ var nl = {
|
|
|
2863
3391
|
"assistant-skill-in-use": "Een trigger start deze vaardigheid nog. Pas de trigger eerst aan of verwijder hem.",
|
|
2864
3392
|
"assistant-configuration-limit": "Deze agent heeft al zoveel vaardigheden, triggers of raadplegingen als is toegestaan.",
|
|
2865
3393
|
"assistant-run-settings-in-code": "Deze agent staat in de code; daar is ingesteld hoe hij werkt.",
|
|
2866
|
-
"assistant-run-settings-in-use": "Er horen nog vaardigheden, triggers of
|
|
3394
|
+
"assistant-run-settings-in-use": "Er horen nog vaardigheden, triggers, raadplegingen of overdrachten bij deze agent. Verwijder die eerst.",
|
|
2867
3395
|
"assistant-skill-candidate-not-found": "Van deze vaardigheid wordt geen versie in schaduw beoordeeld.",
|
|
3396
|
+
"assistant-trigger-candidate-not-found": "Van deze trigger wordt geen versie in schaduw beoordeeld.",
|
|
2868
3397
|
"assistant-skill-version-gone": "De versie van de vaardigheid waarvoor deze run was, wordt niet meer beoordeeld.",
|
|
2869
3398
|
"assistant-account-search-unavailable": "De applicatie biedt geen accountzoeker; vul de id van het account in.",
|
|
2870
3399
|
"assistant-mcp-connection-required": "Deze server moet eerst gekoppeld worden. Koppel hem en probeer het opnieuw.",
|
|
@@ -2894,7 +3423,28 @@ var nl = {
|
|
|
2894
3423
|
"assistant-file-scan-refused": "Het bestand is niet door de scan op schadelijke inhoud gekomen en is niet opgeslagen.",
|
|
2895
3424
|
"assistant-consultation-in-code": "De agent staat raadpleging over deze soort object in code toe; die kan hier niet veranderen.",
|
|
2896
3425
|
"assistant-consultation-not-found": "De raadpleging is niet gevonden.",
|
|
2897
|
-
"assistant-consultations-not-allowed": "De applicatie laat beheerders geen raadplegingen aan deze agent toevoegen."
|
|
3426
|
+
"assistant-consultations-not-allowed": "De applicatie laat beheerders geen raadplegingen aan deze agent toevoegen.",
|
|
3427
|
+
"assistant-handoffs-not-allowed": "De applicatie laat beheerders geen agents aan deze agent koppelen.",
|
|
3428
|
+
"assistant-handoff-in-code": "De agent neemt overdrachten over deze soort object in code aan; die kan hier niet veranderen.",
|
|
3429
|
+
"assistant-handoff-not-found": "De overdracht is niet gevonden.",
|
|
3430
|
+
"assistant-shadow-variants-not-allowed": "De applicatie laat beheerders geen schaduwvarianten van deze agent maken.",
|
|
3431
|
+
"assistant-metadata-entry-not-found": "De applicatie kent dit veld van agents niet.",
|
|
3432
|
+
"assistant-metadata-read-only": "De applicatie zet dit veld van de agent in haar code; het kan hier niet veranderen.",
|
|
3433
|
+
"assistant-instructions-asset-not-found": "De applicatie heeft deze tekst niet in deze versie.",
|
|
3434
|
+
"assistant-instructions-asset-unavailable": "De teksten van de applicatie zijn nu niet te lezen. Er is niets opgeslagen; probeer het zo opnieuw.",
|
|
3435
|
+
"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.",
|
|
3436
|
+
"assistant-package-format-unsupported": "Dit is geen agentpakket dat deze versie kan lezen: het formaat, de formaatversie of een eigenschap is onbekend.",
|
|
3437
|
+
"assistant-package-locked": "Een agentpakket vergrendelt dit. Ontkoppel het eerst van het pakket.",
|
|
3438
|
+
"assistant-package-too-large": "Een agentpakket is hoogstens 1 MB en bevat hoogstens 20 agents.",
|
|
3439
|
+
"assistant-package-refused": "De controle weigerde onderdelen van het pakket, dus er is niets geïmporteerd. Controleer het pakket opnieuw om te zien welke.",
|
|
3440
|
+
"assistant-package-not-linked": "Deze agent, of dit onderdeel ervan, is niet aan een agentpakket gekoppeld.",
|
|
3441
|
+
"assistant-question-invalid": "De assistent kon deze vraag niet stellen; hij gaat verder zonder.",
|
|
3442
|
+
"assistant-question-not-found": "Deze vraag is niet gevonden.",
|
|
3443
|
+
"assistant-question-not-pending": "Deze vraag wacht niet meer op een antwoord.",
|
|
3444
|
+
"assistant-question-forbidden": "Deze vraag is aan iemand anders gesteld.",
|
|
3445
|
+
"assistant-question-expired": "Niemand heeft deze vraag op tijd beantwoord. Stuur je bericht opnieuw om verder te gaan.",
|
|
3446
|
+
"assistant-question-cancelled": "De vraag is ingetrokken toen de taak werd gestopt.",
|
|
3447
|
+
"assistant-question-answer-invalid": "Kies een van de antwoorden van de vraag."
|
|
2898
3448
|
},
|
|
2899
3449
|
notices: {
|
|
2900
3450
|
"no-answer": "De assistent is klaar zonder antwoord. Probeer het opnieuw of stel je vraag anders.",
|
|
@@ -3278,7 +3828,26 @@ var nl = {
|
|
|
3278
3828
|
"in-code": "In deze groep in de code",
|
|
3279
3829
|
"shadow-variant": "Een schaduwvariant werkt alleen voor beheerders en hoort bij geen groep."
|
|
3280
3830
|
},
|
|
3281
|
-
|
|
3831
|
+
metadata: {
|
|
3832
|
+
title: "Applicatievelden",
|
|
3833
|
+
hint: "De applicatie bewaart hier haar eigen gegevens over agents. Elk veld heeft een editor van de applicatie, die het zelf opslaat.",
|
|
3834
|
+
"save-first": "Sla de agent eerst op; daarna verschijnen zijn velden hier.",
|
|
3835
|
+
loading: "De velden worden geladen",
|
|
3836
|
+
"load-failed": "De velden van deze agent konden niet worden geladen.",
|
|
3837
|
+
"no-editor": "De applicatie toont geen editor voor dit veld.",
|
|
3838
|
+
"read-only": "Ingesteld in de code van de applicatie; het kan hier niet veranderen.",
|
|
3839
|
+
saved: "Opgeslagen.",
|
|
3840
|
+
removed: "Verwijderd.",
|
|
3841
|
+
source: {
|
|
3842
|
+
code: "Uit de code",
|
|
3843
|
+
override: "Hier gewijzigd, boven de waarde in de code",
|
|
3844
|
+
data: "Opgeslagen bij de agent",
|
|
3845
|
+
none: "Geen waarde"
|
|
3846
|
+
}
|
|
3847
|
+
},
|
|
3848
|
+
"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.",
|
|
3849
|
+
"starts-in-shadow": "In schaduw beginnen",
|
|
3850
|
+
"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."
|
|
3282
3851
|
},
|
|
3283
3852
|
effect: {
|
|
3284
3853
|
"read-only": "Alleen lezen",
|
|
@@ -3637,7 +4206,9 @@ var nl = {
|
|
|
3637
4206
|
skill: "Vaardigheid {{id}}:",
|
|
3638
4207
|
candidate: "Kandidaat van vaardigheid {{id}}:",
|
|
3639
4208
|
trigger: "Trigger {{id}}:",
|
|
3640
|
-
consultation: "Raadpleging over {{id}}:"
|
|
4209
|
+
consultation: "Raadpleging over {{id}}:",
|
|
4210
|
+
"hand-off": "Overdracht over {{id}}:",
|
|
4211
|
+
"trigger-candidate": "Kandidaat van trigger {{id}}:"
|
|
3641
4212
|
},
|
|
3642
4213
|
code: {
|
|
3643
4214
|
"unknown-agent": "de agent kan niet meer zelfstandig werken.",
|
|
@@ -3664,7 +4235,18 @@ var nl = {
|
|
|
3664
4235
|
"no-approver": "de route met het account van de agent valt weg, omdat het goedkeuringsbeleid alleen degene die een voorstel veroorzaakte laat beslissen.",
|
|
3665
4236
|
"limit-above-ceiling": "een grens ligt boven wat de applicatie toestaat, dus die van de applicatie geldt.",
|
|
3666
4237
|
"requests-not-allowed": "de applicatie staat geen verzoeken meer toe, dus ze neemt er geen aan.",
|
|
3667
|
-
"mcp-not-allowed": "de applicatie biedt raadplegingen niet meer aan MCP-clients aan, dus die zien haar niet."
|
|
4238
|
+
"mcp-not-allowed": "de applicatie biedt raadplegingen niet meer aan MCP-clients aan, dus die zien haar niet.",
|
|
4239
|
+
"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.",
|
|
4240
|
+
"no-asset-source": "de instructies komen uit de teksten van de applicatie, die de applicatie niet meer aanbiedt.",
|
|
4241
|
+
"asset-missing": "de applicatie heeft de tekst met de instructies niet meer in deze versie.",
|
|
4242
|
+
"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.",
|
|
4243
|
+
"asset-invalid": "de tekst van de applicatie is niet te gebruiken als instructies.",
|
|
4244
|
+
"asset-unavailable": "de teksten van de applicatie waren niet te lezen; ze worden zo opnieuw gelezen.",
|
|
4245
|
+
"outside-ceiling": "de applicatie staat het niet meer toe.",
|
|
4246
|
+
"unknown-source": "een agent die mag overdragen kan niet meer zelfstandig werken.",
|
|
4247
|
+
"unknown-live-agent": "de agent die deze schaduwvariant volgt kan niet meer zelfstandig werken.",
|
|
4248
|
+
"live-agent-not-live": "de agent die deze schaduwvariant volgt is geen live agent.",
|
|
4249
|
+
"too-many-variants": "de agent die hij volgt heeft meer schaduwvarianten dan de applicatie toestaat."
|
|
3668
4250
|
}
|
|
3669
4251
|
},
|
|
3670
4252
|
"field-errors": {
|
|
@@ -3683,7 +4265,10 @@ var nl = {
|
|
|
3683
4265
|
"megabytes-up-to": "Vul een grootte in boven 0 en hooguit {{max}} MB.",
|
|
3684
4266
|
"megabytes-positive": "Vul een grootte in boven 0 MB.",
|
|
3685
4267
|
"not-allowed": "De applicatie staat dit niet toe.",
|
|
3686
|
-
"routes-required": "Kies minstens één route, of laat hem alleen antwoorden."
|
|
4268
|
+
"routes-required": "Kies minstens één route, of laat hem alleen antwoorden.",
|
|
4269
|
+
"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.",
|
|
4270
|
+
locked: "Een agentpakket vergrendelt dit veld. Ontkoppel het onderdeel eerst om het te wijzigen.",
|
|
4271
|
+
"region-not-permitted": "Dit modelprofiel mag niet draaien in de regio waarin de applicatie werkt, en zijn terugvalprofielen ook niet. Kies een profiel dat de regio toestaat."
|
|
3687
4272
|
},
|
|
3688
4273
|
settings: {
|
|
3689
4274
|
title: "Runinstellingen",
|
|
@@ -3926,6 +4511,24 @@ var nl = {
|
|
|
3926
4511
|
"set-hint": "Telkens één run voor elk object in een verzameling, zoals de actieve projecten.",
|
|
3927
4512
|
"every-division": "Elke divisie",
|
|
3928
4513
|
dropped: "Dit schema draaide voor de hele applicatie, waaraan de agent niet meer werkt. Kies een verzameling objecten."
|
|
4514
|
+
},
|
|
4515
|
+
"saved-candidate": "De nieuwe versie vuurt in schaduw naast de live versie, die blijft werken.",
|
|
4516
|
+
apply: "Hoe de wijziging ingaat",
|
|
4517
|
+
"apply-live": "Direct toepassen",
|
|
4518
|
+
"apply-live-hint": "De nieuwe versie vervangt de live versie meteen, in de modus van de trigger.",
|
|
4519
|
+
"apply-shadow": "Eerst in schaduw beoordelen naast de live versie",
|
|
4520
|
+
"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.",
|
|
4521
|
+
versions: "Versies",
|
|
4522
|
+
candidate: {
|
|
4523
|
+
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.",
|
|
4524
|
+
"out-of-effect": "De kandidaat vuurt niet: hij past niet meer bij de code ({{problem}}). De live versie blijft werken.",
|
|
4525
|
+
changes: "Wat de kandidaat verandert",
|
|
4526
|
+
"no-changes": "De kandidaat heeft dezelfde definitie als de live versie.",
|
|
4527
|
+
change: "{{candidate}} (live: {{live}})",
|
|
4528
|
+
comparison: "Live versie en kandidaat van trigger {{trigger}}",
|
|
4529
|
+
paired: "Sinds {{date}} startten beide een run op {{count}} dezelfde gebeurtenissen, alleen de live versie op {{liveOnly}} en alleen de kandidaat op {{candidateOnly}}.",
|
|
4530
|
+
promoted: "De kandidaat is nu de live versie van de trigger.",
|
|
4531
|
+
none: "geen"
|
|
3929
4532
|
}
|
|
3930
4533
|
},
|
|
3931
4534
|
"way-of-working": "Werkwijze",
|
|
@@ -4176,6 +4779,9 @@ var nl = {
|
|
|
4176
4779
|
"no-askers": "Nog geen agent vraagt het. Selecteer de tool bij de tools van een agent die het moet vragen.",
|
|
4177
4780
|
"code-hint": "Toegestaan in code; hier veranderen alleen de routeschakelaars hieronder iets.",
|
|
4178
4781
|
"limits-value": "Hooguit {{calls}} toolaanroepen, {{seconds}} seconden, {{chars}} tekens en {{history}} berichten uit de thread",
|
|
4782
|
+
"tools-label": "Tools:",
|
|
4783
|
+
"tools-all": "alle tools van de agent",
|
|
4784
|
+
"tools-none": "geen, want geen gekozen tool hoort nog bij de eigen tools van de agent",
|
|
4179
4785
|
"edit-named": "De raadpleging over {{type}} bewerken",
|
|
4180
4786
|
"remove-named": "De raadpleging over {{type}} verwijderen",
|
|
4181
4787
|
"remove-explain": "Haar tools verdwijnen; voorstellen die ze deed, kunnen nog worden beslist.",
|
|
@@ -4257,7 +4863,7 @@ var nl = {
|
|
|
4257
4863
|
"four-eyes": "Dit goedkeuringsbeleid vraagt vier ogen, dus degene die het vroeg kan het eigen voorstel niet in de eigen chat beslissen; die route geldt dan niet.",
|
|
4258
4864
|
"initiator-only": "Dit goedkeuringsbeleid laat alleen degene die een voorstel veroorzaakte erover beslissen, dus de route met het technische account van de agent wordt geweigerd."
|
|
4259
4865
|
},
|
|
4260
|
-
advanced: "Geavanceerd: grenzen, verzoeken en classificatie",
|
|
4866
|
+
advanced: "Geavanceerd: tools, grenzen, verzoeken en classificatie",
|
|
4261
4867
|
limits: "Grenzen van één raadpleging",
|
|
4262
4868
|
"limits-hint": "Leeg begint bij de standaard binnen wat de applicatie toestaat.",
|
|
4263
4869
|
"limit-range": "Van {{min}} tot en met {{max}}.",
|
|
@@ -4268,8 +4874,128 @@ var nl = {
|
|
|
4268
4874
|
"mcp-hint": "Externe MCP-clients mogen hem ook raadplegen, met de rechten van hun persoon.",
|
|
4269
4875
|
"mcp-closed": "De applicatie biedt raadplegingen niet aan MCP-clients aan.",
|
|
4270
4876
|
"classification-hint": "Hoe gevoelig zijn antwoorden zijn in het gesprek dat vroeg. Zonder geldt de classificatie van de agent.",
|
|
4271
|
-
|
|
4272
|
-
|
|
4877
|
+
tools: "Tools die hij mag gebruiken",
|
|
4878
|
+
"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.",
|
|
4879
|
+
"tool-not-covered": "Hoort niet meer bij de eigen tools van de agent.",
|
|
4880
|
+
"in-effect": "Een raadpleging werkt zodra ze is opgeslagen; ze antwoordt zodra een agent die vraagt haar tool selecteert.",
|
|
4881
|
+
"starts-off": "Uit beginnen",
|
|
4882
|
+
"starts-off-hint": "Hij wordt niet aangeboden tot je hem aanzet in de lijst, bijvoorbeeld na een beoordeling.",
|
|
4883
|
+
"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."
|
|
4884
|
+
},
|
|
4885
|
+
"off-badge": "Uit",
|
|
4886
|
+
"off-explain": "Uit: vragende agents krijgen geen van zijn tools tot je hem aanzet.",
|
|
4887
|
+
"switch-on": "Aanzetten",
|
|
4888
|
+
"switch-off": "Uitzetten",
|
|
4889
|
+
"switch-on-named": "Raadpleging over {{type}} aanzetten",
|
|
4890
|
+
"switch-off-named": "Raadpleging over {{type}} uitzetten",
|
|
4891
|
+
"switched-on": "De raadpleging staat aan: agents die vragen krijgen zijn tools.",
|
|
4892
|
+
"switched-off": "De raadpleging staat uit: agents die vragen krijgen geen van zijn tools."
|
|
4893
|
+
}
|
|
4894
|
+
},
|
|
4895
|
+
"hand-offs": {
|
|
4896
|
+
title: "Overdrachten",
|
|
4897
|
+
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.",
|
|
4898
|
+
loading: "Overdrachten laden…",
|
|
4899
|
+
"load-failed": "De overdrachten konden niet geladen worden.",
|
|
4900
|
+
add: "Overdracht toevoegen",
|
|
4901
|
+
empty: "Nog geen agent kan werk aan deze agent overdragen.",
|
|
4902
|
+
closed: {
|
|
4903
|
+
application: "De applicatie laat beheerders geen agents aan deze agent koppelen; haar overdrachten komen uit haar code.",
|
|
4904
|
+
"needs-settings": "Geef de agent runinstellingen voordat je agents eraan koppelt.",
|
|
4905
|
+
limit: "Deze agent neemt zoveel overdrachten aan als toegestaan ({{max}}).",
|
|
4906
|
+
"no-types": "Elke soort object waarover de applicatie deze agent laat koppelen heeft al een overdracht."
|
|
4907
|
+
},
|
|
4908
|
+
notifies: "Laat de bron weten hoe het afliep",
|
|
4909
|
+
"no-description": "Geen beschrijving.",
|
|
4910
|
+
from: "Van:",
|
|
4911
|
+
"limit-value": "Hoogstens {{max}} per bron en object per dag",
|
|
4912
|
+
"code-hint": "Aangenomen in code; dit kan hier niet veranderen.",
|
|
4913
|
+
changed: "Gewijzigd door {{user}} op {{date}}",
|
|
4914
|
+
"edit-named": "De overdracht over {{type}} bewerken",
|
|
4915
|
+
"remove-named": "De overdracht over {{type}} verwijderen",
|
|
4916
|
+
"remove-explain": "Het hulpmiddel verdwijnt uit de volgende runs van de bronnen; runs die het startte maken het af.",
|
|
4917
|
+
added: "De overdracht is toegevoegd. Een bron gebruikt hem zodra zijn hulpmiddelen het hulpmiddel ervan selecteren.",
|
|
4918
|
+
saved: "De overdracht is opgeslagen.",
|
|
4919
|
+
removed: "De overdracht is verwijderd.",
|
|
4920
|
+
problems: {
|
|
4921
|
+
invalid: "Buiten werking: een opgeslagen waarde is niet geldig.",
|
|
4922
|
+
"outside-ceiling": "Buiten werking: de applicatie laat deze agents niet meer over deze soort object koppelen.",
|
|
4923
|
+
"unknown-agent": "Buiten werking: deze agent kan niet meer zelfstandig werken.",
|
|
4924
|
+
"unknown-source": "Buiten werking: een agent die mag overdragen kan niet meer zelfstandig werken.",
|
|
4925
|
+
"not-worked-on": "Buiten werking: deze agent werkt niet aan deze soort object.",
|
|
4926
|
+
"conflicts-with-code": "Buiten werking: de applicatie neemt overdrachten over deze soort object nu in code aan.",
|
|
4927
|
+
"limit-above-ceiling": "Buiten werking: de daglimiet ligt boven wat de applicatie toestaat."
|
|
4928
|
+
},
|
|
4929
|
+
form: {
|
|
4930
|
+
"new-title": "Nieuwe overdracht",
|
|
4931
|
+
"edit-title": "Overdracht over {{type}}, versie {{version}}",
|
|
4932
|
+
"subject-type": "Soort object",
|
|
4933
|
+
"subject-type-hint": "De soorten object waarover de applicatie deze agent laat koppelen.",
|
|
4934
|
+
sources: "Agents die mogen overdragen",
|
|
4935
|
+
"no-sources": "De applicatie staat nog geen zelfstandig werkende agent toe om over deze soort object over te dragen.",
|
|
4936
|
+
"source-not-allowed": "Niet meer toegestaan; haal hem weg.",
|
|
4937
|
+
"sources-hint": "Alleen de agents die de applicatie toestaat; een hier gemaakte agent telt mee zodra hij runinstellingen heeft.",
|
|
4938
|
+
"sources-admin": "De applicatie staat ook agents toe die in het beheer gemaakt zijn.",
|
|
4939
|
+
description: "Beschrijving voor de bronnen",
|
|
4940
|
+
"description-hint": "Wanneer een bron werk moet overdragen, in een of twee zinnen.",
|
|
4941
|
+
notify: "Geef de bron een vervolg wanneer de run van deze agent eindigt",
|
|
4942
|
+
"notify-hint": "De bron hoort de uitkomst en het aantal voorstellen, en de samenvatting van de run wanneer beide aan hetzelfde object werken.",
|
|
4943
|
+
limit: "Overdrachten per bron en object per dag",
|
|
4944
|
+
"limit-hint": "1 tot en met {{max}}; 5 als je het leeg laat.",
|
|
4945
|
+
"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."
|
|
4946
|
+
}
|
|
4947
|
+
},
|
|
4948
|
+
"shadow-variants": {
|
|
4949
|
+
title: "Schaduwvarianten",
|
|
4950
|
+
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.",
|
|
4951
|
+
loading: "Schaduwvarianten laden…",
|
|
4952
|
+
"load-failed": "De schaduwvarianten konden niet geladen worden.",
|
|
4953
|
+
add: "Nieuwe schaduwvariant",
|
|
4954
|
+
empty: "Deze agent heeft geen schaduwvarianten.",
|
|
4955
|
+
closed: {
|
|
4956
|
+
"not-allowed": "De applicatie laat beheerders geen schaduwvarianten van deze agent maken.",
|
|
4957
|
+
limit: "Deze agent heeft zoveel schaduwvarianten als toegestaan ({{max}})."
|
|
4958
|
+
},
|
|
4959
|
+
source: {
|
|
4960
|
+
code: "In code",
|
|
4961
|
+
data: "Hier gemaakt"
|
|
4962
|
+
},
|
|
4963
|
+
"needs-settings": "Heeft runinstellingen nodig",
|
|
4964
|
+
"in-effect": "Krijgt de gebeurtenissen van deze agent",
|
|
4965
|
+
open: "Runconfiguratie",
|
|
4966
|
+
"set-up": "Runs instellen",
|
|
4967
|
+
"open-named": "De runconfiguratie van {{name}} openen",
|
|
4968
|
+
promote: "Promoveren naar {{name}}",
|
|
4969
|
+
"promote-named": "{{variant}} promoveren naar {{name}}",
|
|
4970
|
+
"promote-confirm": {
|
|
4971
|
+
title: "{{variant}} promoveren naar {{name}}?",
|
|
4972
|
+
code: "Zijn beschrijving, instructies, hulpmiddelen, vereiste policy en autonomie worden de volgende versie van {{name}}, een agent in code, als overschrijving tot die wordt teruggezet. {{name}} houdt zijn naam, MCP-servers, runinstellingen, triggers, status en schaduwmodus.",
|
|
4973
|
+
admin: "Zijn beschrijving, instructies, hulpmiddelen, vereiste policy, autonomie, profiel, classificatie en werkgebied worden de volgende versie van {{name}}. {{name}} houdt zijn naam, MCP-servers, metadata, runinstellingen, triggers, status en schaduwmodus.",
|
|
4974
|
+
removed: "Daarna wordt de variant verwijderd; hij gaat zelf nooit live.",
|
|
4975
|
+
"move-skills": "Ook zijn vaardigheden verplaatsen",
|
|
4976
|
+
"move-skills-hint": "Elke vaardigheid wordt de volgende live versie van de vaardigheid met hetzelfde id, of een nieuwe vaardigheid die in schaduw begint.",
|
|
4977
|
+
confirm: "Promoveren",
|
|
4978
|
+
promoting: "Promoveren…"
|
|
4979
|
+
},
|
|
4980
|
+
promoted: "{{variant}} is gepromoveerd naar {{name}}, dat nu op versie {{version}} staat.",
|
|
4981
|
+
problems: {
|
|
4982
|
+
invalid: "Buiten werking: een opgeslagen waarde is niet geldig.",
|
|
4983
|
+
"outside-ceiling": "Buiten werking: de applicatie laat beheerders geen schaduwvarianten van deze agent meer maken.",
|
|
4984
|
+
"unknown-live-agent": "Buiten werking: de agent die hij volgt kan niet meer zelfstandig werken.",
|
|
4985
|
+
"live-agent-not-live": "Buiten werking: de agent die hij volgt is geen live agent.",
|
|
4986
|
+
"too-many-variants": "Buiten werking: de agent die hij volgt heeft meer schaduwvarianten dan de applicatie toestaat."
|
|
4987
|
+
},
|
|
4988
|
+
form: {
|
|
4989
|
+
title: "Nieuwe schaduwvariant",
|
|
4990
|
+
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.",
|
|
4991
|
+
id: "Id",
|
|
4992
|
+
"id-hint": "Kleine letters, cijfers en streepjes; dit kan later niet veranderen.",
|
|
4993
|
+
name: "Naam",
|
|
4994
|
+
"default-name": "{{name}} (variant)",
|
|
4995
|
+
description: "Beschrijving",
|
|
4996
|
+
instructions: "Instructies",
|
|
4997
|
+
"instructions-hint": "Ze beginnen als de instructies van deze agent; verander wat de variant moet proberen.",
|
|
4998
|
+
create: "Variant maken"
|
|
4273
4999
|
}
|
|
4274
5000
|
},
|
|
4275
5001
|
runs: {
|
|
@@ -4302,6 +5028,225 @@ var nl = {
|
|
|
4302
5028
|
id: "Account-ID {{id}}",
|
|
4303
5029
|
"copy-id": "Account-ID van {{name}} kopiëren",
|
|
4304
5030
|
"id-copied": "Account-ID gekopieerd"
|
|
5031
|
+
},
|
|
5032
|
+
"instruction-assets": {
|
|
5033
|
+
source: "Waar komen de instructies vandaan?",
|
|
5034
|
+
"source-inline": "Hier geschreven",
|
|
5035
|
+
"source-inline-hint": "Typ de instructies in dit formulier.",
|
|
5036
|
+
"source-asset": "Tekst van de applicatie",
|
|
5037
|
+
"source-asset-hint": "Instructies die de applicatie meelevert of bewaart, in een vaste versie. Een nieuwe versie wordt pas gebruikt als je hem opslaat.",
|
|
5038
|
+
"not-offered": "De applicatie biedt haar teksten niet meer aan; schrijf de instructies hier zodat dit blijft werken.",
|
|
5039
|
+
loading: "De teksten van de applicatie laden…",
|
|
5040
|
+
asset: "Tekst",
|
|
5041
|
+
"asset-hint": "De applicatie toont de teksten die je kunt kiezen, elk in een vaste versie.",
|
|
5042
|
+
choose: "Kies een tekst",
|
|
5043
|
+
option: "{{asset}}, versie {{version}}",
|
|
5044
|
+
deprecated: "Vervangen door de applicatie",
|
|
5045
|
+
"deprecated-by": "Vervangen door {{asset}}",
|
|
5046
|
+
"none-listed": "De applicatie toont geen teksten; vul de id en versie in die je van haar kreeg.",
|
|
5047
|
+
"asset-id": "Id van de tekst",
|
|
5048
|
+
version: "Versie",
|
|
5049
|
+
read: "Tekst lezen",
|
|
5050
|
+
reading: "De tekst lezen…",
|
|
5051
|
+
reference: "Gebruikt {{asset}}, versie {{version}}.",
|
|
5052
|
+
hash: "Hash {{hash}}",
|
|
5053
|
+
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.",
|
|
5054
|
+
text: "Tekst van de instructies",
|
|
5055
|
+
"text-hint": "Alleen lezen: deze tekst is van de applicatie. Opslaan bewaart welke tekst en versie, nooit een kopie.",
|
|
5056
|
+
"agent-problem": "De agent werkt niet:",
|
|
5057
|
+
problems: {
|
|
5058
|
+
"no-asset-source": "De applicatie biedt haar teksten niet meer aan; de instructies zijn niet beschikbaar.",
|
|
5059
|
+
"asset-missing": "De applicatie heeft deze tekst niet meer in deze versie.",
|
|
5060
|
+
"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.",
|
|
5061
|
+
"asset-invalid": "Deze tekst is niet te gebruiken als instructies.",
|
|
5062
|
+
"asset-unavailable": "De teksten van de applicatie waren niet te lezen; ze worden zo opnieuw gelezen."
|
|
5063
|
+
},
|
|
5064
|
+
errors: {
|
|
5065
|
+
required: "Kies een tekst en lees hem eerst.",
|
|
5066
|
+
"not-found": "De applicatie heeft deze tekst niet in deze versie.",
|
|
5067
|
+
changed: "De tekst is veranderd sinds je hem las. Lees hem opnieuw voordat je opslaat.",
|
|
5068
|
+
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.",
|
|
5069
|
+
"not-allowed": "De applicatie biedt haar teksten hier niet aan."
|
|
5070
|
+
}
|
|
5071
|
+
},
|
|
5072
|
+
packages: {
|
|
5073
|
+
"export": "Als pakket exporteren",
|
|
5074
|
+
"export-named": "{{name}} als pakket exporteren",
|
|
5075
|
+
"import": "Pakket importeren",
|
|
5076
|
+
"linked-badge": "Pakket {{package}} {{version}}",
|
|
5077
|
+
"delete-locked": "De agent hoort bij pakket {{package}}. Ontkoppel de agent eerst om hem te verwijderen.",
|
|
5078
|
+
"remove-locked": "Pakket {{package}} vergrendelt dit onderdeel. Ontkoppel het eerst om het te verwijderen.",
|
|
5079
|
+
lock: {
|
|
5080
|
+
linked: "Gekoppeld aan pakket {{package}}, versie {{version}}.",
|
|
5081
|
+
"agent-linked": "Deze agent komt uit pakket {{package}}, versie {{version}}.",
|
|
5082
|
+
whole: "Het pakket vergrendelt het als geheel: het verandert met de volgende versie van het pakket.",
|
|
5083
|
+
fields: "Vergrendeld: {{fields}}.",
|
|
5084
|
+
"nothing-locked": "Er is niets van vergrendeld; de volgende versie van het pakket overschrijft een wijziging die hier is gemaakt.",
|
|
5085
|
+
field: "Vergrendeld door pakket {{package}}, versie {{version}}",
|
|
5086
|
+
unlink: "Ontkoppelen",
|
|
5087
|
+
"unlink-agent": "De agent ontkoppelen",
|
|
5088
|
+
"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.",
|
|
5089
|
+
"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.",
|
|
5090
|
+
"confirm-unlink": "Ontkoppelen"
|
|
5091
|
+
},
|
|
5092
|
+
parts: {
|
|
5093
|
+
agent: "Agent",
|
|
5094
|
+
"run-settings": "Runinstellingen",
|
|
5095
|
+
skill: "Vaardigheid {{name}}",
|
|
5096
|
+
trigger: "Trigger {{name}}",
|
|
5097
|
+
consultation: "Raadpleging over {{name}}",
|
|
5098
|
+
"hand-off": "Overdracht over {{name}}",
|
|
5099
|
+
metadata: "Veld {{name}}"
|
|
5100
|
+
},
|
|
5101
|
+
outcomes: {
|
|
5102
|
+
created: "Nieuw",
|
|
5103
|
+
changed: "Gewijzigd",
|
|
5104
|
+
unchanged: "Ongewijzigd",
|
|
5105
|
+
"kept-local": "Lokaal gehouden",
|
|
5106
|
+
"left-behind": "Achtergelaten",
|
|
5107
|
+
refused: "Geweigerd"
|
|
5108
|
+
},
|
|
5109
|
+
"outcome-explain": {
|
|
5110
|
+
created: "De import voegt het toe.",
|
|
5111
|
+
changed: "De import vervangt het door de versie van het pakket.",
|
|
5112
|
+
unchanged: "Het is gelijk aan de versie van het pakket.",
|
|
5113
|
+
"kept-local": "Het is hier ontkoppeld, dus de import laat het zoals het is, tenzij je de versie van het pakket neemt.",
|
|
5114
|
+
"left-behind": "Het pakket bevat deze agent niet meer: hij blijft hier, ontkoppeld.",
|
|
5115
|
+
refused: "De import weigert het, en daarmee het hele pakket."
|
|
5116
|
+
},
|
|
5117
|
+
"changed-locally": "Lokaal gewijzigd",
|
|
5118
|
+
"changed-locally-hint": "Iemand heeft het hier gewijzigd sinds het is geïmporteerd; de import overschrijft die wijziging.",
|
|
5119
|
+
"export-dialog": {
|
|
5120
|
+
title: "Agents als pakket exporteren",
|
|
5121
|
+
close: "Sluiten",
|
|
5122
|
+
agents: "Agents in het pakket",
|
|
5123
|
+
"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.",
|
|
5124
|
+
"agents-required": "Kies minstens één agent.",
|
|
5125
|
+
"too-many": "Een pakket bevat hoogstens {{max}} agents.",
|
|
5126
|
+
"package-id": "Pakket-id",
|
|
5127
|
+
"package-id-hint": "Kleine letters, cijfers en streepjes. Een host werkt de agents die hij uit hetzelfde pakket-id importeerde bij.",
|
|
5128
|
+
"package-id-default": "Leeg: {{id}}",
|
|
5129
|
+
version: "Versie",
|
|
5130
|
+
"version-hint": "Een heel getal vanaf 1. Leeg: de volgende versie na die deze host importeerde, anders 1.",
|
|
5131
|
+
description: "Beschrijving",
|
|
5132
|
+
"description-hint": "Optioneel: waarvoor het pakket is, voor wie het importeert.",
|
|
5133
|
+
locks: "Vergrendelingen",
|
|
5134
|
+
"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.",
|
|
5135
|
+
"lock-none": "Niet vergrendeld",
|
|
5136
|
+
"lock-whole": "Helemaal",
|
|
5137
|
+
"lock-fields": "Gekozen velden",
|
|
5138
|
+
"lock-choice": "{{part}} vergrendelen",
|
|
5139
|
+
"lock-fields-of": "Te vergrendelen velden van {{part}}",
|
|
5140
|
+
"loading-parts": "De onderdelen van de agents lezen…",
|
|
5141
|
+
"parts-failed": "De onderdelen van de agents konden niet gelezen worden.",
|
|
5142
|
+
"no-parts": "Niets van deze agent gaat als gegevens mee.",
|
|
5143
|
+
references: "Verwijzingen buiten het pakket",
|
|
5144
|
+
"references-hint": "Deze agents zitten niet in het pakket, dus ze moeten bestaan waar het wordt geïmporteerd.",
|
|
5145
|
+
add: "{{agent}} toevoegen",
|
|
5146
|
+
download: "Pakket downloaden",
|
|
5147
|
+
downloading: "Exporteren…",
|
|
5148
|
+
downloaded: "Het pakket is gedownload als {{file}}.",
|
|
5149
|
+
reference: {
|
|
5150
|
+
"hand-off-source": "{{referenced}} draagt werk over aan {{agent}} ({{part}}).",
|
|
5151
|
+
"shadow-of": "{{agent}} is een schaduwvariant van {{referenced}}.",
|
|
5152
|
+
"consultation-asker": "{{referenced}} raadpleegt {{agent}} ({{part}}).",
|
|
5153
|
+
"shadow-variant": "{{referenced}} is een schaduwvariant van {{agent}} en krijgt zijn triggers."
|
|
5154
|
+
}
|
|
5155
|
+
},
|
|
5156
|
+
"import-dialog": {
|
|
5157
|
+
title: "Een agentpakket importeren",
|
|
5158
|
+
close: "Sluiten",
|
|
5159
|
+
file: "Pakketbestand",
|
|
5160
|
+
"file-hint": "Een JSON-bestand van hoogstens 1 MB, zoals een export het schrijft.",
|
|
5161
|
+
"file-chosen": "Gelezen uit {{name}}.",
|
|
5162
|
+
paste: "Of plak het pakket",
|
|
5163
|
+
"paste-hint": "De JSON van het pakket.",
|
|
5164
|
+
"invalid-json": "Dit is geen pakket: de JSON ervan kan niet gelezen worden.",
|
|
5165
|
+
"too-large": "Een pakket is hoogstens 1 MB.",
|
|
5166
|
+
"no-package": "Kies eerst een pakketbestand of plak een pakket.",
|
|
5167
|
+
preview: "Het pakket controleren",
|
|
5168
|
+
previewing: "Controleren…",
|
|
5169
|
+
"preview-again": "Opnieuw controleren",
|
|
5170
|
+
"preview-title": "Wat de import doet",
|
|
5171
|
+
summary: "Pakket {{package}}, versie {{version}}",
|
|
5172
|
+
"agent-heading": "Agent {{agent}}",
|
|
5173
|
+
"column-part": "Onderdeel",
|
|
5174
|
+
"column-outcome": "Uitkomst",
|
|
5175
|
+
"column-details": "Details",
|
|
5176
|
+
"column-relink": "Versie van het pakket",
|
|
5177
|
+
relink: "De versie van het pakket van {{part}} nemen",
|
|
5178
|
+
"relink-hint": "Koppelt het onderdeel weer: de import overschrijft de lokale versie en koppelt het weer aan het pakket.",
|
|
5179
|
+
account: "Technisch account van {{agent}}",
|
|
5180
|
+
"account-hint": "Accounts gaan nooit mee: kies het account op deze host waaraan de agent verantwoording aflegt.",
|
|
5181
|
+
apply: "Gewijzigde vaardigheden en triggers",
|
|
5182
|
+
"apply-live": "Direct van kracht",
|
|
5183
|
+
"apply-live-hint": "Elke wijziging wordt de live versie, zoals bij opslaan.",
|
|
5184
|
+
"apply-shadow": "Eerst in schaduw draaien",
|
|
5185
|
+
"apply-shadow-hint": "Elke wijziging wordt een kandidaat naast de live versie, om te vergelijken en te promoveren.",
|
|
5186
|
+
"apply-new-hint": "Nieuwe vaardigheden en triggers beginnen hoe dan ook in schaduw.",
|
|
5187
|
+
refused: "De import weigert {{count}} onderdelen. Herstel het pakket of de host en controleer opnieuw.",
|
|
5188
|
+
"options-changed": "De keuzes zijn gewijzigd sinds de controle; controleer opnieuw voordat je importeert.",
|
|
5189
|
+
"import": "Importeren",
|
|
5190
|
+
importing: "Importeren…",
|
|
5191
|
+
imported: "Het pakket is geïmporteerd.",
|
|
5192
|
+
"result-title": "Wat de import deed",
|
|
5193
|
+
done: "Klaar",
|
|
5194
|
+
"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.",
|
|
5195
|
+
"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.",
|
|
5196
|
+
"agent-exists-in-code": "Op deze host heeft een agent in code dit id; de agent van het pakket kan hem niet vervangen.",
|
|
5197
|
+
"take-over": "De bestaande agent overnemen",
|
|
5198
|
+
"take-over-hint": "Het pakket vervangt zijn configuratie en koppelt hem.",
|
|
5199
|
+
"refused-one": "De import weigert {{count}} onderdeel. Herstel het pakket of de host en controleer opnieuw."
|
|
5200
|
+
},
|
|
5201
|
+
fields: {
|
|
5202
|
+
"display-name": "Naam",
|
|
5203
|
+
description: "Omschrijving",
|
|
5204
|
+
instructions: "Instructies",
|
|
5205
|
+
"tool-selectors": "Tools",
|
|
5206
|
+
"required-policy": "Vereiste policy",
|
|
5207
|
+
autonomy: "Autonomie",
|
|
5208
|
+
"offered-in-chat": "Gebruik in de chat",
|
|
5209
|
+
"works-on": "Waaraan hij werkt",
|
|
5210
|
+
profile: "Modelprofiel",
|
|
5211
|
+
"data-classification": "Dataclassificatie",
|
|
5212
|
+
accountability: "Legt verantwoording af aan",
|
|
5213
|
+
"delegate-from-initiator": "Rechten van de persoon die een run start",
|
|
5214
|
+
"allow-gateway-reads": "Lezen via de datagateway",
|
|
5215
|
+
"elevated-reads": "Lezen met de rechten van het account",
|
|
5216
|
+
"approval-policy": "Goedkeuringsbeleid",
|
|
5217
|
+
"retry-count": "Nieuwe pogingen na een fout",
|
|
5218
|
+
"daily-budget": "Daglimieten",
|
|
5219
|
+
"max-concurrent-runs": "Runs tegelijk",
|
|
5220
|
+
"max-runs-per-subject-per-day": "Runs per onderwerp per dag",
|
|
5221
|
+
"max-tokens-per-run": "Tokens per run",
|
|
5222
|
+
"triage-profile": "Triageprofiel",
|
|
5223
|
+
"rule-handler": "Werkwijze",
|
|
5224
|
+
files: "Bestanden",
|
|
5225
|
+
tools: "Tools",
|
|
5226
|
+
skill: "Vaardigheid",
|
|
5227
|
+
source: "Wanneer hij start",
|
|
5228
|
+
event: "Gebeurtenis",
|
|
5229
|
+
filters: "Filters",
|
|
5230
|
+
cron: "Schema",
|
|
5231
|
+
"time-zone": "Tijdzone",
|
|
5232
|
+
"subject-set": "Onderwerpen",
|
|
5233
|
+
message: "Bericht aan elke run",
|
|
5234
|
+
conflict: "Terwijl een run bezig is",
|
|
5235
|
+
"debounce-seconds": "Wachten op meer gebeurtenissen",
|
|
5236
|
+
"minimum-role": "Rol van de persoon die vraagt",
|
|
5237
|
+
"asker-policy": "Policy van de persoon die vraagt",
|
|
5238
|
+
routes: "Routes",
|
|
5239
|
+
"proposal-role": "Rol voordat hij voorstelt",
|
|
5240
|
+
"proposal-policy": "Goedkeuringsbeleid van zijn voorstellen",
|
|
5241
|
+
limits: "Limieten",
|
|
5242
|
+
"allow-requests": "Verzoeken",
|
|
5243
|
+
"expose-to-mcp": "MCP-clients",
|
|
5244
|
+
sources: "Agents die mogen overdragen",
|
|
5245
|
+
"notify-source": "Laat de bron weten hoe het afliep",
|
|
5246
|
+
"max-per-subject-per-day": "Overdrachten per bron en object per dag",
|
|
5247
|
+
value: "Waarde"
|
|
5248
|
+
},
|
|
5249
|
+
"reset-locked": "Pakket {{package}} vergrendelt velden van de definitie. Ontkoppel ze eerst om de agent terug te zetten."
|
|
4305
5250
|
}
|
|
4306
5251
|
},
|
|
4307
5252
|
"page-context": {
|
|
@@ -4316,6 +5261,11 @@ var nl = {
|
|
|
4316
5261
|
waiting: "Wacht op goedkeuring",
|
|
4317
5262
|
unread: "Ongelezen"
|
|
4318
5263
|
},
|
|
5264
|
+
document: {
|
|
5265
|
+
"diagram-failed": "Dit diagram kon niet worden getekend: {{reason}}",
|
|
5266
|
+
"diagram-no-reason": "de renderer gaf geen reden.",
|
|
5267
|
+
"diagram-not-svg": "de renderer gaf geen SVG terug."
|
|
5268
|
+
},
|
|
4319
5269
|
share: {
|
|
4320
5270
|
title: "Gesprek delen",
|
|
4321
5271
|
"members-title": "Mensen in dit gesprek",
|
|
@@ -4438,6 +5388,10 @@ var nl = {
|
|
|
4438
5388
|
"re-execute": "Opnieuw uitvoeren",
|
|
4439
5389
|
"mark-resolved": "Als afgehandeld markeren",
|
|
4440
5390
|
"unknown-hint": "De uitvoering stopte zonder bekende uitkomst. Controleer of het gebeurd is voordat je het opnieuw uitvoert.",
|
|
5391
|
+
"hand-to-application": "Opnieuw aan de applicatie geven",
|
|
5392
|
+
"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.",
|
|
5393
|
+
"awaiting-application-hint": "De applicatie voert dit goedgekeurde voorstel uit en meldt zich als het klaar is.",
|
|
5394
|
+
"report-due": "Melding verwacht {{date}}",
|
|
4441
5395
|
mode: {
|
|
4442
5396
|
inline: "De run wacht",
|
|
4443
5397
|
deferred: "Later beslissen"
|
|
@@ -4450,6 +5404,7 @@ var nl = {
|
|
|
4450
5404
|
withdrawn: "Ingetrokken",
|
|
4451
5405
|
stale: "Verouderd",
|
|
4452
5406
|
executing: "Wordt uitgevoerd",
|
|
5407
|
+
"awaiting-application": "Bij de applicatie",
|
|
4453
5408
|
executed: "Uitgevoerd",
|
|
4454
5409
|
"execution-failed": "Mislukt",
|
|
4455
5410
|
"execution-unknown": "Uitkomst onbekend",
|
|
@@ -4934,6 +5889,20 @@ class NhAssistantTransport {
|
|
|
4934
5889
|
return () => abort.abort();
|
|
4935
5890
|
});
|
|
4936
5891
|
}
|
|
5892
|
+
/**
|
|
5893
|
+
* A cold request with a JSON body that answers the response's text and headers, for an endpoint that
|
|
5894
|
+
* answers a file with details in a header, such as the export of an agent package. It aborts on
|
|
5895
|
+
* unsubscribe and errors as `json` does: with the code and field errors of a refused request's error
|
|
5896
|
+
* body, the endpoint's status mapping without one, and `assistant-network` when the request did not
|
|
5897
|
+
* reach the server.
|
|
5898
|
+
*/
|
|
5899
|
+
file(method, path, body, accept, statusCodes = {}) {
|
|
5900
|
+
return new Observable(subscriber => {
|
|
5901
|
+
const abort = new AbortController();
|
|
5902
|
+
void this.executeFile(method, path, body, accept, statusCodes, abort.signal, subscriber);
|
|
5903
|
+
return () => abort.abort();
|
|
5904
|
+
});
|
|
5905
|
+
}
|
|
4937
5906
|
async fetch(method, path, accept, body, signal) {
|
|
4938
5907
|
const init = await this.createInit(method, accept, body, signal);
|
|
4939
5908
|
return this.fetchFn(this.url(path), init);
|
|
@@ -5029,6 +5998,33 @@ class NhAssistantTransport {
|
|
|
5029
5998
|
}
|
|
5030
5999
|
return { code: statusCodes[response.status] ?? nhAssistantCodeForStatus(response.status), fieldErrors };
|
|
5031
6000
|
}
|
|
6001
|
+
async executeFile(method, path, body, accept, statusCodes, signal, subscriber) {
|
|
6002
|
+
let response;
|
|
6003
|
+
try {
|
|
6004
|
+
response = await this.fetch(method, path, accept, body, signal);
|
|
6005
|
+
}
|
|
6006
|
+
catch {
|
|
6007
|
+
if (!signal.aborted) {
|
|
6008
|
+
subscriber.error(createApiError(0, nhAssistantCodeForStatus(0)));
|
|
6009
|
+
}
|
|
6010
|
+
return;
|
|
6011
|
+
}
|
|
6012
|
+
if (!response.ok) {
|
|
6013
|
+
const failure = await this.failure(response, statusCodes);
|
|
6014
|
+
subscriber.error(createApiError(response.status, failure.code, failure.fieldErrors));
|
|
6015
|
+
return;
|
|
6016
|
+
}
|
|
6017
|
+
try {
|
|
6018
|
+
const text = await response.text();
|
|
6019
|
+
subscriber.next({ text, headers: response.headers });
|
|
6020
|
+
subscriber.complete();
|
|
6021
|
+
}
|
|
6022
|
+
catch {
|
|
6023
|
+
if (!signal.aborted) {
|
|
6024
|
+
subscriber.error(createApiError(response.status, NhAssistantClientErrorCodes.streamInterrupted));
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
}
|
|
5032
6028
|
async executeJson(method, path, body, statusCodes, signal, subscriber) {
|
|
5033
6029
|
let response;
|
|
5034
6030
|
try {
|
|
@@ -5176,6 +6172,25 @@ class NhAssistantApiService {
|
|
|
5176
6172
|
const path = `conversations/${encodeURIComponent(conversationId)}/approvals/${encodeURIComponent(approvalId)}/decide`;
|
|
5177
6173
|
return this.requestStream(path, request, false);
|
|
5178
6174
|
}
|
|
6175
|
+
/**
|
|
6176
|
+
* Answers the question the chat's waiting turn asked with `ask_question` with the index of one of
|
|
6177
|
+
* its choices, and streams the resumed turn like a decision. Only the question's addressee answers;
|
|
6178
|
+
* the server refuses others with `assistant-question-forbidden` and a question whose wait ended with
|
|
6179
|
+
* `assistant-question-expired`.
|
|
6180
|
+
*/
|
|
6181
|
+
answerQuestion(conversationId, questionId, request) {
|
|
6182
|
+
const path = `conversations/${encodeURIComponent(conversationId)}/questions/${encodeURIComponent(questionId)}/answer`;
|
|
6183
|
+
return this.requestStream(path, request, false);
|
|
6184
|
+
}
|
|
6185
|
+
/**
|
|
6186
|
+
* Resolves an uncertain hand-off of a proposal the caller approved in this chat (`canResolve`):
|
|
6187
|
+
* `hand-to-application` hands it to the application again, `mark-resolved` confirms its outcome.
|
|
6188
|
+
* Returns the conversation as it is afterwards.
|
|
6189
|
+
*/
|
|
6190
|
+
resolveApproval(conversationId, approvalId, request) {
|
|
6191
|
+
const path = `conversations/${encodeURIComponent(conversationId)}/approvals/${encodeURIComponent(approvalId)}/resolve`;
|
|
6192
|
+
return this.transport.json('POST', path, request);
|
|
6193
|
+
}
|
|
5179
6194
|
cancel(conversationId) {
|
|
5180
6195
|
return this.transport.json('POST', `conversations/${encodeURIComponent(conversationId)}/cancel`);
|
|
5181
6196
|
}
|
|
@@ -5378,6 +6393,8 @@ const adminStatusCodes = {
|
|
|
5378
6393
|
const maxAccountIds = 50;
|
|
5379
6394
|
/** The longest account id the server reads; a longer id names no account. */
|
|
5380
6395
|
const maxAccountIdLength = 256;
|
|
6396
|
+
/** The header of the agent package export that lists the references to agents outside the selection. */
|
|
6397
|
+
const packageWarningsHeader = 'X-NewHeap-Package-Warnings';
|
|
5381
6398
|
/**
|
|
5382
6399
|
* Client for the assistant administration endpoints (`admin/*`). The server requires the
|
|
5383
6400
|
* access policy and the admin policy; show the administration only when
|
|
@@ -5468,6 +6485,29 @@ class NhAssistantAdminApiService {
|
|
|
5468
6485
|
setAgentGroups(agentId, groups) {
|
|
5469
6486
|
return this.request('PUT', `admin/agents/${encodeURIComponent(agentId)}/groups`, { groups });
|
|
5470
6487
|
}
|
|
6488
|
+
/**
|
|
6489
|
+
* Every entry of agent metadata the application registers, with the agent's value in effect, where
|
|
6490
|
+
* it comes from and whether it changes here (`GET admin/agents/{id}/metadata`).
|
|
6491
|
+
*/
|
|
6492
|
+
getAgentMetadata(agentId) {
|
|
6493
|
+
return this.request('GET', `${agentPath(agentId)}/metadata`);
|
|
6494
|
+
}
|
|
6495
|
+
/**
|
|
6496
|
+
* Saves the agent's value of one metadata entry after the checks in code: field errors `value` or
|
|
6497
|
+
* `value.<field>`. For an agent created here it makes the agent's next version (`expectedVersion` is
|
|
6498
|
+
* the agent's version); for an agent in code only an editable entry changes, as an override with a
|
|
6499
|
+
* version of its own (`assistant-metadata-read-only` otherwise).
|
|
6500
|
+
*/
|
|
6501
|
+
saveAgentMetadata(agentId, name, request) {
|
|
6502
|
+
return this.request('PUT', metadataPath(agentId, name), request);
|
|
6503
|
+
}
|
|
6504
|
+
/**
|
|
6505
|
+
* Removes the agent's stored value of one metadata entry, so an agent in code uses its value in code
|
|
6506
|
+
* again; answers the entry as it is now.
|
|
6507
|
+
*/
|
|
6508
|
+
removeAgentMetadata(agentId, name, expectedVersion) {
|
|
6509
|
+
return this.request('DELETE', withQuery$1(metadataPath(agentId, name), { expectedVersion }));
|
|
6510
|
+
}
|
|
5471
6511
|
/** Deletes an admin agent. Code agents cannot be deleted; stop them instead. */
|
|
5472
6512
|
deleteAgent(agentId) {
|
|
5473
6513
|
return this.request('DELETE', `admin/agents/${encodeURIComponent(agentId)}`);
|
|
@@ -5591,6 +6631,21 @@ class NhAssistantAdminApiService {
|
|
|
5591
6631
|
getRunCatalog() {
|
|
5592
6632
|
return this.request('GET', 'admin/run-catalog');
|
|
5593
6633
|
}
|
|
6634
|
+
/**
|
|
6635
|
+
* The application's assets an administrator may choose as instructions, without their content
|
|
6636
|
+
* (`GET admin/instruction-assets`). Fails with `assistant-instructions-asset-unavailable` when the
|
|
6637
|
+
* application's source fails.
|
|
6638
|
+
*/
|
|
6639
|
+
listInstructionAssets() {
|
|
6640
|
+
return this.request('GET', 'admin/instruction-assets');
|
|
6641
|
+
}
|
|
6642
|
+
/**
|
|
6643
|
+
* The text of one asset, read-only, with the hash a reference stores. Fails with
|
|
6644
|
+
* `assistant-instructions-asset-not-found` for an asset or version the application does not have.
|
|
6645
|
+
*/
|
|
6646
|
+
getInstructionAsset(assetId, version) {
|
|
6647
|
+
return this.request('GET', `admin/instruction-assets/${encodeURIComponent(assetId)}/versions/${encodeURIComponent(String(version))}`);
|
|
6648
|
+
}
|
|
5594
6649
|
/**
|
|
5595
6650
|
* Accounts whose name or e-mail address contains `query` (2 to 100 characters), at most `limit`.
|
|
5596
6651
|
* Fails with `assistant-account-search-unavailable` when the application offers no search; the
|
|
@@ -5641,7 +6696,10 @@ class NhAssistantAdminApiService {
|
|
|
5641
6696
|
getAgentRuns(agentId, filter = {}) {
|
|
5642
6697
|
return this.request('GET', withQuery$1(`${agentPath(agentId)}/runs`, filter));
|
|
5643
6698
|
}
|
|
5644
|
-
/**
|
|
6699
|
+
/**
|
|
6700
|
+
* Removes the run settings; while data skills, triggers, consultations or hand-offs defined as data
|
|
6701
|
+
* belong to the agent, `assistant-run-settings-in-use`.
|
|
6702
|
+
*/
|
|
5645
6703
|
removeRunSettings(agentId, removal = {}) {
|
|
5646
6704
|
return this.request('DELETE', withQuery$1(`${agentPath(agentId)}/run-settings`, removal));
|
|
5647
6705
|
}
|
|
@@ -5672,10 +6730,30 @@ class NhAssistantAdminApiService {
|
|
|
5672
6730
|
compareSkillCandidate(agentId, skillId, filter = {}) {
|
|
5673
6731
|
return this.request('GET', withQuery$1(`${skillPath(agentId, skillId)}/candidate/comparison`, filter));
|
|
5674
6732
|
}
|
|
5675
|
-
/**
|
|
6733
|
+
/**
|
|
6734
|
+
* Adds a trigger defined as data, which starts in shadow, or stores its next version: with `apply`
|
|
6735
|
+
* `live` (default) it takes effect at once in the trigger's mode; with `shadow` it becomes the
|
|
6736
|
+
* candidate that fires next to the live version until it is promoted or discarded.
|
|
6737
|
+
*/
|
|
5676
6738
|
saveDataTrigger(agentId, triggerId, request) {
|
|
5677
6739
|
return this.request('PUT', triggerPath(agentId, triggerId), request);
|
|
5678
6740
|
}
|
|
6741
|
+
/** Every version of a trigger defined as data, newest first, with its definition. */
|
|
6742
|
+
getDataTriggerVersions(agentId, triggerId) {
|
|
6743
|
+
return this.request('GET', `${triggerPath(agentId, triggerId)}/versions`);
|
|
6744
|
+
}
|
|
6745
|
+
/** Makes the candidate the live version of its trigger, in the trigger's mode. */
|
|
6746
|
+
promoteTriggerCandidate(agentId, triggerId, request) {
|
|
6747
|
+
return this.request('POST', `${triggerPath(agentId, triggerId)}/candidate/promote`, request);
|
|
6748
|
+
}
|
|
6749
|
+
/** Discards the candidate of a trigger; it stays as history and fires no more. */
|
|
6750
|
+
discardTriggerCandidate(agentId, triggerId, request) {
|
|
6751
|
+
return this.request('POST', `${triggerPath(agentId, triggerId)}/candidate/discard`, request);
|
|
6752
|
+
}
|
|
6753
|
+
/** Compares the trigger's candidate with its live version on the runs they started in the period. */
|
|
6754
|
+
compareTriggerCandidate(agentId, triggerId, filter = {}) {
|
|
6755
|
+
return this.request('GET', withQuery$1(`${triggerPath(agentId, triggerId)}/candidate/comparison`, filter));
|
|
6756
|
+
}
|
|
5679
6757
|
removeDataTrigger(agentId, triggerId, removal = {}) {
|
|
5680
6758
|
return this.request('DELETE', withQuery$1(triggerPath(agentId, triggerId), removal));
|
|
5681
6759
|
}
|
|
@@ -5696,6 +6774,14 @@ class NhAssistantAdminApiService {
|
|
|
5696
6774
|
saveDataConsultation(agentId, subjectType, request) {
|
|
5697
6775
|
return this.request('PUT', consultationPath(agentId, subjectType), request);
|
|
5698
6776
|
}
|
|
6777
|
+
/**
|
|
6778
|
+
* Switches a consultation defined as data on or off, without a new version. Off, it is not offered,
|
|
6779
|
+
* while its recorded proposals can still be decided. Fails with `assistant-consultation-not-found`
|
|
6780
|
+
* without one and with `assistant-consultation-in-code` for a consultation in code.
|
|
6781
|
+
*/
|
|
6782
|
+
setDataConsultationState(agentId, subjectType, request) {
|
|
6783
|
+
return this.request('POST', `${consultationPath(agentId, subjectType)}/state`, request);
|
|
6784
|
+
}
|
|
5699
6785
|
/**
|
|
5700
6786
|
* Removes a consultation defined as data: its tools disappear, while its recorded proposals can still
|
|
5701
6787
|
* be decided. Fails with `assistant-consultation-not-found` without one and with
|
|
@@ -5704,6 +6790,102 @@ class NhAssistantAdminApiService {
|
|
|
5704
6790
|
removeDataConsultation(agentId, subjectType, removal = {}) {
|
|
5705
6791
|
return this.request('DELETE', withQuery$1(consultationPath(agentId, subjectType), removal));
|
|
5706
6792
|
}
|
|
6793
|
+
/**
|
|
6794
|
+
* The hand-offs the agent accepts, in code and as data with their problems, and what the ceiling in
|
|
6795
|
+
* code (`UseHandOffsAsData`) lets administrators add; `ceiling` is `null` when it may accept none.
|
|
6796
|
+
*/
|
|
6797
|
+
getAgentHandOffs(agentId) {
|
|
6798
|
+
return this.request('GET', `${agentPath(agentId)}/hand-offs`);
|
|
6799
|
+
}
|
|
6800
|
+
/**
|
|
6801
|
+
* Adds or changes the hand-off defined as data that the agent accepts about one subject type, within
|
|
6802
|
+
* the ceiling: in effect once saved, as one in code. An agent the ceiling connects to no agent fails
|
|
6803
|
+
* with `assistant-handoffs-not-allowed`, a type it accepts in code with `assistant-handoff-in-code`,
|
|
6804
|
+
* an agent without run configuration with `assistant-agent-not-configured`, more than the ceiling's
|
|
6805
|
+
* `maxHandOffs` with `assistant-configuration-limit`, a stale `expectedVersion` with
|
|
6806
|
+
* `assistant-version-conflict` and invalid input with field errors, such as `sources: not-allowed`
|
|
6807
|
+
* for a source outside the ceiling.
|
|
6808
|
+
*/
|
|
6809
|
+
saveDataHandOff(agentId, subjectType, request) {
|
|
6810
|
+
return this.request('PUT', handOffPath(agentId, subjectType), request);
|
|
6811
|
+
}
|
|
6812
|
+
/**
|
|
6813
|
+
* Removes a hand-off defined as data; its tool disappears from the sources' next turns. Fails with
|
|
6814
|
+
* `assistant-handoff-not-found` without one and with `assistant-handoff-in-code` for one in code.
|
|
6815
|
+
*/
|
|
6816
|
+
removeDataHandOff(agentId, subjectType, removal = {}) {
|
|
6817
|
+
return this.request('DELETE', withQuery$1(handOffPath(agentId, subjectType), removal));
|
|
6818
|
+
}
|
|
6819
|
+
/**
|
|
6820
|
+
* The agent's shadow variants, in code and created as data, and whether administrators may create
|
|
6821
|
+
* more (`UseShadowVariantsAsData`). Create a data variant with `createAgent` and `shadowOf`.
|
|
6822
|
+
*/
|
|
6823
|
+
getShadowVariants(agentId) {
|
|
6824
|
+
return this.request('GET', `${agentPath(agentId)}/shadow-variants`);
|
|
6825
|
+
}
|
|
6826
|
+
/**
|
|
6827
|
+
* Promotes the data shadow variant `variantId` onto its live agent (`POST admin/agents/{id}/promote`):
|
|
6828
|
+
* its definition becomes the live agent's next version through the update path, with its checks,
|
|
6829
|
+
* locks and audit, its data skills move along when asked, and the variant is deleted. The live agent
|
|
6830
|
+
* keeps its name, MCP servers, metadata, run settings, triggers, state and shadow mode; an agent in
|
|
6831
|
+
* code takes only the fields it can override. Fails with `assistant-not-shadow-variant`,
|
|
6832
|
+
* `assistant-shadow-variants-not-allowed`, `assistant-version-conflict` and `assistant-skill-in-code`.
|
|
6833
|
+
*/
|
|
6834
|
+
promoteShadowVariant(variantId, request) {
|
|
6835
|
+
return this.request('POST', `${agentPath(variantId)}/promote`, request);
|
|
6836
|
+
}
|
|
6837
|
+
/**
|
|
6838
|
+
* Exports exactly `agentIds` (1 to 20) as one agent package (`POST admin/agent-packages/export`):
|
|
6839
|
+
* agents created here whole, agents in code as an overlay of what data changes on them; never
|
|
6840
|
+
* history, candidates, runs, run state, shadow overrides, MCP servers, the technical account or
|
|
6841
|
+
* secrets. The options set the package id, version and locks; left out, the id of the package the
|
|
6842
|
+
* first agent is linked to and its next version, otherwise the first agent's id and 1. Answers the
|
|
6843
|
+
* package, its JSON exactly as the server wrote it for the download, and every reference to an agent
|
|
6844
|
+
* outside the selection, which must exist where the package is imported. Fails with
|
|
6845
|
+
* `assistant-agent-not-found` for an unknown agent and with field errors for invalid options; the
|
|
6846
|
+
* server audits the export.
|
|
6847
|
+
*/
|
|
6848
|
+
exportAgentPackage(agentIds, options = {}) {
|
|
6849
|
+
return this.transport.file('POST', 'admin/agent-packages/export', { agentIds: [...agentIds], options }, 'application/json', adminStatusCodes).pipe(map(file => {
|
|
6850
|
+
let agentPackage;
|
|
6851
|
+
try {
|
|
6852
|
+
agentPackage = JSON.parse(file.text);
|
|
6853
|
+
}
|
|
6854
|
+
catch {
|
|
6855
|
+
throw new NhAssistantApiError(200, NhAssistantClientErrorCodes.invalidResponse, nhAssistantErrorMessageKey(NhAssistantClientErrorCodes.invalidResponse));
|
|
6856
|
+
}
|
|
6857
|
+
return { package: agentPackage, json: file.text, warnings: packageWarnings(file.headers.get(packageWarningsHeader)) };
|
|
6858
|
+
}));
|
|
6859
|
+
}
|
|
6860
|
+
/**
|
|
6861
|
+
* What importing the package would do, per agent and part (`POST admin/agent-packages/preview`):
|
|
6862
|
+
* `created`, `changed`, `unchanged`, `kept-local`, `left-behind` or `refused` with the field
|
|
6863
|
+
* errors of the save validators, after one check of the whole package against this host as it would
|
|
6864
|
+
* be after the import. Changes nothing. The server reads the package strictly: a package it does not
|
|
6865
|
+
* read fails with `assistant-package-format-unsupported`, one above 1 MB or 20 agents with
|
|
6866
|
+
* `assistant-package-too-large`.
|
|
6867
|
+
*/
|
|
6868
|
+
previewAgentPackageImport(agentPackage, options = {}) {
|
|
6869
|
+
return this.request('POST', 'admin/agent-packages/preview', { package: agentPackage, options });
|
|
6870
|
+
}
|
|
6871
|
+
/**
|
|
6872
|
+
* Imports the package in one transaction (`POST admin/agent-packages/import`): every agent and part
|
|
6873
|
+
* of it, or nothing. Fails as `previewAgentPackageImport` does, and with `assistant-package-refused`
|
|
6874
|
+
* and the field error `parts: invalid` when the check refuses a part; preview again to see which part
|
|
6875
|
+
* and why. Every part is audited as its save.
|
|
6876
|
+
*/
|
|
6877
|
+
importAgentPackage(agentPackage, options = {}) {
|
|
6878
|
+
return this.request('POST', 'admin/agent-packages/import', { package: agentPackage, options });
|
|
6879
|
+
}
|
|
6880
|
+
/**
|
|
6881
|
+
* Unlinks one part of the agent, or without `part` the whole agent, from its package
|
|
6882
|
+
* (`POST admin/agents/{id}/package/unlink`): its locks no longer hold and the next upgrade keeps it as
|
|
6883
|
+
* `kept-local` unless the import relinks it. Fails with `assistant-package-not-linked` for an agent
|
|
6884
|
+
* or part without a link and with the field error `part: invalid` for an unknown part key.
|
|
6885
|
+
*/
|
|
6886
|
+
unlinkAgentPackage(agentId, request = {}) {
|
|
6887
|
+
return this.request('POST', `${agentPath(agentId)}/package/unlink`, request);
|
|
6888
|
+
}
|
|
5707
6889
|
download(path) {
|
|
5708
6890
|
return this.transport.download(path, 'application/x-ndjson', adminStatusCodes);
|
|
5709
6891
|
}
|
|
@@ -5734,6 +6916,43 @@ function triggerPath(agentId, triggerId) {
|
|
|
5734
6916
|
function consultationPath(agentId, subjectType) {
|
|
5735
6917
|
return `${agentPath(agentId)}/consultations/${encodeURIComponent(subjectType)}`;
|
|
5736
6918
|
}
|
|
6919
|
+
function handOffPath(agentId, subjectType) {
|
|
6920
|
+
return `${agentPath(agentId)}/hand-offs/${encodeURIComponent(subjectType)}`;
|
|
6921
|
+
}
|
|
6922
|
+
function metadataPath(agentId, name) {
|
|
6923
|
+
return `${agentPath(agentId)}/metadata/${encodeURIComponent(name)}`;
|
|
6924
|
+
}
|
|
6925
|
+
/**
|
|
6926
|
+
* The references to agents outside an exported selection, from the export's header: a JSON array,
|
|
6927
|
+
* of which only entries with a safe code and string ids are kept. Without the header, none.
|
|
6928
|
+
*/
|
|
6929
|
+
function packageWarnings(header) {
|
|
6930
|
+
if (!header) {
|
|
6931
|
+
return [];
|
|
6932
|
+
}
|
|
6933
|
+
let items;
|
|
6934
|
+
try {
|
|
6935
|
+
items = JSON.parse(header);
|
|
6936
|
+
}
|
|
6937
|
+
catch {
|
|
6938
|
+
return [];
|
|
6939
|
+
}
|
|
6940
|
+
if (!Array.isArray(items)) {
|
|
6941
|
+
return [];
|
|
6942
|
+
}
|
|
6943
|
+
const warnings = [];
|
|
6944
|
+
for (const item of items) {
|
|
6945
|
+
const record = item && typeof item === 'object' ? item : null;
|
|
6946
|
+
if (record
|
|
6947
|
+
&& typeof record['agentId'] === 'string'
|
|
6948
|
+
&& typeof record['part'] === 'string'
|
|
6949
|
+
&& typeof record['referencedAgentId'] === 'string'
|
|
6950
|
+
&& nhAssistantIsSafeCode(record['code'])) {
|
|
6951
|
+
warnings.push({ agentId: record['agentId'], part: record['part'], code: record['code'], referencedAgentId: record['referencedAgentId'] });
|
|
6952
|
+
}
|
|
6953
|
+
}
|
|
6954
|
+
return warnings;
|
|
6955
|
+
}
|
|
5737
6956
|
/** Appends the filter values that are set as query parameters. */
|
|
5738
6957
|
function withQuery$1(path, filter) {
|
|
5739
6958
|
const query = new URLSearchParams();
|
|
@@ -5922,7 +7141,9 @@ class NhAssistantAgentRunApiService {
|
|
|
5922
7141
|
}
|
|
5923
7142
|
/**
|
|
5924
7143
|
* Pending proposals the caller may decide, sorted by expiry, or with `grouped` by parent and subject,
|
|
5925
|
-
* with what is new since the caller's last visit (`visitInbox`).
|
|
7144
|
+
* with what is new since the caller's last visit (`visitInbox`). `status` lists the proposals that
|
|
7145
|
+
* wait for the application's report (`awaiting-application`) or for an approver to resolve an
|
|
7146
|
+
* uncertain execution (`execution-unknown`) instead, with the same visibility.
|
|
5926
7147
|
*/
|
|
5927
7148
|
getInbox(filter = {}) {
|
|
5928
7149
|
const query = new URLSearchParams();
|
|
@@ -6568,18 +7789,32 @@ class NhAssistantPushService {
|
|
|
6568
7789
|
this.subscribedState = signal(false, ...(ngDevMode ? [{ debugName: "subscribedState" }] : []));
|
|
6569
7790
|
this.busyState = signal(false, ...(ngDevMode ? [{ debugName: "busyState" }] : []));
|
|
6570
7791
|
this.openSubject = new Subject();
|
|
7792
|
+
this.openRunSubject = new Subject();
|
|
6571
7793
|
this.revision = 0;
|
|
6572
7794
|
this.onWorkerMessage = (event) => {
|
|
6573
7795
|
const data = event.data;
|
|
6574
7796
|
if (data?.type === openConversationMessage && typeof data.conversationId === 'string') {
|
|
6575
|
-
this.
|
|
7797
|
+
this.openNotification(data.conversationId, typeof data.runId === 'string' ? data.runId : undefined);
|
|
6576
7798
|
}
|
|
6577
7799
|
};
|
|
6578
7800
|
/** The caller's server-side choice, or `null` before it was loaded. */
|
|
6579
7801
|
this.settings = this.settingsState.asReadonly();
|
|
6580
7802
|
this.busy = this.busyState.asReadonly();
|
|
6581
|
-
/**
|
|
7803
|
+
/**
|
|
7804
|
+
* Conversations a clicked notification asks to open; the assistant panel opens them. A
|
|
7805
|
+
* notification about the proposals of a run goes to `openRun$` instead while the application
|
|
7806
|
+
* subscribes to it.
|
|
7807
|
+
*/
|
|
6582
7808
|
this.openConversation$ = this.openSubject.asObservable();
|
|
7809
|
+
/**
|
|
7810
|
+
* Runs whose proposals a clicked notification is about, for the application to open its inbox of
|
|
7811
|
+
* the run, for example `nh-assistant-agent-inbox` with `[runId]`, which lists every proposal of the
|
|
7812
|
+
* run the person may decide. While the application subscribes, such a click emits the run here
|
|
7813
|
+
* instead of opening the conversation in the panel; without a subscriber it opens the conversation
|
|
7814
|
+
* as before. Subscribe in the application shell, so a notification that opens a new window finds
|
|
7815
|
+
* the subscription.
|
|
7816
|
+
*/
|
|
7817
|
+
this.openRun$ = this.openRunSubject.asObservable();
|
|
6583
7818
|
this.state = computed(() => {
|
|
6584
7819
|
const settings = this.settingsState();
|
|
6585
7820
|
if (!settings?.pushAvailable || !this.isSupported()) {
|
|
@@ -6599,12 +7834,25 @@ class NhAssistantPushService {
|
|
|
6599
7834
|
navigator.serviceWorker.removeEventListener('message', this.onWorkerMessage);
|
|
6600
7835
|
}
|
|
6601
7836
|
this.openSubject.complete();
|
|
7837
|
+
this.openRunSubject.complete();
|
|
6602
7838
|
});
|
|
6603
7839
|
if (this.browser && this.isSupported()) {
|
|
6604
7840
|
navigator.serviceWorker.addEventListener('message', this.onWorkerMessage);
|
|
6605
7841
|
navigator.serviceWorker.startMessages();
|
|
6606
7842
|
}
|
|
6607
7843
|
}
|
|
7844
|
+
/**
|
|
7845
|
+
* Opens what a clicked notification is about: the run through `openRun$` when the notification
|
|
7846
|
+
* names one and the application subscribes, otherwise the conversation through
|
|
7847
|
+
* `openConversation$`. The bundled worker and the panel's notification fragments call it.
|
|
7848
|
+
*/
|
|
7849
|
+
openNotification(conversationId, runId) {
|
|
7850
|
+
if (runId && this.openRunSubject.observed) {
|
|
7851
|
+
this.openRunSubject.next(runId);
|
|
7852
|
+
return;
|
|
7853
|
+
}
|
|
7854
|
+
this.openSubject.next(conversationId);
|
|
7855
|
+
}
|
|
6608
7856
|
/**
|
|
6609
7857
|
* Loads the user's choice and, when permission was granted before, renews this browser's
|
|
6610
7858
|
* subscription, which also moves it to the current user and to a rotated server key.
|
|
@@ -7013,6 +8261,22 @@ function applyNhAssistantEvent(conversation, event, clientMessageId) {
|
|
|
7013
8261
|
: appendToCurrentAssistantMessage(withToolAwaiting, approval);
|
|
7014
8262
|
return { ...withApproval, status: 'waiting-for-approval', pendingApproval: approval };
|
|
7015
8263
|
}
|
|
8264
|
+
case 'question.asked': {
|
|
8265
|
+
const question = { ...event.data, type: 'question' };
|
|
8266
|
+
// The ask_question call waits for the answer as a call waits for an approval.
|
|
8267
|
+
const withToolAwaiting = updateToolCall(conversation, question.questionId, part => ({ ...part, status: 'awaiting-answer' }));
|
|
8268
|
+
const withQuestion = hasQuestion(withToolAwaiting, question.questionId)
|
|
8269
|
+
? replaceQuestion(withToolAwaiting, question)
|
|
8270
|
+
: appendToCurrentAssistantMessage(withToolAwaiting, question);
|
|
8271
|
+
return { ...withQuestion, status: 'waiting-for-approval', pendingQuestion: question };
|
|
8272
|
+
}
|
|
8273
|
+
case 'question.answered': {
|
|
8274
|
+
const question = { ...event.data, type: 'question' };
|
|
8275
|
+
return {
|
|
8276
|
+
...replaceQuestion(conversation, question),
|
|
8277
|
+
pendingQuestion: conversation.pendingQuestion?.questionId === question.questionId ? null : conversation.pendingQuestion ?? null
|
|
8278
|
+
};
|
|
8279
|
+
}
|
|
7016
8280
|
case 'connection.required': {
|
|
7017
8281
|
const data = event.data;
|
|
7018
8282
|
// One card per server and answer, also when a live update repeats the event.
|
|
@@ -7032,7 +8296,8 @@ function applyNhAssistantEvent(conversation, event, clientMessageId) {
|
|
|
7032
8296
|
return {
|
|
7033
8297
|
...conversation,
|
|
7034
8298
|
status,
|
|
7035
|
-
pendingApproval: status === 'waiting-for-approval' ? conversation.pendingApproval : null
|
|
8299
|
+
pendingApproval: status === 'waiting-for-approval' ? conversation.pendingApproval : null,
|
|
8300
|
+
pendingQuestion: status === 'waiting-for-approval' ? conversation.pendingQuestion ?? null : null
|
|
7036
8301
|
};
|
|
7037
8302
|
}
|
|
7038
8303
|
case 'error':
|
|
@@ -7076,6 +8341,19 @@ function applyNhAssistantApprovalDecision(conversation, approvalId, decision) {
|
|
|
7076
8341
|
}
|
|
7077
8342
|
return updated;
|
|
7078
8343
|
}
|
|
8344
|
+
/**
|
|
8345
|
+
* Records the addressee's answer to a question locally until the server state is reloaded: the
|
|
8346
|
+
* question reads as answered with the chosen index and the turn runs again.
|
|
8347
|
+
*/
|
|
8348
|
+
function applyNhAssistantQuestionAnswer(conversation, questionId, choice) {
|
|
8349
|
+
const messages = conversation.messages.map(message => ({
|
|
8350
|
+
...message,
|
|
8351
|
+
parts: message.parts.map(part => part.type === 'question' && part.questionId === questionId
|
|
8352
|
+
? { ...part, status: 'answered', answerIndex: choice }
|
|
8353
|
+
: part)
|
|
8354
|
+
}));
|
|
8355
|
+
return updateToolCall({ ...conversation, messages, status: 'running', pendingQuestion: null }, questionId, part => ({ ...part, status: 'running' }));
|
|
8356
|
+
}
|
|
7079
8357
|
/** An approval part after the user's decision. */
|
|
7080
8358
|
function decidedApproval(part, decision) {
|
|
7081
8359
|
const decided = { ...part, status: decision === 'approve' ? 'approved' : 'rejected' };
|
|
@@ -7112,7 +8390,8 @@ function applyNhAssistantConversationChange(conversation, change) {
|
|
|
7112
8390
|
activeActorId: change.activeActorId,
|
|
7113
8391
|
lastMessageSequence: change.lastMessageSequence,
|
|
7114
8392
|
participantCount: change.participantCount,
|
|
7115
|
-
pendingApproval: change.status === 'waiting-for-approval' ? conversation.pendingApproval : null
|
|
8393
|
+
pendingApproval: change.status === 'waiting-for-approval' ? conversation.pendingApproval : null,
|
|
8394
|
+
pendingQuestion: change.status === 'waiting-for-approval' ? conversation.pendingQuestion ?? null : null
|
|
7116
8395
|
};
|
|
7117
8396
|
}
|
|
7118
8397
|
/**
|
|
@@ -7204,8 +8483,23 @@ function partKey(part) {
|
|
|
7204
8483
|
if (part.type === 'connection-required') {
|
|
7205
8484
|
return `connection-${part.serverId}`;
|
|
7206
8485
|
}
|
|
8486
|
+
if (part.type === 'question') {
|
|
8487
|
+
return `question-${part.questionId}`;
|
|
8488
|
+
}
|
|
7207
8489
|
return 'text';
|
|
7208
8490
|
}
|
|
8491
|
+
function hasQuestion(conversation, questionId) {
|
|
8492
|
+
return conversation.messages.some(message => message.parts.some(part => part.type === 'question' && part.questionId === questionId));
|
|
8493
|
+
}
|
|
8494
|
+
function replaceQuestion(conversation, question) {
|
|
8495
|
+
return {
|
|
8496
|
+
...conversation,
|
|
8497
|
+
messages: conversation.messages.map(message => ({
|
|
8498
|
+
...message,
|
|
8499
|
+
parts: message.parts.map(part => part.type === 'question' && part.questionId === question.questionId ? question : part)
|
|
8500
|
+
}))
|
|
8501
|
+
};
|
|
8502
|
+
}
|
|
7209
8503
|
function findToolCall(messages, invocationId) {
|
|
7210
8504
|
return findLatestToolCall(messages, part => part.invocationId === invocationId);
|
|
7211
8505
|
}
|
|
@@ -7657,6 +8951,24 @@ class NhAssistantStore {
|
|
|
7657
8951
|
const approval = this.activeConversation()?.pendingApproval;
|
|
7658
8952
|
return approval ? this.approvalRights().get(approval.approvalId)?.canDecide === true : false;
|
|
7659
8953
|
}, ...(ngDevMode ? [{ debugName: "canDecide" }] : []));
|
|
8954
|
+
/**
|
|
8955
|
+
* True when the current user may answer the question the open chat waits for: it is addressed to
|
|
8956
|
+
* them and still pending (`ask_question`, `run.AllowQuestions()` on the server).
|
|
8957
|
+
*/
|
|
8958
|
+
this.canAnswer = computed(() => {
|
|
8959
|
+
const conversation = this.activeConversation();
|
|
8960
|
+
const question = conversation?.pendingQuestion;
|
|
8961
|
+
return !!question && question.status === 'pending' && question.addresseeActorId === conversation?.currentActorId;
|
|
8962
|
+
}, ...(ngDevMode ? [{ debugName: "canAnswer" }] : []));
|
|
8963
|
+
/** The member a pending question of the open conversation is addressed to, when it is someone else. */
|
|
8964
|
+
this.questionAddressee = computed(() => {
|
|
8965
|
+
const conversation = this.activeConversation();
|
|
8966
|
+
const question = conversation?.pendingQuestion;
|
|
8967
|
+
if (!question || question.addresseeActorId === conversation?.currentActorId) {
|
|
8968
|
+
return null;
|
|
8969
|
+
}
|
|
8970
|
+
return conversation?.members?.find(member => member.actorId === question.addresseeActorId) ?? null;
|
|
8971
|
+
}, ...(ngDevMode ? [{ debugName: "questionAddressee" }] : []));
|
|
7660
8972
|
/** The member whose turn runs or waits in the open conversation, when it is someone else. */
|
|
7661
8973
|
this.activeMember = computed(() => {
|
|
7662
8974
|
const conversation = this.activeConversation();
|
|
@@ -8189,16 +9501,61 @@ class NhAssistantStore {
|
|
|
8189
9501
|
});
|
|
8190
9502
|
}
|
|
8191
9503
|
/**
|
|
8192
|
-
*
|
|
8193
|
-
*
|
|
8194
|
-
*
|
|
9504
|
+
* Answers the question the open chat waits for with the choice at `choice` and streams the resumed
|
|
9505
|
+
* turn, as a decision does. Ignores another question, a question addressed to someone else, a choice
|
|
9506
|
+
* the question does not offer and calls while a turn or a decision is in flight. A refused answer,
|
|
9507
|
+
* such as an expired question, shows its error and reads the conversation again.
|
|
8195
9508
|
*/
|
|
8196
|
-
|
|
8197
|
-
const
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
9509
|
+
answerQuestion(questionId, choice) {
|
|
9510
|
+
const session = this.activeSession();
|
|
9511
|
+
const conversation = session?.conversation;
|
|
9512
|
+
if (!session || !conversation || session.deciding || session.streaming || !this.canAnswer()) {
|
|
9513
|
+
return;
|
|
9514
|
+
}
|
|
9515
|
+
const question = conversation.pendingQuestion;
|
|
9516
|
+
if (!question || question.questionId !== questionId || !Number.isInteger(choice) || choice < 0 || choice >= question.choices.length) {
|
|
9517
|
+
return;
|
|
9518
|
+
}
|
|
9519
|
+
const conversationId = conversation.id;
|
|
9520
|
+
this.patchSession(conversationId, current => ({ ...current, deciding: true, error: null, notice: null }));
|
|
9521
|
+
let accepted = false;
|
|
9522
|
+
let failed = false;
|
|
9523
|
+
this.runStream(conversationId, this.api.answerQuestion(conversationId, questionId, { choice }), {
|
|
9524
|
+
next: event => {
|
|
9525
|
+
if (!accepted && event.type !== 'error') {
|
|
9526
|
+
accepted = true;
|
|
9527
|
+
this.patchSession(conversationId, current => ({
|
|
9528
|
+
...current,
|
|
9529
|
+
conversation: applyNhAssistantQuestionAnswer(current.conversation, questionId, choice)
|
|
9530
|
+
}));
|
|
9531
|
+
}
|
|
9532
|
+
if (event.type === 'error') {
|
|
9533
|
+
failed = true;
|
|
9534
|
+
if (!accepted) {
|
|
9535
|
+
this.patchSession(conversationId, current => ({ ...current, error: event.data }));
|
|
9536
|
+
return;
|
|
9537
|
+
}
|
|
9538
|
+
}
|
|
9539
|
+
this.applyEvent(conversationId, event);
|
|
9540
|
+
},
|
|
9541
|
+
complete: () => {
|
|
9542
|
+
this.patchSession(conversationId, current => ({ ...current, deciding: false }));
|
|
9543
|
+
// An expired question released the conversation; reading it again shows that.
|
|
9544
|
+
this.afterTurn(conversationId, failed);
|
|
9545
|
+
}
|
|
9546
|
+
});
|
|
9547
|
+
}
|
|
9548
|
+
/**
|
|
9549
|
+
* Decides a proposal of an agent's run with `POST approvals/{id}/decisions`. An approved deferred
|
|
9550
|
+
* proposal executes later as a background operation; an inline one wakes the waiting run. The
|
|
9551
|
+
* reloaded snapshot shows the outcome and the proposals that remain open.
|
|
9552
|
+
*/
|
|
9553
|
+
async decideProposal(conversationId, approval, decision, reason) {
|
|
9554
|
+
const revision = this.accountRevision;
|
|
9555
|
+
this.patchSession(conversationId, session => ({ ...session, deciding: true, error: null, notice: null }));
|
|
9556
|
+
try {
|
|
9557
|
+
const proposal = await firstValueFrom(this.agentRuns.decide(approval, decision, reason));
|
|
9558
|
+
if (revision === this.accountRevision) {
|
|
8202
9559
|
if (decision === 'reject' && proposal.status === 'rejected' && proposal.canGiveFeedback === true) {
|
|
8203
9560
|
this.feedbackApprovalsState.update(approvals => new Set(approvals).add(approval.approvalId));
|
|
8204
9561
|
}
|
|
@@ -8220,6 +9577,42 @@ class NhAssistantStore {
|
|
|
8220
9577
|
}
|
|
8221
9578
|
}
|
|
8222
9579
|
}
|
|
9580
|
+
/**
|
|
9581
|
+
* Resolves an uncertain hand-off in the open chat that the current user approved (`canResolve`):
|
|
9582
|
+
* `hand-to-application` hands it to the application again with a new report deadline,
|
|
9583
|
+
* `mark-resolved` confirms its outcome. The conversation the server returns replaces the shown one.
|
|
9584
|
+
* Ignores approvals the user may not resolve and calls while a decision or a turn is in flight.
|
|
9585
|
+
*/
|
|
9586
|
+
async resolveApproval(approvalId, resolution, reason) {
|
|
9587
|
+
const session = this.activeSession();
|
|
9588
|
+
const conversation = session?.conversation;
|
|
9589
|
+
if (!session || !conversation || session.deciding || session.streaming
|
|
9590
|
+
|| !resolvableApprovalParts(conversation).some(part => part.approvalId === approvalId)) {
|
|
9591
|
+
return;
|
|
9592
|
+
}
|
|
9593
|
+
const conversationId = conversation.id;
|
|
9594
|
+
const revision = this.accountRevision;
|
|
9595
|
+
this.patchSession(conversationId, current => ({ ...current, deciding: true, error: null, notice: null }));
|
|
9596
|
+
try {
|
|
9597
|
+
const resolved = await firstValueFrom(this.api.resolveApproval(conversationId, approvalId, {
|
|
9598
|
+
action: resolution,
|
|
9599
|
+
...(reason ? { reason } : {})
|
|
9600
|
+
}));
|
|
9601
|
+
if (revision === this.accountRevision) {
|
|
9602
|
+
this.upsertSession(resolved);
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
catch (error) {
|
|
9606
|
+
if (revision === this.accountRevision) {
|
|
9607
|
+
this.setError(conversationId, error);
|
|
9608
|
+
}
|
|
9609
|
+
}
|
|
9610
|
+
finally {
|
|
9611
|
+
if (revision === this.accountRevision) {
|
|
9612
|
+
this.patchSession(conversationId, current => ({ ...current, deciding: false }));
|
|
9613
|
+
}
|
|
9614
|
+
}
|
|
9615
|
+
}
|
|
8223
9616
|
/** Asks the server to stop the running turn or to abandon a waiting approval of the open conversation. */
|
|
8224
9617
|
async cancel() {
|
|
8225
9618
|
const conversationId = this.activeIdState();
|
|
@@ -9172,6 +10565,12 @@ function approvalParts(conversation) {
|
|
|
9172
10565
|
}
|
|
9173
10566
|
return [...approvals.values()];
|
|
9174
10567
|
}
|
|
10568
|
+
/** The uncertain hand-offs of a chat that the current user may resolve (`canResolve`). */
|
|
10569
|
+
function resolvableApprovalParts(conversation) {
|
|
10570
|
+
return conversation.messages
|
|
10571
|
+
.flatMap(message => message.parts)
|
|
10572
|
+
.filter((part) => part.type === 'approval' && part.canResolve === true && part.status === 'execution-unknown');
|
|
10573
|
+
}
|
|
9175
10574
|
function pendingApprovalParts(conversation) {
|
|
9176
10575
|
const approvals = new Map();
|
|
9177
10576
|
for (const message of conversation.messages) {
|
|
@@ -9815,6 +11214,7 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9815
11214
|
'assistant-turn-timeout',
|
|
9816
11215
|
'assistant-model-unavailable',
|
|
9817
11216
|
'assistant-classification-not-permitted',
|
|
11217
|
+
'assistant-model-region-denied',
|
|
9818
11218
|
'assistant-files-unavailable',
|
|
9819
11219
|
'assistant-files-not-accepted',
|
|
9820
11220
|
'assistant-file-reference-invalid',
|
|
@@ -9867,6 +11267,7 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9867
11267
|
'assistant-skill-switch-limit',
|
|
9868
11268
|
'assistant-moved-to-shadow',
|
|
9869
11269
|
'assistant-shadow-variant',
|
|
11270
|
+
'assistant-not-shadow-variant',
|
|
9870
11271
|
'assistant-service-account-not-used',
|
|
9871
11272
|
'assistant-service-account-not-found',
|
|
9872
11273
|
'assistant-skill-in-code',
|
|
@@ -9877,6 +11278,7 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9877
11278
|
'assistant-run-settings-in-code',
|
|
9878
11279
|
'assistant-run-settings-in-use',
|
|
9879
11280
|
'assistant-skill-candidate-not-found',
|
|
11281
|
+
'assistant-trigger-candidate-not-found',
|
|
9880
11282
|
'assistant-skill-version-gone',
|
|
9881
11283
|
'assistant-account-search-unavailable',
|
|
9882
11284
|
'assistant-handoff-unavailable',
|
|
@@ -9924,15 +11326,25 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9924
11326
|
// Feedback on proposals
|
|
9925
11327
|
'assistant-feedback-invalid',
|
|
9926
11328
|
'assistant-feedback-not-accepted',
|
|
11329
|
+
// Questions an agent asks with ask_question in a person's chat
|
|
11330
|
+
'assistant-question-invalid',
|
|
11331
|
+
'assistant-question-not-found',
|
|
11332
|
+
'assistant-question-not-pending',
|
|
11333
|
+
'assistant-question-forbidden',
|
|
11334
|
+
'assistant-question-expired',
|
|
11335
|
+
'assistant-question-cancelled',
|
|
11336
|
+
'assistant-question-answer-invalid',
|
|
9927
11337
|
// Consultations of other agents
|
|
9928
11338
|
'assistant-consult-subject-unavailable',
|
|
9929
11339
|
'assistant-consult-agent-unavailable',
|
|
9930
11340
|
'assistant-consult-depth-exceeded',
|
|
9931
11341
|
'assistant-consult-budget-exhausted',
|
|
9932
11342
|
'assistant-consult-limit-reached',
|
|
11343
|
+
'assistant-consult-turn-limit',
|
|
9933
11344
|
'assistant-consult-timeout',
|
|
9934
11345
|
'assistant-consult-failed',
|
|
9935
11346
|
'assistant-consult-read-only',
|
|
11347
|
+
'assistant-consult-tool-not-selected',
|
|
9936
11348
|
'assistant-consult-proposal-refused',
|
|
9937
11349
|
'assistant-consult-asker-decides',
|
|
9938
11350
|
'assistant-consult-route-not-allowed',
|
|
@@ -9941,6 +11353,17 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9941
11353
|
'assistant-consultation-in-code',
|
|
9942
11354
|
'assistant-consultation-not-found',
|
|
9943
11355
|
'assistant-consultations-not-allowed',
|
|
11356
|
+
// Hand-offs defined as data and shadow variants created in the administration
|
|
11357
|
+
'assistant-handoffs-not-allowed',
|
|
11358
|
+
'assistant-handoff-in-code',
|
|
11359
|
+
'assistant-handoff-not-found',
|
|
11360
|
+
'assistant-shadow-variants-not-allowed',
|
|
11361
|
+
// Agent packages: their format and the parts they lock
|
|
11362
|
+
'assistant-package-format-unsupported',
|
|
11363
|
+
'assistant-package-too-large',
|
|
11364
|
+
'assistant-package-refused',
|
|
11365
|
+
'assistant-package-locked',
|
|
11366
|
+
'assistant-package-not-linked',
|
|
9944
11367
|
// Preferences and administration
|
|
9945
11368
|
'assistant-validation',
|
|
9946
11369
|
'assistant-instructions-too-long',
|
|
@@ -9951,6 +11374,13 @@ const NH_ASSISTANT_SERVER_ERROR_CODES = [
|
|
|
9951
11374
|
'assistant-agent-exists',
|
|
9952
11375
|
'assistant-code-agent-not-deletable',
|
|
9953
11376
|
'assistant-agent-not-code',
|
|
11377
|
+
// Agent metadata registered by the application
|
|
11378
|
+
'assistant-metadata-entry-not-found',
|
|
11379
|
+
'assistant-metadata-read-only',
|
|
11380
|
+
// Instructions from the application's text assets
|
|
11381
|
+
'assistant-instructions-asset-not-found',
|
|
11382
|
+
'assistant-instructions-asset-unavailable',
|
|
11383
|
+
'assistant-agent-instructions-unavailable',
|
|
9954
11384
|
'assistant-mcp-server-not-found',
|
|
9955
11385
|
'assistant-mcp-server-exists',
|
|
9956
11386
|
'assistant-mcp-tool-not-found',
|
|
@@ -9995,6 +11425,12 @@ const NH_ASSISTANT_ERROR_CODES = [
|
|
|
9995
11425
|
const NH_ASSISTANT_JOIN_FRAGMENT = 'nh-assistant-join';
|
|
9996
11426
|
/** Fragment a clicked notification opens: `#nh-assistant-conversation=<id>`. */
|
|
9997
11427
|
const NH_ASSISTANT_CONVERSATION_FRAGMENT = 'nh-assistant-conversation';
|
|
11428
|
+
/**
|
|
11429
|
+
* Fragment a clicked notification about the proposals of a run opens:
|
|
11430
|
+
* `#nh-assistant-run=<runId>.<conversationId>`. The run goes to `NhAssistantPushService.openRun$`
|
|
11431
|
+
* while the application subscribes; otherwise the panel opens the conversation.
|
|
11432
|
+
*/
|
|
11433
|
+
const NH_ASSISTANT_RUN_FRAGMENT = 'nh-assistant-run';
|
|
9998
11434
|
/** Builds the default invitation link: the current page with the join fragment. */
|
|
9999
11435
|
function nhAssistantShareLink(conversationId, token) {
|
|
10000
11436
|
const location = globalThis.location;
|
|
@@ -10032,7 +11468,8 @@ const builtInPaths = {
|
|
|
10032
11468
|
bell: 'M6 16V11a6 6 0 0 1 12 0v5l2 2H4zM10 20a2 2 0 0 0 4 0',
|
|
10033
11469
|
leave: 'M10 4H5v16h5M14 8l4 4-4 4M18 12H9',
|
|
10034
11470
|
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',
|
|
10035
|
-
file: 'M6 3h8l4 4v14H6zM14 3v4h4'
|
|
11471
|
+
file: 'M6 3h8l4 4v14H6zM14 3v4h4',
|
|
11472
|
+
lock: 'M6 11h12v9H6zM8.5 11V8a3.5 3.5 0 0 1 7 0v3M12 15v2'
|
|
10036
11473
|
};
|
|
10037
11474
|
/** Decorative icon. The surrounding control provides the accessible name. */
|
|
10038
11475
|
class NhAssistantIconComponent {
|
|
@@ -10288,7 +11725,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10288
11725
|
`, 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}.strip{display:flex;gap:6px;overflow-x:auto;padding:0 12px 8px 16px;scrollbar-width:none}.strip::-webkit-scrollbar{display:none}.chip{display:inline-flex;flex:none;align-items:center;gap:6px;max-width:180px;height:26px;border:1px solid var(--nha-border);border-radius:999px;padding:0 10px 0 8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;font-size:12px;cursor:pointer}.chip:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip:hover{border-color:var(--nha-highlight)}.title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared{flex:none;color:var(--nha-text-muted);font-size:12px}.indicator{flex:none;width:8px;height:8px;border-radius:50%;background:var(--nha-accent)}.chip[data-state=unread] .indicator{background:var(--nha-highlight)}.chip[data-state=waiting] .indicator{background:var(--nha-warning)}.chip[data-state=running] .indicator{width:10px;height:10px;border:2px solid color-mix(in srgb,var(--nha-highlight) 30%,transparent);border-top-color:var(--nha-highlight);background:transparent;animation:nh-assistant-spin .9s linear infinite}@media(prefers-reduced-motion:reduce){.chip[data-state=running] .indicator{border-color:var(--nha-highlight);animation:none}}@keyframes nh-assistant-spin{to{transform:rotate(360deg)}}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
10289
11726
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], conversationSelect: [{ type: i0.Output, args: ["conversationSelect"] }] } });
|
|
10290
11727
|
|
|
10291
|
-
let nextId$
|
|
11728
|
+
let nextId$c = 0;
|
|
10292
11729
|
/**
|
|
10293
11730
|
* Chooses the agent for new conversations. Agent names come from the host's translation
|
|
10294
11731
|
* keys; agents created by an administrator carry literal text, which is shown as is.
|
|
@@ -10301,7 +11738,7 @@ class NhAssistantAgentPickerComponent {
|
|
|
10301
11738
|
/** Compact prompt-bar control; capability information remains in the tooltip and accessible description. */
|
|
10302
11739
|
this.compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : []));
|
|
10303
11740
|
this.agentChange = output();
|
|
10304
|
-
this.selectId = `nh-assistant-agent-picker-${nextId$
|
|
11741
|
+
this.selectId = `nh-assistant-agent-picker-${nextId$c++}`;
|
|
10305
11742
|
this.selected = computed(() => this.agents().find(agent => agent.id === this.selectedAgentId()) ?? null, ...(ngDevMode ? [{ debugName: "selected" }] : []));
|
|
10306
11743
|
}
|
|
10307
11744
|
onChange(event) {
|
|
@@ -10353,7 +11790,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10353
11790
|
`, styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;gap:2px;min-width:0}:host(.compact){flex-direction:row;align-items:center}:host(.compact) select{min-width:0;max-width:100%;border-color:transparent;padding-left:8px;background:transparent;cursor:pointer}:host(.compact) select:hover:not(:disabled){border-color:var(--nha-border);background:var(--nha-surface-strong)}:host(.compact) select:disabled{cursor:default}select{align-self:flex-start;max-width:100%;min-height:32px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 28px 4px 10px;color:var(--nha-text);background:var(--nha-background);font:inherit;font-size:13px;font-weight:650}select:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}select:disabled{opacity:1;cursor:default}.capability{padding-left:2px;color:var(--nha-text-muted);font-size:11px}.capability[data-can-mutate=true]{color:var(--nha-warning)}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
10354
11791
|
}], propDecorators: { agents: [{ type: i0.Input, args: [{ isSignal: true, alias: "agents", required: true }] }], selectedAgentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedAgentId", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], agentChange: [{ type: i0.Output, args: ["agentChange"] }] } });
|
|
10355
11792
|
|
|
10356
|
-
let nextId$
|
|
11793
|
+
let nextId$b = 0;
|
|
10357
11794
|
/**
|
|
10358
11795
|
* Message input. Enter sends when sending is available; Shift+Enter inserts a new line.
|
|
10359
11796
|
* Drafting remains available while the assistant runs or waits for approval. With `uploads`, an
|
|
@@ -10371,9 +11808,12 @@ class NhAssistantComposerComponent {
|
|
|
10371
11808
|
this.busy = input(false, ...(ngDevMode ? [{ debugName: "busy" }] : []));
|
|
10372
11809
|
/** Keeps the send action available next to Stop so the host can queue messages. */
|
|
10373
11810
|
this.queueWhileBusy = input(false, ...(ngDevMode ? [{ debugName: "queueWhileBusy" }] : []));
|
|
10374
|
-
/**
|
|
11811
|
+
/**
|
|
11812
|
+
* Announces why sending is temporarily unavailable: a running turn, a turn that waits for an
|
|
11813
|
+
* approval, or one that waits for the answer to a question the agent asked.
|
|
11814
|
+
*/
|
|
10375
11815
|
this.status = input(null, ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
10376
|
-
/** Name of the participant whose turn runs or waits, when it is someone else. */
|
|
11816
|
+
/** Name of the participant whose turn runs or waits, or who answers the question, when it is someone else. */
|
|
10377
11817
|
this.statusActor = input(null, ...(ngDevMode ? [{ debugName: "statusActor" }] : []));
|
|
10378
11818
|
/** False when the user may not stop the running turn, such as another participant's turn. */
|
|
10379
11819
|
this.canStop = input(true, ...(ngDevMode ? [{ debugName: "canStop" }] : []));
|
|
@@ -10400,7 +11840,7 @@ class NhAssistantComposerComponent {
|
|
|
10400
11840
|
this.attachButton = viewChild('attachButton', ...(ngDevMode ? [{ debugName: "attachButton" }] : []));
|
|
10401
11841
|
this.ownedFocus = false;
|
|
10402
11842
|
this.previousBusy = false;
|
|
10403
|
-
this.inputId = `nh-assistant-composer-${nextId$
|
|
11843
|
+
this.inputId = `nh-assistant-composer-${nextId$b++}`;
|
|
10404
11844
|
this.hintId = `${this.inputId}-hint`;
|
|
10405
11845
|
this.attachHintId = `${this.inputId}-attach-hint`;
|
|
10406
11846
|
this.attachmentsId = `${this.inputId}-attachments`;
|
|
@@ -10524,11 +11964,11 @@ class NhAssistantComposerComponent {
|
|
|
10524
11964
|
}
|
|
10525
11965
|
}
|
|
10526
11966
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10527
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantComposerComponent, isStandalone: true, selector: "nh-assistant-composer", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, sendDisabled: { classPropertyName: "sendDisabled", publicName: "sendDisabled", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, queueWhileBusy: { classPropertyName: "queueWhileBusy", publicName: "queueWhileBusy", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, statusActor: { classPropertyName: "statusActor", publicName: "statusActor", isSignal: true, isRequired: false, transformFunction: null }, canStop: { classPropertyName: "canStop", publicName: "canStop", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, restore: { classPropertyName: "restore", publicName: "restore", isSignal: true, isRequired: false, transformFunction: null }, uploads: { classPropertyName: "uploads", publicName: "uploads", isSignal: true, isRequired: false, transformFunction: null }, attachments: { classPropertyName: "attachments", publicName: "attachments", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { send: "send", cancel: "cancel", restored: "restored", attach: "attach", removeAttachment: "removeAttachment" }, host: { listeners: { "focusin": "onFocusIn()", "focusout": "onFocusOut($event)" } }, viewQueries: [{ propertyName: "textarea", first: true, predicate: ["textarea"], descendants: true, isSignal: true }, { propertyName: "attachButton", first: true, predicate: ["attachButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<form class=\"composer\" (submit)=\"onSubmit($event)\">\n <label class=\"visually-hidden\" [for]=\"inputId\">{{ 'nh-assistant.composer.label' | translate }}</label>\n <textarea\n #textarea\n data-nh-assistant-autofocus\n rows=\"2\"\n [id]=\"inputId\"\n [value]=\"text()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"'nh-assistant.composer.placeholder' | translate\"\n [attr.aria-describedby]=\"hintId\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n @if (attachments().length > 0) {\n <ul class=\"attachments\" [id]=\"attachmentsId\" [attr.aria-label]=\"'nh-assistant.composer.attachments' | translate\">\n @for (attachment of attachments(); track attachment.id) {\n <li class=\"attachment\" [attr.data-state]=\"attachment.state\">\n <nh-assistant-icon class=\"attachment-icon\" [name]=\"attachment.state === 'failed' ? 'warning' : 'file'\" />\n <div class=\"attachment-body\">\n <span class=\"attachment-name\" [attr.title]=\"attachment.name\">{{ attachment.name }}</span>\n @switch (attachment.state) {\n @case ('uploading') {\n <progress\n class=\"attachment-progress\"\n max=\"100\"\n [value]=\"percent(attachment)\"\n [attr.aria-label]=\"'nh-assistant.composer.uploading' | translate: { name: attachment.name }\"></progress>\n }\n @case ('failed') {\n <span class=\"attachment-error\" role=\"alert\">\n {{ errorKeys(attachment) | nhAssistantTranslate: (attachment.error?.code ?? '') : uploadParams() }}\n </span>\n }\n @default {\n <span class=\"attachment-meta\">{{ size(attachment.size) }}</span>\n }\n }\n </div>\n <button\n class=\"attachment-remove\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n [attr.title]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n (click)=\"remove(attachment)\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </li>\n }\n </ul>\n }\n\n <div class=\"prompt-bar\">\n @if (uploads()) {\n <button\n #attachButton\n class=\"attach\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.composer.attach' | translate\"\n [attr.title]=\"'nh-assistant.composer.attach-hint' | translate: uploadParams()\"\n [attr.aria-describedby]=\"attachHintId\"\n (click)=\"fileInput.click()\">\n <nh-assistant-icon name=\"attach\" />\n </button>\n <span class=\"visually-hidden\" [id]=\"attachHintId\">{{ 'nh-assistant.composer.attach-hint' | translate: uploadParams() }}</span>\n <input\n #fileInput\n class=\"visually-hidden\"\n type=\"file\"\n multiple\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [accept]=\"accept()\"\n (change)=\"onFilesChosen($event)\" />\n }\n <div class=\"prompt-controls\">\n <ng-content select=\"[nhAssistantComposerControls]\" />\n </div>\n <div class=\"actions\">\n @if (busy() && canStop()) {\n <button\n class=\"stop\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.stop' | translate\"\n [attr.title]=\"'nh-assistant.composer.stop' | translate\"\n (click)=\"cancel.emit()\">\n <nh-assistant-icon name=\"stop\" />\n </button>\n }\n @if (!busy() || !canStop() || queueWhileBusy()) {\n <button\n class=\"send\"\n type=\"submit\"\n [disabled]=\"!canSend()\"\n [attr.aria-label]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\"\n [attr.title]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\">\n <nh-assistant-icon name=\"send\" />\n </button>\n }\n </div>\n </div>\n</form>\n\n@if (status() === 'waiting-for-approval') {\n <p class=\"composer-status\" role=\"status\" aria-live=\"polite\">\n @if (statusActor(); as name) {\n {{ 'nh-assistant.composer.status.waiting-for-approval-by' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.composer.status.waiting-for-approval' | translate }}\n }\n </p>\n}\n\n<p class=\"hint\" [id]=\"hintId\">\n @if (tooLong()) {\n <span class=\"error\">{{ 'nh-assistant.composer.too-long' | translate }}</span>\n } @else if (uploading()) {\n <span>{{ 'nh-assistant.composer.uploading-hint' | translate }}</span>\n } @else {\n <span>{{ (busy() && queueWhileBusy() ? 'nh-assistant.queue.hint' : 'nh-assistant.composer.hint') | translate }}</span>\n }\n @if (showCounter()) {\n <span class=\"counter\" [class.error]=\"tooLong()\">\n {{ 'nh-assistant.composer.characters' | translate: { count: length(), max: maxLength() } }}\n </span>\n }\n</p>\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}.composer{display:flex;flex-direction:column;gap:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:8px 8px 8px 14px;background:var(--nha-surface);box-shadow:0 2px 6px color-mix(in srgb,var(--nha-text) 4%,transparent)}.composer:focus-within{border-color:var(--nha-focus);box-shadow:0 0 0 2px color-mix(in srgb,var(--nha-focus) 16%,transparent)}textarea{width:100%;min-width:0;min-height:44px;max-height:180px;border:0;padding:6px 0;color:var(--nha-text);background:transparent;font:inherit;font-size:14px;line-height:1.45;resize:vertical;outline:none}textarea::placeholder{color:var(--nha-text-muted);opacity:1}textarea:disabled{cursor:not-allowed}.prompt-bar{display:flex;align-items:center;gap:8px;min-width:0}.prompt-controls{flex:1;min-width:0}.actions{display:flex;flex-shrink:0;gap:6px}.send,.stop{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:40px;height:40px}.send:focus-visible,.stop:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.send:hover:not(:disabled),.stop:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.send:disabled,.stop:disabled{cursor:not-allowed;opacity:.5}.send:not(:disabled){color:var(--nha-accent-contrast);background:var(--nha-accent)}.send:not(:disabled):hover{color:var(--nha-accent-contrast);background:var(--nha-accent);filter:brightness(1.12)}.stop{color:var(--nha-danger);border-color:var(--nha-danger)}.attach{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;flex-shrink:0;width:40px;height:40px}.attach:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attach:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attach:disabled{cursor:not-allowed;opacity:.5}.attachments{display:flex;flex-wrap:wrap;gap:6px;min-width:0;margin:0;padding:0;list-style:none}.attachment{display:flex;align-items:center;gap:8px;min-width:0;max-width:100%;flex:0 1 240px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 4px 4px 10px;background:var(--nha-background)}.attachment[data-state=failed]{flex-basis:100%;border-color:var(--nha-danger);background:var(--nha-danger-soft)}.attachment-icon{flex-shrink:0;color:var(--nha-text-muted)}[data-state=failed] .attachment-icon{color:var(--nha-danger)}.attachment-body{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.attachment-name{overflow:hidden;font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.attachment-meta,.attachment-error{font-size:11px;color:var(--nha-text-muted);overflow-wrap:anywhere}.attachment-error{color:var(--nha-danger)}.attachment-progress{width:100%;height:4px;accent-color:var(--nha-accent)}.attachment-remove{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;flex-shrink:0;width:32px;height:32px}.attachment-remove:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attachment-remove:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attachment-remove:disabled{cursor:not-allowed;opacity:.5}.hint,.composer-status{display:flex;justify-content:space-between;gap:8px;margin:6px 2px 0;color:var(--nha-text-muted);font-size:11px}.composer-status{margin-bottom:0}.counter{flex:none;font-variant-numeric:tabular-nums}.error{color:var(--nha-danger)}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11967
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantComposerComponent, isStandalone: true, selector: "nh-assistant-composer", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, sendDisabled: { classPropertyName: "sendDisabled", publicName: "sendDisabled", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, queueWhileBusy: { classPropertyName: "queueWhileBusy", publicName: "queueWhileBusy", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, statusActor: { classPropertyName: "statusActor", publicName: "statusActor", isSignal: true, isRequired: false, transformFunction: null }, canStop: { classPropertyName: "canStop", publicName: "canStop", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, restore: { classPropertyName: "restore", publicName: "restore", isSignal: true, isRequired: false, transformFunction: null }, uploads: { classPropertyName: "uploads", publicName: "uploads", isSignal: true, isRequired: false, transformFunction: null }, attachments: { classPropertyName: "attachments", publicName: "attachments", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { send: "send", cancel: "cancel", restored: "restored", attach: "attach", removeAttachment: "removeAttachment" }, host: { listeners: { "focusin": "onFocusIn()", "focusout": "onFocusOut($event)" } }, viewQueries: [{ propertyName: "textarea", first: true, predicate: ["textarea"], descendants: true, isSignal: true }, { propertyName: "attachButton", first: true, predicate: ["attachButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<form class=\"composer\" (submit)=\"onSubmit($event)\">\n <label class=\"visually-hidden\" [for]=\"inputId\">{{ 'nh-assistant.composer.label' | translate }}</label>\n <textarea\n #textarea\n data-nh-assistant-autofocus\n rows=\"2\"\n [id]=\"inputId\"\n [value]=\"text()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"'nh-assistant.composer.placeholder' | translate\"\n [attr.aria-describedby]=\"hintId\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n @if (attachments().length > 0) {\n <ul class=\"attachments\" [id]=\"attachmentsId\" [attr.aria-label]=\"'nh-assistant.composer.attachments' | translate\">\n @for (attachment of attachments(); track attachment.id) {\n <li class=\"attachment\" [attr.data-state]=\"attachment.state\">\n <nh-assistant-icon class=\"attachment-icon\" [name]=\"attachment.state === 'failed' ? 'warning' : 'file'\" />\n <div class=\"attachment-body\">\n <span class=\"attachment-name\" [attr.title]=\"attachment.name\">{{ attachment.name }}</span>\n @switch (attachment.state) {\n @case ('uploading') {\n <progress\n class=\"attachment-progress\"\n max=\"100\"\n [value]=\"percent(attachment)\"\n [attr.aria-label]=\"'nh-assistant.composer.uploading' | translate: { name: attachment.name }\"></progress>\n }\n @case ('failed') {\n <span class=\"attachment-error\" role=\"alert\">\n {{ errorKeys(attachment) | nhAssistantTranslate: (attachment.error?.code ?? '') : uploadParams() }}\n </span>\n }\n @default {\n <span class=\"attachment-meta\">{{ size(attachment.size) }}</span>\n }\n }\n </div>\n <button\n class=\"attachment-remove\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n [attr.title]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n (click)=\"remove(attachment)\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </li>\n }\n </ul>\n }\n\n <div class=\"prompt-bar\">\n @if (uploads()) {\n <button\n #attachButton\n class=\"attach\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.composer.attach' | translate\"\n [attr.title]=\"'nh-assistant.composer.attach-hint' | translate: uploadParams()\"\n [attr.aria-describedby]=\"attachHintId\"\n (click)=\"fileInput.click()\">\n <nh-assistant-icon name=\"attach\" />\n </button>\n <span class=\"visually-hidden\" [id]=\"attachHintId\">{{ 'nh-assistant.composer.attach-hint' | translate: uploadParams() }}</span>\n <input\n #fileInput\n class=\"visually-hidden\"\n type=\"file\"\n multiple\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [accept]=\"accept()\"\n (change)=\"onFilesChosen($event)\" />\n }\n <div class=\"prompt-controls\">\n <ng-content select=\"[nhAssistantComposerControls]\" />\n </div>\n <div class=\"actions\">\n @if (busy() && canStop()) {\n <button\n class=\"stop\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.stop' | translate\"\n [attr.title]=\"'nh-assistant.composer.stop' | translate\"\n (click)=\"cancel.emit()\">\n <nh-assistant-icon name=\"stop\" />\n </button>\n }\n @if (!busy() || !canStop() || queueWhileBusy()) {\n <button\n class=\"send\"\n type=\"submit\"\n [disabled]=\"!canSend()\"\n [attr.aria-label]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\"\n [attr.title]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\">\n <nh-assistant-icon name=\"send\" />\n </button>\n }\n </div>\n </div>\n</form>\n\n@if (status() === 'waiting-for-approval') {\n <p class=\"composer-status\" role=\"status\" aria-live=\"polite\">\n @if (statusActor(); as name) {\n {{ 'nh-assistant.composer.status.waiting-for-approval-by' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.composer.status.waiting-for-approval' | translate }}\n }\n </p>\n} @else if (status() === 'waiting-for-answer') {\n <p class=\"composer-status\" role=\"status\" aria-live=\"polite\">\n @if (statusActor(); as name) {\n {{ 'nh-assistant.composer.status.waiting-for-answer-by' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.composer.status.waiting-for-answer' | translate }}\n }\n </p>\n}\n\n<p class=\"hint\" [id]=\"hintId\">\n @if (tooLong()) {\n <span class=\"error\">{{ 'nh-assistant.composer.too-long' | translate }}</span>\n } @else if (uploading()) {\n <span>{{ 'nh-assistant.composer.uploading-hint' | translate }}</span>\n } @else {\n <span>{{ (busy() && queueWhileBusy() ? 'nh-assistant.queue.hint' : 'nh-assistant.composer.hint') | translate }}</span>\n }\n @if (showCounter()) {\n <span class=\"counter\" [class.error]=\"tooLong()\">\n {{ 'nh-assistant.composer.characters' | translate: { count: length(), max: maxLength() } }}\n </span>\n }\n</p>\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}.composer{display:flex;flex-direction:column;gap:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:8px 8px 8px 14px;background:var(--nha-surface);box-shadow:0 2px 6px color-mix(in srgb,var(--nha-text) 4%,transparent)}.composer:focus-within{border-color:var(--nha-focus);box-shadow:0 0 0 2px color-mix(in srgb,var(--nha-focus) 16%,transparent)}textarea{width:100%;min-width:0;min-height:44px;max-height:180px;border:0;padding:6px 0;color:var(--nha-text);background:transparent;font:inherit;font-size:14px;line-height:1.45;resize:vertical;outline:none}textarea::placeholder{color:var(--nha-text-muted);opacity:1}textarea:disabled{cursor:not-allowed}.prompt-bar{display:flex;align-items:center;gap:8px;min-width:0}.prompt-controls{flex:1;min-width:0}.actions{display:flex;flex-shrink:0;gap:6px}.send,.stop{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:40px;height:40px}.send:focus-visible,.stop:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.send:hover:not(:disabled),.stop:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.send:disabled,.stop:disabled{cursor:not-allowed;opacity:.5}.send:not(:disabled){color:var(--nha-accent-contrast);background:var(--nha-accent)}.send:not(:disabled):hover{color:var(--nha-accent-contrast);background:var(--nha-accent);filter:brightness(1.12)}.stop{color:var(--nha-danger);border-color:var(--nha-danger)}.attach{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;flex-shrink:0;width:40px;height:40px}.attach:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attach:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attach:disabled{cursor:not-allowed;opacity:.5}.attachments{display:flex;flex-wrap:wrap;gap:6px;min-width:0;margin:0;padding:0;list-style:none}.attachment{display:flex;align-items:center;gap:8px;min-width:0;max-width:100%;flex:0 1 240px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 4px 4px 10px;background:var(--nha-background)}.attachment[data-state=failed]{flex-basis:100%;border-color:var(--nha-danger);background:var(--nha-danger-soft)}.attachment-icon{flex-shrink:0;color:var(--nha-text-muted)}[data-state=failed] .attachment-icon{color:var(--nha-danger)}.attachment-body{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.attachment-name{overflow:hidden;font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.attachment-meta,.attachment-error{font-size:11px;color:var(--nha-text-muted);overflow-wrap:anywhere}.attachment-error{color:var(--nha-danger)}.attachment-progress{width:100%;height:4px;accent-color:var(--nha-accent)}.attachment-remove{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;flex-shrink:0;width:32px;height:32px}.attachment-remove:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attachment-remove:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attachment-remove:disabled{cursor:not-allowed;opacity:.5}.hint,.composer-status{display:flex;justify-content:space-between;gap:8px;margin:6px 2px 0;color:var(--nha-text-muted);font-size:11px}.composer-status{margin-bottom:0}.counter{flex:none;font-variant-numeric:tabular-nums}.error{color:var(--nha-danger)}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10528
11968
|
}
|
|
10529
11969
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantComposerComponent, decorators: [{
|
|
10530
11970
|
type: Component,
|
|
10531
|
-
args: [{ selector: 'nh-assistant-composer', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent, NhAssistantTranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"composer\" (submit)=\"onSubmit($event)\">\n <label class=\"visually-hidden\" [for]=\"inputId\">{{ 'nh-assistant.composer.label' | translate }}</label>\n <textarea\n #textarea\n data-nh-assistant-autofocus\n rows=\"2\"\n [id]=\"inputId\"\n [value]=\"text()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"'nh-assistant.composer.placeholder' | translate\"\n [attr.aria-describedby]=\"hintId\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n @if (attachments().length > 0) {\n <ul class=\"attachments\" [id]=\"attachmentsId\" [attr.aria-label]=\"'nh-assistant.composer.attachments' | translate\">\n @for (attachment of attachments(); track attachment.id) {\n <li class=\"attachment\" [attr.data-state]=\"attachment.state\">\n <nh-assistant-icon class=\"attachment-icon\" [name]=\"attachment.state === 'failed' ? 'warning' : 'file'\" />\n <div class=\"attachment-body\">\n <span class=\"attachment-name\" [attr.title]=\"attachment.name\">{{ attachment.name }}</span>\n @switch (attachment.state) {\n @case ('uploading') {\n <progress\n class=\"attachment-progress\"\n max=\"100\"\n [value]=\"percent(attachment)\"\n [attr.aria-label]=\"'nh-assistant.composer.uploading' | translate: { name: attachment.name }\"></progress>\n }\n @case ('failed') {\n <span class=\"attachment-error\" role=\"alert\">\n {{ errorKeys(attachment) | nhAssistantTranslate: (attachment.error?.code ?? '') : uploadParams() }}\n </span>\n }\n @default {\n <span class=\"attachment-meta\">{{ size(attachment.size) }}</span>\n }\n }\n </div>\n <button\n class=\"attachment-remove\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n [attr.title]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n (click)=\"remove(attachment)\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </li>\n }\n </ul>\n }\n\n <div class=\"prompt-bar\">\n @if (uploads()) {\n <button\n #attachButton\n class=\"attach\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.composer.attach' | translate\"\n [attr.title]=\"'nh-assistant.composer.attach-hint' | translate: uploadParams()\"\n [attr.aria-describedby]=\"attachHintId\"\n (click)=\"fileInput.click()\">\n <nh-assistant-icon name=\"attach\" />\n </button>\n <span class=\"visually-hidden\" [id]=\"attachHintId\">{{ 'nh-assistant.composer.attach-hint' | translate: uploadParams() }}</span>\n <input\n #fileInput\n class=\"visually-hidden\"\n type=\"file\"\n multiple\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [accept]=\"accept()\"\n (change)=\"onFilesChosen($event)\" />\n }\n <div class=\"prompt-controls\">\n <ng-content select=\"[nhAssistantComposerControls]\" />\n </div>\n <div class=\"actions\">\n @if (busy() && canStop()) {\n <button\n class=\"stop\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.stop' | translate\"\n [attr.title]=\"'nh-assistant.composer.stop' | translate\"\n (click)=\"cancel.emit()\">\n <nh-assistant-icon name=\"stop\" />\n </button>\n }\n @if (!busy() || !canStop() || queueWhileBusy()) {\n <button\n class=\"send\"\n type=\"submit\"\n [disabled]=\"!canSend()\"\n [attr.aria-label]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\"\n [attr.title]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\">\n <nh-assistant-icon name=\"send\" />\n </button>\n }\n </div>\n </div>\n</form>\n\n@if (status() === 'waiting-for-approval') {\n <p class=\"composer-status\" role=\"status\" aria-live=\"polite\">\n @if (statusActor(); as name) {\n {{ 'nh-assistant.composer.status.waiting-for-approval-by' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.composer.status.waiting-for-approval' | translate }}\n }\n </p>\n}\n\n<p class=\"hint\" [id]=\"hintId\">\n @if (tooLong()) {\n <span class=\"error\">{{ 'nh-assistant.composer.too-long' | translate }}</span>\n } @else if (uploading()) {\n <span>{{ 'nh-assistant.composer.uploading-hint' | translate }}</span>\n } @else {\n <span>{{ (busy() && queueWhileBusy() ? 'nh-assistant.queue.hint' : 'nh-assistant.composer.hint') | translate }}</span>\n }\n @if (showCounter()) {\n <span class=\"counter\" [class.error]=\"tooLong()\">\n {{ 'nh-assistant.composer.characters' | translate: { count: length(), max: maxLength() } }}\n </span>\n }\n</p>\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}.composer{display:flex;flex-direction:column;gap:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:8px 8px 8px 14px;background:var(--nha-surface);box-shadow:0 2px 6px color-mix(in srgb,var(--nha-text) 4%,transparent)}.composer:focus-within{border-color:var(--nha-focus);box-shadow:0 0 0 2px color-mix(in srgb,var(--nha-focus) 16%,transparent)}textarea{width:100%;min-width:0;min-height:44px;max-height:180px;border:0;padding:6px 0;color:var(--nha-text);background:transparent;font:inherit;font-size:14px;line-height:1.45;resize:vertical;outline:none}textarea::placeholder{color:var(--nha-text-muted);opacity:1}textarea:disabled{cursor:not-allowed}.prompt-bar{display:flex;align-items:center;gap:8px;min-width:0}.prompt-controls{flex:1;min-width:0}.actions{display:flex;flex-shrink:0;gap:6px}.send,.stop{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:40px;height:40px}.send:focus-visible,.stop:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.send:hover:not(:disabled),.stop:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.send:disabled,.stop:disabled{cursor:not-allowed;opacity:.5}.send:not(:disabled){color:var(--nha-accent-contrast);background:var(--nha-accent)}.send:not(:disabled):hover{color:var(--nha-accent-contrast);background:var(--nha-accent);filter:brightness(1.12)}.stop{color:var(--nha-danger);border-color:var(--nha-danger)}.attach{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;flex-shrink:0;width:40px;height:40px}.attach:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attach:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attach:disabled{cursor:not-allowed;opacity:.5}.attachments{display:flex;flex-wrap:wrap;gap:6px;min-width:0;margin:0;padding:0;list-style:none}.attachment{display:flex;align-items:center;gap:8px;min-width:0;max-width:100%;flex:0 1 240px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 4px 4px 10px;background:var(--nha-background)}.attachment[data-state=failed]{flex-basis:100%;border-color:var(--nha-danger);background:var(--nha-danger-soft)}.attachment-icon{flex-shrink:0;color:var(--nha-text-muted)}[data-state=failed] .attachment-icon{color:var(--nha-danger)}.attachment-body{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.attachment-name{overflow:hidden;font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.attachment-meta,.attachment-error{font-size:11px;color:var(--nha-text-muted);overflow-wrap:anywhere}.attachment-error{color:var(--nha-danger)}.attachment-progress{width:100%;height:4px;accent-color:var(--nha-accent)}.attachment-remove{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;flex-shrink:0;width:32px;height:32px}.attachment-remove:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attachment-remove:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attachment-remove:disabled{cursor:not-allowed;opacity:.5}.hint,.composer-status{display:flex;justify-content:space-between;gap:8px;margin:6px 2px 0;color:var(--nha-text-muted);font-size:11px}.composer-status{margin-bottom:0}.counter{flex:none;font-variant-numeric:tabular-nums}.error{color:var(--nha-danger)}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
11971
|
+
args: [{ selector: 'nh-assistant-composer', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent, NhAssistantTranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"composer\" (submit)=\"onSubmit($event)\">\n <label class=\"visually-hidden\" [for]=\"inputId\">{{ 'nh-assistant.composer.label' | translate }}</label>\n <textarea\n #textarea\n data-nh-assistant-autofocus\n rows=\"2\"\n [id]=\"inputId\"\n [value]=\"text()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"'nh-assistant.composer.placeholder' | translate\"\n [attr.aria-describedby]=\"hintId\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n\n @if (attachments().length > 0) {\n <ul class=\"attachments\" [id]=\"attachmentsId\" [attr.aria-label]=\"'nh-assistant.composer.attachments' | translate\">\n @for (attachment of attachments(); track attachment.id) {\n <li class=\"attachment\" [attr.data-state]=\"attachment.state\">\n <nh-assistant-icon class=\"attachment-icon\" [name]=\"attachment.state === 'failed' ? 'warning' : 'file'\" />\n <div class=\"attachment-body\">\n <span class=\"attachment-name\" [attr.title]=\"attachment.name\">{{ attachment.name }}</span>\n @switch (attachment.state) {\n @case ('uploading') {\n <progress\n class=\"attachment-progress\"\n max=\"100\"\n [value]=\"percent(attachment)\"\n [attr.aria-label]=\"'nh-assistant.composer.uploading' | translate: { name: attachment.name }\"></progress>\n }\n @case ('failed') {\n <span class=\"attachment-error\" role=\"alert\">\n {{ errorKeys(attachment) | nhAssistantTranslate: (attachment.error?.code ?? '') : uploadParams() }}\n </span>\n }\n @default {\n <span class=\"attachment-meta\">{{ size(attachment.size) }}</span>\n }\n }\n </div>\n <button\n class=\"attachment-remove\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n [attr.title]=\"'nh-assistant.composer.remove-attachment' | translate: { name: attachment.name }\"\n (click)=\"remove(attachment)\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </li>\n }\n </ul>\n }\n\n <div class=\"prompt-bar\">\n @if (uploads()) {\n <button\n #attachButton\n class=\"attach\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.composer.attach' | translate\"\n [attr.title]=\"'nh-assistant.composer.attach-hint' | translate: uploadParams()\"\n [attr.aria-describedby]=\"attachHintId\"\n (click)=\"fileInput.click()\">\n <nh-assistant-icon name=\"attach\" />\n </button>\n <span class=\"visually-hidden\" [id]=\"attachHintId\">{{ 'nh-assistant.composer.attach-hint' | translate: uploadParams() }}</span>\n <input\n #fileInput\n class=\"visually-hidden\"\n type=\"file\"\n multiple\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [accept]=\"accept()\"\n (change)=\"onFilesChosen($event)\" />\n }\n <div class=\"prompt-controls\">\n <ng-content select=\"[nhAssistantComposerControls]\" />\n </div>\n <div class=\"actions\">\n @if (busy() && canStop()) {\n <button\n class=\"stop\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.composer.stop' | translate\"\n [attr.title]=\"'nh-assistant.composer.stop' | translate\"\n (click)=\"cancel.emit()\">\n <nh-assistant-icon name=\"stop\" />\n </button>\n }\n @if (!busy() || !canStop() || queueWhileBusy()) {\n <button\n class=\"send\"\n type=\"submit\"\n [disabled]=\"!canSend()\"\n [attr.aria-label]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\"\n [attr.title]=\"(busy() && queueWhileBusy() ? 'nh-assistant.queue.add' : 'nh-assistant.composer.send') | translate\">\n <nh-assistant-icon name=\"send\" />\n </button>\n }\n </div>\n </div>\n</form>\n\n@if (status() === 'waiting-for-approval') {\n <p class=\"composer-status\" role=\"status\" aria-live=\"polite\">\n @if (statusActor(); as name) {\n {{ 'nh-assistant.composer.status.waiting-for-approval-by' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.composer.status.waiting-for-approval' | translate }}\n }\n </p>\n} @else if (status() === 'waiting-for-answer') {\n <p class=\"composer-status\" role=\"status\" aria-live=\"polite\">\n @if (statusActor(); as name) {\n {{ 'nh-assistant.composer.status.waiting-for-answer-by' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.composer.status.waiting-for-answer' | translate }}\n }\n </p>\n}\n\n<p class=\"hint\" [id]=\"hintId\">\n @if (tooLong()) {\n <span class=\"error\">{{ 'nh-assistant.composer.too-long' | translate }}</span>\n } @else if (uploading()) {\n <span>{{ 'nh-assistant.composer.uploading-hint' | translate }}</span>\n } @else {\n <span>{{ (busy() && queueWhileBusy() ? 'nh-assistant.queue.hint' : 'nh-assistant.composer.hint') | translate }}</span>\n }\n @if (showCounter()) {\n <span class=\"counter\" [class.error]=\"tooLong()\">\n {{ 'nh-assistant.composer.characters' | translate: { count: length(), max: maxLength() } }}\n </span>\n }\n</p>\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}.composer{display:flex;flex-direction:column;gap:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:8px 8px 8px 14px;background:var(--nha-surface);box-shadow:0 2px 6px color-mix(in srgb,var(--nha-text) 4%,transparent)}.composer:focus-within{border-color:var(--nha-focus);box-shadow:0 0 0 2px color-mix(in srgb,var(--nha-focus) 16%,transparent)}textarea{width:100%;min-width:0;min-height:44px;max-height:180px;border:0;padding:6px 0;color:var(--nha-text);background:transparent;font:inherit;font-size:14px;line-height:1.45;resize:vertical;outline:none}textarea::placeholder{color:var(--nha-text-muted);opacity:1}textarea:disabled{cursor:not-allowed}.prompt-bar{display:flex;align-items:center;gap:8px;min-width:0}.prompt-controls{flex:1;min-width:0}.actions{display:flex;flex-shrink:0;gap:6px}.send,.stop{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:40px;height:40px}.send:focus-visible,.stop:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.send:hover:not(:disabled),.stop:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.send:disabled,.stop:disabled{cursor:not-allowed;opacity:.5}.send:not(:disabled){color:var(--nha-accent-contrast);background:var(--nha-accent)}.send:not(:disabled):hover{color:var(--nha-accent-contrast);background:var(--nha-accent);filter:brightness(1.12)}.stop{color:var(--nha-danger);border-color:var(--nha-danger)}.attach{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;flex-shrink:0;width:40px;height:40px}.attach:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attach:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attach:disabled{cursor:not-allowed;opacity:.5}.attachments{display:flex;flex-wrap:wrap;gap:6px;min-width:0;margin:0;padding:0;list-style:none}.attachment{display:flex;align-items:center;gap:8px;min-width:0;max-width:100%;flex:0 1 240px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 4px 4px 10px;background:var(--nha-background)}.attachment[data-state=failed]{flex-basis:100%;border-color:var(--nha-danger);background:var(--nha-danger-soft)}.attachment-icon{flex-shrink:0;color:var(--nha-text-muted)}[data-state=failed] .attachment-icon{color:var(--nha-danger)}.attachment-body{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.attachment-name{overflow:hidden;font-size:12px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.attachment-meta,.attachment-error{font-size:11px;color:var(--nha-text-muted);overflow-wrap:anywhere}.attachment-error{color:var(--nha-danger)}.attachment-progress{width:100%;height:4px;accent-color:var(--nha-accent)}.attachment-remove{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;flex-shrink:0;width:32px;height:32px}.attachment-remove:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.attachment-remove:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.attachment-remove:disabled{cursor:not-allowed;opacity:.5}.hint,.composer-status{display:flex;justify-content:space-between;gap:8px;margin:6px 2px 0;color:var(--nha-text-muted);font-size:11px}.composer-status{margin-bottom:0}.counter{flex:none;font-variant-numeric:tabular-nums}.error{color:var(--nha-danger)}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
10532
11972
|
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], sendDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendDisabled", required: false }] }], busy: [{ type: i0.Input, args: [{ isSignal: true, alias: "busy", required: false }] }], queueWhileBusy: [{ type: i0.Input, args: [{ isSignal: true, alias: "queueWhileBusy", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], statusActor: [{ type: i0.Input, args: [{ isSignal: true, alias: "statusActor", required: false }] }], canStop: [{ type: i0.Input, args: [{ isSignal: true, alias: "canStop", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], restore: [{ type: i0.Input, args: [{ isSignal: true, alias: "restore", required: false }] }], uploads: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploads", required: false }] }], attachments: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachments", required: false }] }], send: [{ type: i0.Output, args: ["send"] }], cancel: [{ type: i0.Output, args: ["cancel"] }], restored: [{ type: i0.Output, args: ["restored"] }], attach: [{ type: i0.Output, args: ["attach"] }], removeAttachment: [{ type: i0.Output, args: ["removeAttachment"] }], textarea: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }], attachButton: [{ type: i0.ViewChild, args: ['attachButton', { isSignal: true }] }], onFocusIn: [{
|
|
10533
11973
|
type: HostListener,
|
|
10534
11974
|
args: ['focusin']
|
|
@@ -10574,7 +12014,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10574
12014
|
args: [{ selector: 'nh-assistant-conversation-list', standalone: true, imports: [DatePipe, TranslatePipe, NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav class=\"list\" [attr.aria-label]=\"'nh-assistant.conversation-list.title' | translate\" [attr.aria-busy]=\"loading()\">\n <header class=\"header\">\n <h3>{{ 'nh-assistant.conversation-list.title' | translate }}</h3>\n @if (conversations().length > 0 && total() > conversations().length) {\n <span class=\"count\">{{ 'nh-assistant.conversation-list.count' | translate: { count: conversations().length, total: total() } }}</span>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"conversationCreate.emit()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n </header>\n\n @if (loading() && conversations().length === 0) {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.conversation-list.loading' | translate }}</p>\n } @else if (conversations().length === 0) {\n <p class=\"state\">{{ 'nh-assistant.conversation-list.empty' | translate }}</p>\n } @else {\n <ul>\n @for (conversation of conversations(); track conversation.id) {\n <li [class.active]=\"conversation.id === activeConversationId()\" [class.unread]=\"unread(conversation)\">\n <button\n class=\"item\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-current]=\"conversation.id === activeConversationId() ? 'true' : null\"\n (click)=\"conversationSelect.emit(conversation.id)\">\n <span class=\"title-row\">\n <span class=\"indicator\" [attr.data-state]=\"indicator(conversation)\" aria-hidden=\"true\"></span>\n <span class=\"title\">{{ conversation.title || ('nh-assistant.conversation-list.untitled' | translate) }}</span>\n @if ((conversation.participantCount ?? 0) > 0) {\n <nh-assistant-icon\n class=\"shared\"\n name=\"users\"\n [attr.title]=\"'nh-assistant.conversation-list.shared' | translate: { count: conversation.participantCount }\" />\n }\n </span>\n <span class=\"meta\">\n <span class=\"status\" [attr.data-status]=\"conversation.status\">{{ 'nh-assistant.conversation-list.status.' + conversation.status | translate }}</span>\n @if (unread(conversation)) {\n <span class=\"unread-label\">{{ 'nh-assistant.conversation-list.unread' | translate }}</span>\n }\n @if (conversation.role === 'participant') {\n <span>{{ 'nh-assistant.conversation-list.shared-with-you' | translate }}</span>\n }\n <time [attr.datetime]=\"conversation.updatedAt\">{{ conversation.updatedAt | date: 'short' }}</time>\n </span>\n </button>\n <button\n class=\"icon-button delete\"\n type=\"button\"\n [disabled]=\"disabled() || conversation.status === 'running'\"\n [attr.aria-label]=\"((conversation.role === 'participant' ? 'nh-assistant.conversation-list.leave' : 'nh-assistant.conversation-list.delete') | translate) + ': ' + (conversation.title || ('nh-assistant.conversation-list.untitled' | translate))\"\n [attr.title]=\"(conversation.role === 'participant' ? 'nh-assistant.conversation-list.leave' : 'nh-assistant.conversation-list.delete') | translate\"\n (click)=\"conversationDelete.emit(conversation.id)\">\n <nh-assistant-icon [name]=\"conversation.role === 'participant' ? 'leave' : 'trash'\" />\n </button>\n </li>\n }\n </ul>\n }\n</nav>\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)}.list{display:flex;flex:1;flex-direction:column;min-height:0}.header{display:flex;align-items:center;gap:8px;padding:12px 12px 8px 16px}h3{flex:1;margin:0;font-size:13px;font-weight:700}.count{color:var(--nha-text-muted);font-size:11px}.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}.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}.state{margin:0;padding:12px 16px;color:var(--nha-text-muted);font-size:13px}ul{flex:1;min-height:0;margin:0;overflow-y:auto;padding:0 8px 12px;list-style:none}li{display:flex;align-items:center;gap:4px;border-radius:var(--nha-radius-control)}li.active{background:var(--nha-surface-strong)}.item{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0;border:0;border-radius:var(--nha-radius-control);padding:8px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.item:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.item:hover:not(:disabled){background:var(--nha-surface-strong)}.item:disabled{cursor:not-allowed;opacity:.6}.title-row{display:flex;align-items:center;gap:6px;min-width:0}.title{overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}li.unread .title{font-weight:800}.shared{flex:none;color:var(--nha-text-muted);font-size:12px}.indicator{flex:none;width:8px;height:8px;border-radius:50%}.indicator:not([data-state]){display:none}.indicator[data-state=unread]{background:var(--nha-highlight)}.indicator[data-state=waiting]{background:var(--nha-warning)}.indicator[data-state=running]{width:10px;height:10px;border:2px solid color-mix(in srgb,var(--nha-highlight) 30%,transparent);border-top-color:var(--nha-highlight);animation:nh-assistant-spin .9s linear infinite}@media(prefers-reduced-motion:reduce){.indicator[data-state=running]{border-color:var(--nha-highlight);animation:none}}@keyframes nh-assistant-spin{to{transform:rotate(360deg)}}.unread-label{color:var(--nha-highlight);font-weight:700}.meta{display:flex;gap:8px;color:var(--nha-text-muted);font-size:11px}.status[data-status=waiting-for-approval]{color:var(--nha-warning);font-weight:700}.status[data-status=failed]{color:var(--nha-danger)}.delete{flex:none}\n"] }]
|
|
10575
12015
|
}], propDecorators: { conversations: [{ type: i0.Input, args: [{ isSignal: true, alias: "conversations", required: true }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], activeConversationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeConversationId", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], conversationSelect: [{ type: i0.Output, args: ["conversationSelect"] }], conversationDelete: [{ type: i0.Output, args: ["conversationDelete"] }], conversationCreate: [{ type: i0.Output, args: ["conversationCreate"] }] } });
|
|
10576
12016
|
|
|
10577
|
-
let nextId$
|
|
12017
|
+
let nextId$a = 0;
|
|
10578
12018
|
/**
|
|
10579
12019
|
* The caller's own MCP accounts: servers each person connects to with OAuth, with Connect,
|
|
10580
12020
|
* Connect again and Disconnect, and the consent to background use of servers that run with the
|
|
@@ -10586,7 +12026,7 @@ class NhAssistantMcpConnectionsComponent {
|
|
|
10586
12026
|
this.api = inject(NhAssistantApiService);
|
|
10587
12027
|
this.connector = inject(NhAssistantMcpConnectService);
|
|
10588
12028
|
this.store = inject(NhAssistantStore, { optional: true });
|
|
10589
|
-
this.id = `nh-assistant-mcp-connections-${nextId$
|
|
12029
|
+
this.id = `nh-assistant-mcp-connections-${nextId$a++}`;
|
|
10590
12030
|
this.connections = signal([], ...(ngDevMode ? [{ debugName: "connections" }] : []));
|
|
10591
12031
|
this.loadFailed = signal(false, ...(ngDevMode ? [{ debugName: "loadFailed" }] : []));
|
|
10592
12032
|
/** The server whose consent or connection is being changed. */
|
|
@@ -10699,7 +12139,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10699
12139
|
|
|
10700
12140
|
/** Maximum length of the user's own instructions. */
|
|
10701
12141
|
const NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS = 1_000;
|
|
10702
|
-
let nextId$
|
|
12142
|
+
let nextId$9 = 0;
|
|
10703
12143
|
/**
|
|
10704
12144
|
* The user's own assistant preferences: desktop notifications, background use of MCP servers
|
|
10705
12145
|
* with the user's own account, style, form of address, answer length and optional instructions.
|
|
@@ -10715,7 +12155,7 @@ class NhAssistantPreferencesComponent {
|
|
|
10715
12155
|
this.closed = output();
|
|
10716
12156
|
/** Emitted with the stored preferences after a successful save. */
|
|
10717
12157
|
this.saved = output();
|
|
10718
|
-
this.id = `nh-assistant-preferences-${nextId$
|
|
12158
|
+
this.id = `nh-assistant-preferences-${nextId$9++}`;
|
|
10719
12159
|
this.styles = ['default', 'direct', 'personal', 'detailed'];
|
|
10720
12160
|
this.addressForms = ['informal', 'formal'];
|
|
10721
12161
|
this.responseLengths = ['short', 'normal', 'long'];
|
|
@@ -10819,7 +12259,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10819
12259
|
args: [{ selector: 'nh-assistant-preferences', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent, NhAssistantMcpConnectionsComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"preferences\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading() || saving()\">\n <header class=\"header\">\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.preferences.title' | translate }}</h3>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.preferences.back' | translate\"\n [attr.title]=\"'nh-assistant.preferences.back' | translate\"\n (click)=\"closed.emit()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </header>\n\n @if (loading()) {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.preferences.loading' | translate }}</p>\n } @else if (loadFailed()) {\n <div class=\"state\" role=\"alert\">\n <p>{{ 'nh-assistant.preferences.load-failed' | translate }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">{{ 'nh-assistant.preferences.retry' | translate }}</button>\n </div>\n } @else {\n <form class=\"form\" (submit)=\"$event.preventDefault(); save()\">\n @if (push.state() !== 'unavailable') {\n <fieldset class=\"notifications\">\n <legend>{{ 'nh-assistant.preferences.notifications-label' | translate }}</legend>\n <label class=\"switch\">\n <input\n type=\"checkbox\"\n [checked]=\"push.settings()?.pushEnabled === true\"\n [disabled]=\"push.busy()\"\n [attr.aria-describedby]=\"id + '-notifications-hint'\"\n (change)=\"toggleNotifications($event)\" />\n <span>{{ 'nh-assistant.preferences.notifications' | translate }}</span>\n </label>\n <p class=\"hint\" [id]=\"id + '-notifications-hint'\">\n <span>{{ 'nh-assistant.preferences.notifications-state.' + push.state() | translate }}</span>\n </p>\n </fieldset>\n }\n\n <nh-assistant-mcp-connections />\n\n <p class=\"description\">{{ 'nh-assistant.preferences.description' | translate }}</p>\n\n <fieldset>\n <legend>{{ 'nh-assistant.preferences.style-label' | translate }}</legend>\n <div class=\"options styles\">\n @for (option of styles; track option) {\n <label class=\"option\" [class.selected]=\"style() === option\">\n <input type=\"radio\" [name]=\"id + '-style'\" [value]=\"option\" [checked]=\"style() === option\" (change)=\"choose(style, option)\" />\n <span>\n <strong>{{ 'nh-assistant.preferences.style.' + option | translate }}</strong>\n <small>{{ 'nh-assistant.preferences.style.' + option + '-description' | translate }}</small>\n </span>\n </label>\n }\n </div>\n </fieldset>\n\n <fieldset>\n <legend>{{ 'nh-assistant.preferences.address-form-label' | translate }}</legend>\n <div class=\"options segmented\">\n @for (option of addressForms; track option) {\n <label class=\"option\" [class.selected]=\"addressForm() === option\">\n <input type=\"radio\" [name]=\"id + '-address'\" [value]=\"option\" [checked]=\"addressForm() === option\" (change)=\"choose(addressForm, option)\" />\n <span><strong>{{ 'nh-assistant.preferences.address-form.' + option | translate }}</strong></span>\n </label>\n }\n </div>\n </fieldset>\n\n <fieldset>\n <legend>{{ 'nh-assistant.preferences.response-length-label' | translate }}</legend>\n <div class=\"options segmented\">\n @for (option of responseLengths; track option) {\n <label class=\"option\" [class.selected]=\"responseLength() === option\">\n <input type=\"radio\" [name]=\"id + '-length'\" [value]=\"option\" [checked]=\"responseLength() === option\" (change)=\"choose(responseLength, option)\" />\n <span><strong>{{ 'nh-assistant.preferences.response-length.' + option | translate }}</strong></span>\n </label>\n }\n </div>\n </fieldset>\n\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.preferences.custom-instructions-label' | translate }}</label>\n <textarea\n rows=\"4\"\n [id]=\"id + '-instructions'\"\n [value]=\"customInstructions()\"\n [attr.aria-describedby]=\"id + '-instructions-hint'\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"onInstructionsInput($event)\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n @if (tooLong()) {\n <span class=\"error-text\">{{ 'nh-assistant.preferences.too-long' | translate }}</span>\n } @else {\n <span>{{ 'nh-assistant.preferences.custom-instructions-hint' | translate }}</span>\n }\n <span class=\"counter\" [class.error-text]=\"tooLong()\">\n {{ 'nh-assistant.preferences.characters' | translate: { count: instructionsLength(), max: maxInstructions } }}\n </span>\n </p>\n </div>\n\n @if (error(); as error) {\n <p class=\"message error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n {{ errorKeys() | nhAssistantTranslate: error.code }}\n </p>\n }\n @if (savedMessage()) {\n <p class=\"message success\" role=\"status\">\n <nh-assistant-icon name=\"check\" />\n {{ 'nh-assistant.preferences.saved' | translate }}\n </p>\n }\n\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" (click)=\"closed.emit()\">{{ 'nh-assistant.preferences.back' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"!canSave()\">\n {{ (saving() ? 'nh-assistant.preferences.saving' : 'nh-assistant.preferences.save') | translate }}\n </button>\n </div>\n </form>\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:flex;flex-direction:column;min-height:0;color:var(--nha-text)}: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}.preferences{display:flex;flex:1;flex-direction:column;min-height:0}.header{display:flex;align-items:center;gap:8px;padding:12px 12px 8px 16px}h3{flex:1;margin:0;font-size:15px;font-weight:700}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;padding:12px 16px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.form{display:flex;flex:1;flex-direction:column;gap:18px;min-height:0;overflow-y:auto;padding:0 16px 16px}.description{margin:0;color:var(--nha-text-muted);font-size:13px}.options{display:grid;gap:8px}.styles{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.segmented{grid-template-columns:repeat(auto-fit,minmax(90px,1fr))}.option{position:relative;display:flex;align-items:flex-start;gap:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px;background:var(--nha-background);cursor:pointer}.option:hover{background:var(--nha-surface)}.option.selected{border-color:var(--nha-highlight);background:var(--nha-surface);box-shadow:inset 0 0 0 1px var(--nha-highlight)}.option:focus-within{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.option input{flex:none;margin:2px 0 0;accent-color:var(--nha-highlight)}.option span{display:flex;flex-direction:column;gap:2px;min-width:0}.option strong{font-size:13px}.option small{color:var(--nha-text-muted);font-size:12px}.switch{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:650;cursor:pointer}.switch input{width:16px;height:16px;margin:0;accent-color:var(--nha-highlight)}\n"] }]
|
|
10820
12260
|
}], ctorParameters: () => [], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], saved: [{ type: i0.Output, args: ["saved"] }] } });
|
|
10821
12261
|
|
|
10822
|
-
let nextId$
|
|
12262
|
+
let nextId$8 = 0;
|
|
10823
12263
|
const searchDelayMs$1 = 250;
|
|
10824
12264
|
/**
|
|
10825
12265
|
* Sharing of the open conversation. The owner creates, copies, renews or stops an invitation
|
|
@@ -10835,7 +12275,7 @@ class NhAssistantShareComponent {
|
|
|
10835
12275
|
this.closed = output();
|
|
10836
12276
|
/** Show the invitation link, participants, or both (the default for custom hosts). */
|
|
10837
12277
|
this.section = input('all', ...(ngDevMode ? [{ debugName: "section" }] : []));
|
|
10838
|
-
this.id = `nh-assistant-share-${nextId$
|
|
12278
|
+
this.id = `nh-assistant-share-${nextId$8++}`;
|
|
10839
12279
|
this.conversation = this.store.activeConversation;
|
|
10840
12280
|
this.isOwner = this.store.isOwner;
|
|
10841
12281
|
this.busy = signal(false, ...(ngDevMode ? [{ debugName: "busy" }] : []));
|
|
@@ -10944,13 +12384,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
10944
12384
|
args: [{ selector: 'nh-assistant-share', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"share\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"busy()\">\n <header class=\"header\">\n <h3 [id]=\"id + '-title'\">\n {{ (isOwner() && section() !== 'members' ? 'nh-assistant.share.title' : 'nh-assistant.share.members-title') | translate }}\n </h3>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.share.back' | translate\"\n [attr.title]=\"'nh-assistant.share.back' | translate\"\n (click)=\"closed.emit()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </header>\n\n @if (conversation(); as conversation) {\n <div class=\"content\">\n @if (isOwner()) {\n <p class=\"description\">{{ 'nh-assistant.share.description' | translate }}</p>\n\n @if (section() !== 'members' || !directory()) {\n <section class=\"block\" [attr.aria-labelledby]=\"id + '-link'\">\n <h4 [id]=\"id + '-link'\">{{ 'nh-assistant.share.link-title' | translate }}</h4>\n @if (link(); as link) {\n <div class=\"link-row\">\n <label class=\"visually-hidden\" [for]=\"id + '-link-input'\">{{ 'nh-assistant.share.link-label' | translate }}</label>\n <input #linkInput type=\"text\" readonly [id]=\"id + '-link-input'\" [value]=\"link\" (focus)=\"linkInput.select()\" />\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.share.copy' | translate\"\n [attr.title]=\"'nh-assistant.share.copy' | translate\"\n (click)=\"copy(linkInput)\">\n <nh-assistant-icon name=\"copy\" />\n </button>\n </div>\n @if (copied()) {\n <p class=\"message success\" role=\"status\">\n <nh-assistant-icon name=\"check\" />\n {{ 'nh-assistant.share.copied' | translate }}\n </p>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"revokeLink()\">\n {{ 'nh-assistant.share.revoke' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"createLink()\">\n {{ 'nh-assistant.share.renew' | translate }}\n </button>\n </div>\n <p class=\"hint\">{{ 'nh-assistant.share.link-hint' | translate }}</p>\n } @else {\n <button class=\"primary\" type=\"button\" [disabled]=\"busy() || full()\" (click)=\"createLink()\">\n <nh-assistant-icon name=\"link\" />\n {{ 'nh-assistant.share.create' | translate }}\n </button>\n }\n </section>\n }\n\n @if (directory() && section() !== 'link') {\n <section class=\"block\" [attr.aria-labelledby]=\"id + '-invite'\">\n <h4 [id]=\"id + '-invite'\">{{ 'nh-assistant.share.invite-title' | translate }}</h4>\n <label class=\"visually-hidden\" [for]=\"id + '-search'\">{{ 'nh-assistant.share.search-label' | translate }}</label>\n <input\n type=\"search\"\n autocomplete=\"off\"\n [id]=\"id + '-search'\"\n [value]=\"query()\"\n [disabled]=\"full()\"\n [attr.placeholder]=\"'nh-assistant.share.search-placeholder' | translate\"\n (input)=\"onSearch($event)\" />\n @if (searching()) {\n <p class=\"hint\" role=\"status\">{{ 'nh-assistant.share.searching' | translate }}</p>\n } @else if (query().trim().length >= 2 && candidates().length === 0 && !invited()) {\n <p class=\"hint\">{{ 'nh-assistant.share.no-results' | translate }}</p>\n }\n @if (candidates().length > 0) {\n <ul class=\"people\">\n @for (entry of candidates(); track entry.actorId) {\n <li>\n <span class=\"person\">\n <strong>{{ entry.displayName }}</strong>\n @if (entry.detail) {\n <small>{{ entry.detail }}</small>\n }\n </span>\n <button class=\"secondary small\" type=\"button\" [disabled]=\"busy() || full()\" (click)=\"invite(entry)\">\n {{ 'nh-assistant.share.invite' | translate }}\n </button>\n </li>\n }\n </ul>\n }\n @if (invited(); as name) {\n <p class=\"message success\" role=\"status\">\n <nh-assistant-icon name=\"check\" />\n {{ 'nh-assistant.share.invited' | translate: { name } }}\n </p>\n }\n </section>\n }\n }\n\n @if (section() !== 'link') {\n <section class=\"block\" [attr.aria-labelledby]=\"id + '-members'\">\n <h4 [id]=\"id + '-members'\">\n {{ 'nh-assistant.share.members' | translate }}\n @if (maxParticipants() !== null && isOwner()) {\n <span class=\"count\">{{ 'nh-assistant.share.count' | translate: { count: participants().length, max: maxParticipants() } }}</span>\n }\n </h4>\n @if (store.members().length === 0) {\n <p class=\"hint\">{{ 'nh-assistant.share.not-shared' | translate }}</p>\n } @else {\n <ul class=\"people\">\n @for (member of store.members(); track member.actorId) {\n <li>\n <span class=\"person\">\n <strong>\n {{ member.displayName || ('nh-assistant.share.unnamed' | translate) }}\n @if (isCurrentUser(member)) {\n <small class=\"you\">{{ 'nh-assistant.share.you' | translate }}</small>\n }\n </strong>\n <small>{{ 'nh-assistant.share.role.' + member.role | translate }}</small>\n </span>\n @if (isOwner() && member.role === 'participant') {\n <button\n class=\"icon-button\"\n type=\"button\"\n [disabled]=\"busy()\"\n [attr.aria-label]=\"'nh-assistant.share.remove' | translate: { name: member.displayName || ('nh-assistant.share.unnamed' | translate) }\"\n [attr.title]=\"'nh-assistant.share.remove' | translate: { name: member.displayName || ('nh-assistant.share.unnamed' | translate) }\"\n (click)=\"remove(member)\">\n <nh-assistant-icon name=\"trash\" />\n </button>\n }\n </li>\n }\n </ul>\n }\n </section>\n }\n\n @if (!isOwner()) {\n <div class=\"actions\">\n <button class=\"secondary danger\" type=\"button\" [disabled]=\"busy() || conversation.status === 'running'\" (click)=\"leave()\">\n <nh-assistant-icon name=\"leave\" />\n {{ 'nh-assistant.share.leave' | translate }}\n </button>\n </div>\n }\n </div>\n } @else {\n <p class=\"state\">{{ 'nh-assistant.share.no-conversation' | translate }}</p>\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}: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}.share{display:flex;flex:1;flex-direction:column;min-height:0}.header{display:flex;align-items:center;gap:8px;padding:12px 12px 8px 16px}h3{flex:1;margin:0;font-size:15px;font-weight:700}.content{display:flex;flex:1;flex-direction:column;gap:18px;min-height:0;overflow-y:auto;padding:0 16px 16px}.description,.state{margin:0;color:var(--nha-text-muted);font-size:13px}.state{padding:12px 16px}.block{display:flex;flex-direction:column;gap:8px}h4{display:flex;align-items:baseline;gap:8px;margin:0;font-size:12px;font-weight:700}.count{color:var(--nha-text-muted);font-size:11px;font-weight:400}.link-row{display:flex;align-items:center;gap:4px}.link-row input{font-family:var(--nha-mono);font-size:12px}.actions{justify-content:flex-start}.people{display:flex;flex-direction:column;gap:4px;margin:0;padding:0;list-style:none}.people li{display:flex;align-items:center;gap:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 6px 6px 10px}.person{display:flex;flex:1;flex-direction:column;min-width:0}.person strong{overflow:hidden;font-size:13px;text-overflow:ellipsis;white-space:nowrap}.person small{color:var(--nha-text-muted);font-size:11px}.you{margin-left:4px;font-weight:400}.small{min-height:30px;padding:4px 10px;font-size:12px}\n"] }]
|
|
10945
12385
|
}], ctorParameters: () => [], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], section: [{ type: i0.Input, args: [{ isSignal: true, alias: "section", required: false }] }] } });
|
|
10946
12386
|
|
|
10947
|
-
|
|
12387
|
+
/** The tags model text may render as; shared with `nh-assistant-document`. */
|
|
12388
|
+
const nhAssistantMarkdownTags = [
|
|
10948
12389
|
'p', 'br', 'strong', 'em', 'del', 'code', 'pre', 'blockquote', 'ul', 'ol', 'li', 'a',
|
|
10949
12390
|
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'table', 'thead', 'tbody', 'tr', 'th', 'td'
|
|
10950
12391
|
];
|
|
10951
|
-
const
|
|
12392
|
+
const nhAssistantMarkdownAttributes = ['href', 'title', 'start', 'align'];
|
|
10952
12393
|
const allowedUris = /^(?:https?:|mailto:|\/(?!\/)|#)/i;
|
|
10953
|
-
function
|
|
12394
|
+
function nhAssistantEscapeHtml(text) {
|
|
10954
12395
|
return text
|
|
10955
12396
|
.replace(/&/g, '&')
|
|
10956
12397
|
.replace(/</g, '<')
|
|
@@ -10972,10 +12413,10 @@ class NhAssistantMarkdownRenderer {
|
|
|
10972
12413
|
async: false,
|
|
10973
12414
|
renderer: {
|
|
10974
12415
|
html(token) {
|
|
10975
|
-
return
|
|
12416
|
+
return nhAssistantEscapeHtml(token.text);
|
|
10976
12417
|
},
|
|
10977
12418
|
image(token) {
|
|
10978
|
-
return
|
|
12419
|
+
return nhAssistantEscapeHtml(token.text);
|
|
10979
12420
|
}
|
|
10980
12421
|
}
|
|
10981
12422
|
});
|
|
@@ -10984,12 +12425,12 @@ class NhAssistantMarkdownRenderer {
|
|
|
10984
12425
|
render(text) {
|
|
10985
12426
|
const purifier = this.getPurifier();
|
|
10986
12427
|
if (!purifier) {
|
|
10987
|
-
return `<p>${
|
|
12428
|
+
return `<p>${nhAssistantEscapeHtml(text)}</p>`;
|
|
10988
12429
|
}
|
|
10989
12430
|
const html = this.marked.parse(text, { async: false });
|
|
10990
12431
|
return purifier.sanitize(html, {
|
|
10991
|
-
ALLOWED_TAGS:
|
|
10992
|
-
ALLOWED_ATTR:
|
|
12432
|
+
ALLOWED_TAGS: [...nhAssistantMarkdownTags],
|
|
12433
|
+
ALLOWED_ATTR: [...nhAssistantMarkdownAttributes],
|
|
10993
12434
|
ALLOWED_URI_REGEXP: allowedUris,
|
|
10994
12435
|
ALLOW_DATA_ATTR: false,
|
|
10995
12436
|
ALLOW_ARIA_ATTR: false
|
|
@@ -11225,6 +12666,9 @@ function groupNhAssistantParts(parts) {
|
|
|
11225
12666
|
if (part.type === 'approval') {
|
|
11226
12667
|
groups.push({ kind: 'approval', key: `approval:${part.approvalId}`, part });
|
|
11227
12668
|
}
|
|
12669
|
+
else if (part.type === 'question') {
|
|
12670
|
+
groups.push({ kind: 'question', key: `question:${part.questionId}`, part });
|
|
12671
|
+
}
|
|
11228
12672
|
else if (part.type === 'connection-required') {
|
|
11229
12673
|
groups.push({ kind: 'connection', key: `connection:${part.serverId}:${index}`, part });
|
|
11230
12674
|
}
|
|
@@ -11248,7 +12692,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
11248
12692
|
}] });
|
|
11249
12693
|
|
|
11250
12694
|
const notAcceptedCode = 'assistant-feedback-not-accepted';
|
|
11251
|
-
let nextId$
|
|
12695
|
+
let nextId$7 = 0;
|
|
11252
12696
|
/**
|
|
11253
12697
|
* Asks, after a rejection, what was wrong with one or more agent proposals: a category from a fixed
|
|
11254
12698
|
* set and an optional text. It is optional and never blocks the decision; people skip it with one
|
|
@@ -11271,7 +12715,7 @@ class NhAssistantProposalFeedbackComponent {
|
|
|
11271
12715
|
this.saved = output();
|
|
11272
12716
|
/** Emits when the person skips the question. */
|
|
11273
12717
|
this.dismissed = output();
|
|
11274
|
-
this.id = `nh-assistant-proposal-feedback-${nextId$
|
|
12718
|
+
this.id = `nh-assistant-proposal-feedback-${nextId$7++}`;
|
|
11275
12719
|
this.categories = NH_ASSISTANT_FEEDBACK_CATEGORIES;
|
|
11276
12720
|
this.maxText = NH_ASSISTANT_MAX_FEEDBACK_TEXT;
|
|
11277
12721
|
/** A new question when the host passes other proposals or other initial feedback. */
|
|
@@ -11360,7 +12804,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
11360
12804
|
args: [{ selector: 'nh-assistant-proposal-feedback', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (done()) {\n <div class=\"feedback done\" role=\"status\" tabindex=\"-1\" #thanks>\n <p class=\"thanks\"><nh-assistant-icon name=\"check\" />{{ 'nh-assistant.proposal-feedback.thanks' | translate }}</p>\n @if (partial(); as stored) {\n <p class=\"scope\">{{ 'nh-assistant.proposal-feedback.partial' | translate: { stored: stored.stored, total: stored.total } }}</p>\n }\n </div>\n} @else {\n <form class=\"feedback\" [attr.aria-busy]=\"busy()\" (submit)=\"$event.preventDefault(); send()\">\n <fieldset class=\"categories\" [disabled]=\"busy()\">\n <legend>{{ 'nh-assistant.proposal-feedback.legend' | translate }}</legend>\n @if (count() > 1) {\n <p class=\"scope\">{{ 'nh-assistant.proposal-feedback.bulk' | translate: { count: count() } }}</p>\n }\n <div class=\"chips\">\n @for (option of categories; track option) {\n <label class=\"chip\" [class.selected]=\"category() === option\">\n <input\n type=\"radio\"\n [name]=\"id + '-category'\"\n [value]=\"option\"\n [checked]=\"category() === option\"\n [attr.aria-describedby]=\"id + '-hint-' + option\"\n (change)=\"choose(option)\" />\n @if (category() === option) {\n <nh-assistant-icon name=\"check\" />\n }\n <span>{{ 'nh-assistant.proposal-feedback.categories.' + option | translate }}</span>\n </label>\n }\n </div>\n @for (option of categories; track option) {\n <span class=\"visually-hidden\" [id]=\"id + '-hint-' + option\">{{ 'nh-assistant.proposal-feedback.hints.' + option | translate }}</span>\n }\n @if (category(); as selected) {\n <p class=\"selected-hint\" aria-hidden=\"true\">{{ 'nh-assistant.proposal-feedback.hints.' + selected | translate }}</p>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-text'\">{{ 'nh-assistant.proposal-feedback.text-label' | translate }}</label>\n <textarea\n rows=\"2\"\n [id]=\"id + '-text'\"\n [attr.maxlength]=\"maxText\"\n [value]=\"text()\"\n [attr.aria-describedby]=\"id + '-text-hint'\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"onText($event)\"></textarea>\n <p class=\"hint\" [id]=\"id + '-text-hint'\">\n <span>{{ 'nh-assistant.proposal-feedback.text-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"tooLong()\">\n {{ 'nh-assistant.proposal-feedback.characters' | translate: { count: textLength(), max: maxText } }}\n </span>\n </p>\n </div>\n </fieldset>\n\n @if (error(); as failure) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n\n <div class=\"actions\">\n <button class=\"text-button\" type=\"button\" (click)=\"dismiss()\">\n {{ (initial() ? 'nh-assistant.proposal-feedback.cancel' : 'nh-assistant.proposal-feedback.skip') | translate }}\n </button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"!canSend()\">\n {{ (busy() ? 'nh-assistant.proposal-feedback.sending' : 'nh-assistant.proposal-feedback.send') | translate }}\n </button>\n </div>\n </form>\n}\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);font-size:13px}: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}.feedback{display:flex;flex-direction:column;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;background:var(--nha-surface)}.feedback.done{gap:4px}.feedback.done:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.categories{display:flex;flex-direction:column;gap:8px}.chips{display:flex;flex-wrap:wrap;gap:6px}.chip{position:relative;display:inline-flex;align-items:center;gap:4px;min-height:30px;max-width:100%;border:1px solid var(--nha-border);border-radius:999px;padding:4px 12px;color:var(--nha-text);background:var(--nha-background);font-size:12px;font-weight:650;overflow-wrap:anywhere;cursor:pointer}.chip:hover{background:var(--nha-surface-strong)}.chip.selected{border-color:var(--nha-highlight);box-shadow:inset 0 0 0 1px var(--nha-highlight)}.chip:has(input:focus-visible){outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip input{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.chip nh-assistant-icon{color:var(--nha-highlight)}fieldset:disabled .chip{cursor:not-allowed;opacity:.6}.scope,.selected-hint{margin:0;color:var(--nha-text-muted);font-size:12px}.thanks{display:flex;align-items:center;gap:6px;margin:0;font-size:13px}.thanks nh-assistant-icon{color:var(--nha-success)}textarea{min-height:56px}.text-button{min-height:36px;border:0;border-radius:var(--nha-radius-control);padding:6px 10px;color:var(--nha-text-muted);background:transparent;font:inherit;font-size:13px;font-weight:650;cursor:pointer}.text-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.text-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.text-button:disabled{cursor:not-allowed;opacity:.55}\n"] }]
|
|
11361
12805
|
}], ctorParameters: () => [], propDecorators: { thanks: [{ type: i0.ViewChild, args: ['thanks', { isSignal: true }] }], approvalIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "approvalIds", required: true }] }], initial: [{ type: i0.Input, args: [{ isSignal: true, alias: "initial", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
|
|
11362
12806
|
|
|
11363
|
-
let nextId$
|
|
12807
|
+
let nextId$6 = 0;
|
|
11364
12808
|
/** Formats remaining milliseconds as `m:ss`, or `h:mm:ss` above one hour. */
|
|
11365
12809
|
function formatNhAssistantCountdown(milliseconds) {
|
|
11366
12810
|
const totalSeconds = Math.max(0, Math.ceil(milliseconds / 1000));
|
|
@@ -11381,7 +12825,9 @@ function formatNhAssistantCountdown(milliseconds) {
|
|
|
11381
12825
|
* another agent the assistant consulted (`consultation`) names that agent and the subject, offers the
|
|
11382
12826
|
* agent's answer and says that approving runs it with the user's own rights; with a
|
|
11383
12827
|
* `consultation.leaveRoute` a third action leaves it for the subject's approvers (`leave`), after which
|
|
11384
|
-
* the card says that it waits for them.
|
|
12828
|
+
* the card says that it waits for them. A proposal the user approved in their chat whose hand-off to the
|
|
12829
|
+
* application has an unknown outcome (`canResolve`) offers to hand it to the application again or to mark
|
|
12830
|
+
* it resolved (`resolve`).
|
|
11385
12831
|
*/
|
|
11386
12832
|
class NhAssistantApprovalCardComponent {
|
|
11387
12833
|
constructor() {
|
|
@@ -11409,6 +12855,8 @@ class NhAssistantApprovalCardComponent {
|
|
|
11409
12855
|
*/
|
|
11410
12856
|
this.canGiveFeedback = input(false, ...(ngDevMode ? [{ debugName: "canGiveFeedback" }] : []));
|
|
11411
12857
|
this.decide = output();
|
|
12858
|
+
/** How the user resolves an uncertain execution they approved in this chat (`canResolve`). */
|
|
12859
|
+
this.resolve = output();
|
|
11412
12860
|
this.now = signal(Date.now(), ...(ngDevMode ? [{ debugName: "now" }] : []));
|
|
11413
12861
|
this.submitted = signal(false, ...(ngDevMode ? [{ debugName: "submitted" }] : []));
|
|
11414
12862
|
/** The decision this card sent last, so a proposal left for the approvers reads as such at once. */
|
|
@@ -11474,16 +12922,21 @@ class NhAssistantApprovalCardComponent {
|
|
|
11474
12922
|
/** The application's explanation of a stale proposal, such as who already did the work. */
|
|
11475
12923
|
this.staleExplanation = computed(() => this.effectiveStatus() === 'stale' ? this.approval().staleExplanation ?? null : null, ...(ngDevMode ? [{ debugName: "staleExplanation" }] : []));
|
|
11476
12924
|
this.actionable = computed(() => this.effectiveStatus() === 'pending', ...(ngDevMode ? [{ debugName: "actionable" }] : []));
|
|
11477
|
-
this.succeeded = computed(() => ['approved', 'executing', 'executed', 'resolved'].includes(this.effectiveStatus()), ...(ngDevMode ? [{ debugName: "succeeded" }] : []));
|
|
12925
|
+
this.succeeded = computed(() => ['approved', 'executing', 'awaiting-application', 'executed', 'resolved'].includes(this.effectiveStatus()), ...(ngDevMode ? [{ debugName: "succeeded" }] : []));
|
|
11478
12926
|
this.disabled = computed(() => !this.actionable() || !this.canDecide() || this.deciding() || this.submitted(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
11479
12927
|
/** The route at the subject the pending proposal may be left for; `null` when it can only be approved or rejected. */
|
|
11480
12928
|
this.leaveRoute = computed(() => this.actionable() ? this.consultation()?.leaveRoute ?? null : null, ...(ngDevMode ? [{ debugName: "leaveRoute" }] : []));
|
|
11481
|
-
this.leaveHintId = `nh-assistant-approval-leave-${nextId$
|
|
12929
|
+
this.leaveHintId = `nh-assistant-approval-leave-${nextId$6++}`;
|
|
12930
|
+
/** The user may resolve this uncertain hand-off: the server says so for the person who approved it. */
|
|
12931
|
+
this.resolvable = computed(() => this.approval().canResolve === true && this.effectiveStatus() === 'execution-unknown', ...(ngDevMode ? [{ debugName: "resolvable" }] : []));
|
|
12932
|
+
this.resolveDisabled = computed(() => !this.resolvable() || this.deciding() || this.resolving(), ...(ngDevMode ? [{ debugName: "resolveDisabled" }] : []));
|
|
12933
|
+
this.resolveHintId = `nh-assistant-approval-resolve-${nextId$6++}`;
|
|
12934
|
+
this.resolving = signal(false, ...(ngDevMode ? [{ debugName: "resolving" }] : []));
|
|
11482
12935
|
this.countdown = computed(() => formatNhAssistantCountdown(this.remainingMs()), ...(ngDevMode ? [{ debugName: "countdown" }] : []));
|
|
11483
12936
|
this.presentedSummary = computed(() => this.approval().presentation?.summary ?? null, ...(ngDevMode ? [{ debugName: "presentedSummary" }] : []));
|
|
11484
12937
|
this.feedbackAvailable = computed(() => this.canGiveFeedback() && this.effectiveStatus() === 'rejected', ...(ngDevMode ? [{ debugName: "feedbackAvailable" }] : []));
|
|
11485
12938
|
this.feedbackIds = computed(() => [this.approval().approvalId], ...(ngDevMode ? [{ debugName: "feedbackIds" }] : []));
|
|
11486
|
-
this.feedbackPanelId = `nh-assistant-approval-feedback-${nextId$
|
|
12939
|
+
this.feedbackPanelId = `nh-assistant-approval-feedback-${nextId$6++}`;
|
|
11487
12940
|
/** Translation key of the text shown instead of the buttons when the current user cannot decide. */
|
|
11488
12941
|
this.waitingKey = computed(() => {
|
|
11489
12942
|
switch (this.waitingFor()) {
|
|
@@ -11517,6 +12970,20 @@ class NhAssistantApprovalCardComponent {
|
|
|
11517
12970
|
this.submitted.set(false);
|
|
11518
12971
|
}
|
|
11519
12972
|
});
|
|
12973
|
+
// Allow another resolution once the host finished and the outcome is still unknown.
|
|
12974
|
+
effect(() => {
|
|
12975
|
+
if (!this.deciding() && this.approval().status === 'execution-unknown') {
|
|
12976
|
+
this.resolving.set(false);
|
|
12977
|
+
}
|
|
12978
|
+
});
|
|
12979
|
+
}
|
|
12980
|
+
/** Emits a resolution of an uncertain hand-off, at most once until the host reports it is done. */
|
|
12981
|
+
chooseResolution(resolution) {
|
|
12982
|
+
if (this.resolveDisabled()) {
|
|
12983
|
+
return;
|
|
12984
|
+
}
|
|
12985
|
+
this.resolving.set(true);
|
|
12986
|
+
this.resolve.emit(resolution);
|
|
11520
12987
|
}
|
|
11521
12988
|
/** Emits a decision; `leave` only for a consulted agent's proposal with a route at the subject. */
|
|
11522
12989
|
choose(decision) {
|
|
@@ -11539,16 +13006,16 @@ class NhAssistantApprovalCardComponent {
|
|
|
11539
13006
|
this.feedbackToggle()?.nativeElement.focus();
|
|
11540
13007
|
}
|
|
11541
13008
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantApprovalCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11542
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantApprovalCardComponent, isStandalone: true, selector: "nh-assistant-approval-card", inputs: { approval: { classPropertyName: "approval", publicName: "approval", isSignal: true, isRequired: true, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, canDecide: { classPropertyName: "canDecide", publicName: "canDecide", isSignal: true, isRequired: false, transformFunction: null }, decisionOwner: { classPropertyName: "decisionOwner", publicName: "decisionOwner", isSignal: true, isRequired: false, transformFunction: null }, waitingFor: { classPropertyName: "waitingFor", publicName: "waitingFor", isSignal: true, isRequired: false, transformFunction: null }, canGiveFeedback: { classPropertyName: "canGiveFeedback", publicName: "canGiveFeedback", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { decide: "decide" }, host: { properties: { "attr.data-status": "shownStatus()" } }, viewQueries: [{ propertyName: "feedbackToggle", first: true, predicate: ["feedbackToggle"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"leftForApprovers() ? 'users' : actionable() ? 'warning' : succeeded() ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ statusKey() | translate }}</span>\n </header>\n\n @if (staleExplanation(); as explanation) {\n <p class=\"stale-explanation\">{{ explanation }}</p>\n }\n\n <!-- Another agent the assistant consulted proposes this; the person who asked decides it here. -->\n @if (consultation(); as origin) {\n <p class=\"consultation-origin\" data-consultation-origin>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.origin' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId), subject: consultedSubject() } }}</span>\n </p>\n }\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n @if (rationale(); as why) {\n <p class=\"rationale\">{{ 'nh-assistant.approval.rationale' | translate: { rationale: why } }}</p>\n }\n\n @if (consultation(); as origin) {\n @if (origin.answer) {\n <details class=\"consultation-answer\" data-consultation-answer>\n <summary>{{ 'nh-assistant.approval.consultation.answer' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId) } }}</summary>\n <p>{{ origin.answer }}</p>\n </details>\n }\n @if (leftForApprovers()) {\n <p class=\"consultation-moved\" role=\"status\" data-consultation-moved>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.moved' | translate: { subject: consultedSubject() } }}</span>\n </p>\n }\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable() && !canDecide()) {\n <p class=\"waiting-for-other\" role=\"status\">\n <nh-assistant-icon name=\"users\" />\n {{ waitingKey() | translate: { name: decisionOwner() } }}\n </p>\n } @else if (actionable()) {\n @if (consultation()) {\n <p class=\"consultation-rights\" data-consultation-rights>{{ 'nh-assistant.approval.consultation.own-rights' | translate }}</p>\n }\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n <!-- The person may leave a consulted agent's proposal for the subject's approvers instead. -->\n @if (leaveRoute(); as route) {\n <div class=\"leave-for-approvers\">\n <p class=\"leave-explanation\" [id]=\"leaveHintId\">{{ 'nh-assistant.approval.consultation.leave-explain.' + route | translate: { subject: consultedSubject() } }}</p>\n <button\n class=\"leave\"\n type=\"button\"\n data-leave\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.consultation.leave-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n [attr.aria-describedby]=\"leaveHintId\"\n (click)=\"choose('leave')\">\n {{ 'nh-assistant.approval.consultation.leave' | translate }}\n </button>\n </div>\n }\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n\n @if (feedbackAvailable()) {\n @if (!feedbackSaved()) {\n <button\n #feedbackToggle\n class=\"feedback-toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"feedbackOpen()\"\n [attr.aria-controls]=\"feedbackOpen() ? feedbackPanelId : null\"\n (click)=\"toggleFeedback()\">\n {{ 'nh-assistant.approval.give-feedback' | translate }}\n </button>\n }\n @if (feedbackOpen()) {\n <nh-assistant-proposal-feedback\n class=\"feedback\"\n [attr.id]=\"feedbackPanelId\"\n [approvalIds]=\"feedbackIds()\"\n (saved)=\"onFeedbackSaved()\"\n (dismissed)=\"onFeedbackDismissed()\" />\n }\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]),:host([data-status=stale]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700;overflow-wrap:anywhere}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.stale-explanation{margin:8px 0 0;border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong);font-size:13px;overflow-wrap:anywhere}.consultation-origin,.consultation-moved{display:flex;align-items:flex-start;gap:6px;margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.consultation-moved{border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong)}.consultation-answer{margin-top:8px;font-size:13px}.consultation-answer summary{cursor:pointer;color:var(--nha-text-muted);font-size:12px;font-weight:700}.consultation-answer summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.consultation-answer p{max-height:200px;margin:6px 0 0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);white-space:pre-wrap;overflow-wrap:anywhere}.consultation-rights{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.rationale{margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding,.waiting-for-other{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.leave-for-approvers{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-top:10px}.leave-explanation{flex:1 1 200px;margin:0;color:var(--nha-text-muted);font-size:12px}.reject,.leave{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled),.leave:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}.feedback-toggle{display:inline-flex;min-height:0;margin-top:10px;border:0;border-radius:6px;padding:2px 0;color:var(--nha-text-muted);background:transparent;font-size:12px;font-weight:650;text-decoration:underline;text-underline-offset:2px}.feedback-toggle:hover:not(:disabled){color:var(--nha-text)}.feedback{display:block;margin-top:10px}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantProposalFeedbackComponent, selector: "nh-assistant-proposal-feedback", inputs: ["approvalIds", "initial"], outputs: ["saved", "dismissed"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
13009
|
+
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", resolve: "resolve" }, 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 <!-- The user approved it in this chat and whether the application took it is unknown. -->\n @if (resolvable()) {\n <div class=\"resolve\" data-resolve>\n <p class=\"resolve-explanation\" [id]=\"resolveHintId\">{{ 'nh-assistant.approval.resolve.explanation' | translate }}</p>\n <div class=\"actions\">\n <button\n class=\"mark-resolved\"\n type=\"button\"\n data-mark-resolved\n [disabled]=\"resolveDisabled()\"\n [attr.aria-describedby]=\"resolveHintId\"\n (click)=\"chooseResolution('mark-resolved')\">\n {{ 'nh-assistant.approval.resolve.mark-resolved' | translate }}\n </button>\n <button\n class=\"hand-again\"\n type=\"button\"\n data-hand-to-application\n [disabled]=\"resolveDisabled()\"\n [attr.aria-describedby]=\"resolveHintId\"\n (click)=\"chooseResolution('hand-to-application')\">\n {{ 'nh-assistant.approval.resolve.hand-to-application' | translate }}\n </button>\n </div>\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.resolve.resolving' | translate }}</p>\n }\n </div>\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}.resolve{margin-top:10px}.resolve-explanation{margin:0;color:var(--nha-text-muted);font-size:12px}.reject,.leave,.mark-resolved{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled),.leave:hover:not(:disabled),.mark-resolved:hover:not(:disabled){background:var(--nha-surface-strong)}.approve,.hand-again{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled),.hand-again: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 }); }
|
|
11543
13010
|
}
|
|
11544
13011
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantApprovalCardComponent, decorators: [{
|
|
11545
13012
|
type: Component,
|
|
11546
13013
|
args: [{ selector: 'nh-assistant-approval-card', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent, NhAssistantProposalFeedbackComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
11547
13014
|
'[attr.data-status]': 'shownStatus()'
|
|
11548
|
-
}, template: "<section class=\"card\" [attr.aria-label]=\"'nh-assistant.approval.title' | translate\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"leftForApprovers() ? 'users' : actionable() ? 'warning' : succeeded() ? 'check' : 'x'\" />\n <h3>{{ 'nh-assistant.approval.title' | translate }}</h3>\n <span class=\"status\">{{ statusKey() | translate }}</span>\n </header>\n\n @if (staleExplanation(); as explanation) {\n <p class=\"stale-explanation\">{{ explanation }}</p>\n }\n\n <!-- Another agent the assistant consulted proposes this; the person who asked decides it here. -->\n @if (consultation(); as origin) {\n <p class=\"consultation-origin\" data-consultation-origin>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.origin' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId), subject: consultedSubject() } }}</span>\n </p>\n }\n\n @if (approval().presentation; as presentation) {\n <p class=\"tool-name\">{{ presentation.toolDisplayName }}</p>\n <p class=\"summary\">{{ presentation.summary }}</p>\n @if (presentation.fields.length > 0) {\n <dl class=\"presentation-fields\">\n @for (field of presentation.fields; track $index) {\n <div>\n <dt>{{ field.label }}</dt>\n <dd>{{ field.value }}</dd>\n </div>\n }\n </dl>\n }\n @if (presentation.notice) {\n <p class=\"notice\">{{ presentation.notice }}</p>\n }\n } @else {\n <p class=\"summary\">{{ 'nh-assistant.approval.fallback-summary' | translate }}</p>\n }\n\n @if (rationale(); as why) {\n <p class=\"rationale\">{{ 'nh-assistant.approval.rationale' | translate: { rationale: why } }}</p>\n }\n\n @if (consultation(); as origin) {\n @if (origin.answer) {\n <details class=\"consultation-answer\" data-consultation-answer>\n <summary>{{ 'nh-assistant.approval.consultation.answer' | translate: { agent: (consultedAgentKeys() | nhAssistantTranslate: origin.agentId) } }}</summary>\n <p>{{ origin.answer }}</p>\n </details>\n }\n @if (leftForApprovers()) {\n <p class=\"consultation-moved\" role=\"status\" data-consultation-moved>\n <nh-assistant-icon name=\"users\" />\n <span>{{ 'nh-assistant.approval.consultation.moved' | translate: { subject: consultedSubject() } }}</span>\n </p>\n }\n }\n\n <details class=\"technical-details\">\n <summary>{{ 'nh-assistant.approval.technical-details' | translate }}</summary>\n <p class=\"label\">{{ 'nh-assistant.approval.tool-id' | translate }}</p>\n <code>{{ approval().toolId }}</code>\n @if (approval().targets.length > 0) {\n <p class=\"label\">{{ 'nh-assistant.approval.targets' | translate }}</p>\n <ul class=\"targets\">\n @for (target of approval().targets; track $index) {\n <li>{{ target }}</li>\n }\n </ul>\n }\n @if (approval().argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.approval.arguments' | translate }}</p>\n <pre>{{ approval().argumentsPreview }}</pre>\n }\n </details>\n\n @if (actionable() && !canDecide()) {\n <p class=\"waiting-for-other\" role=\"status\">\n <nh-assistant-icon name=\"users\" />\n {{ waitingKey() | translate: { name: decisionOwner() } }}\n </p>\n } @else if (actionable()) {\n @if (consultation()) {\n <p class=\"consultation-rights\" data-consultation-rights>{{ 'nh-assistant.approval.consultation.own-rights' | translate }}</p>\n }\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.approval.expires-in' | translate: { time: countdown() } }}\n </p>\n <div class=\"actions\">\n <button\n class=\"reject\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.reject-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('reject')\">\n {{ 'nh-assistant.approval.reject' | translate }}\n </button>\n <button\n class=\"approve\"\n type=\"button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.approve-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n (click)=\"choose('approve')\">\n {{ 'nh-assistant.approval.approve' | translate }}\n </button>\n </div>\n <!-- The person may leave a consulted agent's proposal for the subject's approvers instead. -->\n @if (leaveRoute(); as route) {\n <div class=\"leave-for-approvers\">\n <p class=\"leave-explanation\" [id]=\"leaveHintId\">{{ 'nh-assistant.approval.consultation.leave-explain.' + route | translate: { subject: consultedSubject() } }}</p>\n <button\n class=\"leave\"\n type=\"button\"\n data-leave\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.approval.consultation.leave-label' | translate: { summary: presentedSummary() ?? ('nh-assistant.approval.fallback-summary' | translate) }\"\n [attr.aria-describedby]=\"leaveHintId\"\n (click)=\"choose('leave')\">\n {{ 'nh-assistant.approval.consultation.leave' | translate }}\n </button>\n </div>\n }\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.deciding' | translate }}</p>\n }\n } @else if (expired()) {\n <p class=\"expiry\">{{ 'nh-assistant.approval.expired' | translate }}</p>\n }\n\n @if (feedbackAvailable()) {\n @if (!feedbackSaved()) {\n <button\n #feedbackToggle\n class=\"feedback-toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"feedbackOpen()\"\n [attr.aria-controls]=\"feedbackOpen() ? feedbackPanelId : null\"\n (click)=\"toggleFeedback()\">\n {{ 'nh-assistant.approval.give-feedback' | translate }}\n </button>\n }\n @if (feedbackOpen()) {\n <nh-assistant-proposal-feedback\n class=\"feedback\"\n [attr.id]=\"feedbackPanelId\"\n [approvalIds]=\"feedbackIds()\"\n (saved)=\"onFeedbackSaved()\"\n (dismissed)=\"onFeedbackDismissed()\" />\n }\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=approved]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=rejected]),:host([data-status=expired]),:host([data-status=stale]){--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}.card{border:1px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:12px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;color:var(--nha-status-color)}h3{flex:1;margin:0;color:var(--nha-text);font-size:14px;font-weight:700}.status{border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.summary{margin:8px 0 0;font-size:14px;overflow-wrap:anywhere}.tool-name{margin:10px 0 0;font-size:12px;font-weight:700}.presentation-fields{display:grid;gap:6px;margin:10px 0 0}.presentation-fields div{display:grid;grid-template-columns:minmax(90px,.4fr) minmax(0,1fr);gap:8px}.presentation-fields dt{color:var(--nha-text-muted);font-size:12px;font-weight:700;overflow-wrap:anywhere}.presentation-fields dd{margin:0;overflow-wrap:anywhere;font-size:13px}.notice{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.stale-explanation{margin:8px 0 0;border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong);font-size:13px;overflow-wrap:anywhere}.consultation-origin,.consultation-moved{display:flex;align-items:flex-start;gap:6px;margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.consultation-moved{border-radius:8px;padding:8px 10px;color:var(--nha-text);background:var(--nha-surface-strong)}.consultation-answer{margin-top:8px;font-size:13px}.consultation-answer summary{cursor:pointer;color:var(--nha-text-muted);font-size:12px;font-weight:700}.consultation-answer summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.consultation-answer p{max-height:200px;margin:6px 0 0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);white-space:pre-wrap;overflow-wrap:anywhere}.consultation-rights{margin:10px 0 0;color:var(--nha-text-muted);font-size:12px}.rationale{margin:8px 0 0;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.technical-details{margin-top:10px;color:var(--nha-text-muted);font-size:12px}.technical-details summary{cursor:pointer;font-weight:700}.technical-details code{overflow-wrap:anywhere}.label{margin:10px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.targets{margin:0;padding-left:18px;font-size:13px;overflow-wrap:anywhere}pre{max-height:160px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}.expiry,.deciding,.waiting-for-other{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:12px}button{min-height:36px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer}button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.55}.leave-for-approvers{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-top:10px}.leave-explanation{flex:1 1 200px;margin:0;color:var(--nha-text-muted);font-size:12px}.reject,.leave{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled),.leave:hover:not(:disabled){background:var(--nha-surface-strong)}.approve{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled){filter:brightness(1.12)}.feedback-toggle{display:inline-flex;min-height:0;margin-top:10px;border:0;border-radius:6px;padding:2px 0;color:var(--nha-text-muted);background:transparent;font-size:12px;font-weight:650;text-decoration:underline;text-underline-offset:2px}.feedback-toggle:hover:not(:disabled){color:var(--nha-text)}.feedback{display:block;margin-top:10px}\n"] }]
|
|
11549
|
-
}], ctorParameters: () => [], propDecorators: { approval: [{ type: i0.Input, args: [{ isSignal: true, alias: "approval", required: true }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], canDecide: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDecide", required: false }] }], decisionOwner: [{ type: i0.Input, args: [{ isSignal: true, alias: "decisionOwner", required: false }] }], waitingFor: [{ type: i0.Input, args: [{ isSignal: true, alias: "waitingFor", required: false }] }], canGiveFeedback: [{ type: i0.Input, args: [{ isSignal: true, alias: "canGiveFeedback", required: false }] }], decide: [{ type: i0.Output, args: ["decide"] }], feedbackToggle: [{ type: i0.ViewChild, args: ['feedbackToggle', { isSignal: true }] }] } });
|
|
13015
|
+
}, 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 <!-- The user approved it in this chat and whether the application took it is unknown. -->\n @if (resolvable()) {\n <div class=\"resolve\" data-resolve>\n <p class=\"resolve-explanation\" [id]=\"resolveHintId\">{{ 'nh-assistant.approval.resolve.explanation' | translate }}</p>\n <div class=\"actions\">\n <button\n class=\"mark-resolved\"\n type=\"button\"\n data-mark-resolved\n [disabled]=\"resolveDisabled()\"\n [attr.aria-describedby]=\"resolveHintId\"\n (click)=\"chooseResolution('mark-resolved')\">\n {{ 'nh-assistant.approval.resolve.mark-resolved' | translate }}\n </button>\n <button\n class=\"hand-again\"\n type=\"button\"\n data-hand-to-application\n [disabled]=\"resolveDisabled()\"\n [attr.aria-describedby]=\"resolveHintId\"\n (click)=\"chooseResolution('hand-to-application')\">\n {{ 'nh-assistant.approval.resolve.hand-to-application' | translate }}\n </button>\n </div>\n @if (deciding()) {\n <p class=\"deciding\" role=\"status\">{{ 'nh-assistant.approval.resolve.resolving' | translate }}</p>\n }\n </div>\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}.resolve{margin-top:10px}.resolve-explanation{margin:0;color:var(--nha-text-muted);font-size:12px}.reject,.leave,.mark-resolved{color:var(--nha-text);background:transparent}.reject:hover:not(:disabled),.leave:hover:not(:disabled),.mark-resolved:hover:not(:disabled){background:var(--nha-surface-strong)}.approve,.hand-again{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.approve:hover:not(:disabled),.hand-again: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"] }]
|
|
13016
|
+
}], 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"] }], resolve: [{ type: i0.Output, args: ["resolve"] }], feedbackToggle: [{ type: i0.ViewChild, args: ['feedbackToggle', { isSignal: true }] }] } });
|
|
11550
13017
|
|
|
11551
|
-
let nextId$
|
|
13018
|
+
let nextId$5 = 0;
|
|
11552
13019
|
/**
|
|
11553
13020
|
* The card of a turn that went on without an MCP server the person who asked has to connect. It
|
|
11554
13021
|
* connects the viewer's own account, in a popup or by redirect as the host configured, and then
|
|
@@ -11563,7 +13030,7 @@ class NhAssistantConnectionRequiredComponent {
|
|
|
11563
13030
|
this.canRetry = input(true, ...(ngDevMode ? [{ debugName: "canRetry" }] : []));
|
|
11564
13031
|
/** Asks the question of the turn again after the account was connected. */
|
|
11565
13032
|
this.retry = output();
|
|
11566
|
-
this.id = `nh-assistant-connection-${nextId$
|
|
13033
|
+
this.id = `nh-assistant-connection-${nextId$5++}`;
|
|
11567
13034
|
this.state = signal('idle', ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
11568
13035
|
/** Why connecting failed, as a code and translation key. */
|
|
11569
13036
|
this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
@@ -11621,12 +13088,93 @@ function serverOf(returned) {
|
|
|
11621
13088
|
return returned.completion?.serverId ?? returned.serverId ?? null;
|
|
11622
13089
|
}
|
|
11623
13090
|
|
|
13091
|
+
let nextId$4 = 0;
|
|
13092
|
+
const statusIcons$1 = {
|
|
13093
|
+
pending: 'clock',
|
|
13094
|
+
answered: 'check',
|
|
13095
|
+
expired: 'x',
|
|
13096
|
+
cancelled: 'stop'
|
|
13097
|
+
};
|
|
13098
|
+
/**
|
|
13099
|
+
* A question the agent asked with `ask_question`: the question with one button per choice for the
|
|
13100
|
+
* person it is addressed to (`canAnswer`), and read-only for everyone else, who sees whom it waits
|
|
13101
|
+
* for. It counts down to the end of its wait. Once answered it marks the chosen answer; an expired or
|
|
13102
|
+
* cancelled question says so. An answer is emitted at most once until the host reports that it is no
|
|
13103
|
+
* longer answering.
|
|
13104
|
+
*/
|
|
13105
|
+
class NhAssistantQuestionCardComponent {
|
|
13106
|
+
constructor() {
|
|
13107
|
+
this.question = input.required(...(ngDevMode ? [{ debugName: "question" }] : []));
|
|
13108
|
+
/** True when the current user is the addressee and may answer, for example `NhAssistantStore.canAnswer`. */
|
|
13109
|
+
this.canAnswer = input(false, ...(ngDevMode ? [{ debugName: "canAnswer" }] : []));
|
|
13110
|
+
/** Name of the person the question is addressed to, shown to everyone else; `null` when unknown. */
|
|
13111
|
+
this.addresseeName = input(null, ...(ngDevMode ? [{ debugName: "addresseeName" }] : []));
|
|
13112
|
+
/** True while the host submits an answer; disables the choices. */
|
|
13113
|
+
this.answering = input(false, ...(ngDevMode ? [{ debugName: "answering" }] : []));
|
|
13114
|
+
/** The zero-based index of the chosen answer. */
|
|
13115
|
+
this.answer = output();
|
|
13116
|
+
this.questionId = `nh-assistant-question-${nextId$4++}`;
|
|
13117
|
+
this.now = signal(Date.now(), ...(ngDevMode ? [{ debugName: "now" }] : []));
|
|
13118
|
+
this.submitted = signal(false, ...(ngDevMode ? [{ debugName: "submitted" }] : []));
|
|
13119
|
+
this.remainingMs = computed(() => Date.parse(this.question().expiresAt) - this.now(), ...(ngDevMode ? [{ debugName: "remainingMs" }] : []));
|
|
13120
|
+
/** A pending question whose wait ended reads as expired before the server says so. */
|
|
13121
|
+
this.effectiveStatus = computed(() => this.question().status === 'pending' && this.remainingMs() <= 0 ? 'expired' : this.question().status, ...(ngDevMode ? [{ debugName: "effectiveStatus" }] : []));
|
|
13122
|
+
this.actionable = computed(() => this.effectiveStatus() === 'pending', ...(ngDevMode ? [{ debugName: "actionable" }] : []));
|
|
13123
|
+
this.statusIcon = computed(() => statusIcons$1[this.effectiveStatus()], ...(ngDevMode ? [{ debugName: "statusIcon" }] : []));
|
|
13124
|
+
this.disabled = computed(() => !this.actionable() || !this.canAnswer() || this.answering() || this.submitted(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
13125
|
+
this.chosen = computed(() => this.question().answerIndex ?? null, ...(ngDevMode ? [{ debugName: "chosen" }] : []));
|
|
13126
|
+
this.chosenText = computed(() => {
|
|
13127
|
+
const index = this.chosen();
|
|
13128
|
+
return index === null ? null : this.question().choices[index] ?? null;
|
|
13129
|
+
}, ...(ngDevMode ? [{ debugName: "chosenText" }] : []));
|
|
13130
|
+
this.countdown = computed(() => formatNhAssistantCountdown(this.remainingMs()), ...(ngDevMode ? [{ debugName: "countdown" }] : []));
|
|
13131
|
+
// Tick only while the question waits.
|
|
13132
|
+
effect(onCleanup => {
|
|
13133
|
+
if (this.question().status !== 'pending') {
|
|
13134
|
+
return;
|
|
13135
|
+
}
|
|
13136
|
+
const expiresAt = Date.parse(this.question().expiresAt);
|
|
13137
|
+
const timer = setInterval(() => {
|
|
13138
|
+
this.now.set(Date.now());
|
|
13139
|
+
if (Date.now() >= expiresAt) {
|
|
13140
|
+
clearInterval(timer);
|
|
13141
|
+
}
|
|
13142
|
+
}, 1000);
|
|
13143
|
+
onCleanup(() => clearInterval(timer));
|
|
13144
|
+
});
|
|
13145
|
+
// Allow another attempt once the host finished and the question still waits.
|
|
13146
|
+
effect(() => {
|
|
13147
|
+
if (!this.answering() && this.question().status === 'pending') {
|
|
13148
|
+
this.submitted.set(false);
|
|
13149
|
+
}
|
|
13150
|
+
});
|
|
13151
|
+
}
|
|
13152
|
+
/** Emits the chosen answer once. */
|
|
13153
|
+
choose(index) {
|
|
13154
|
+
if (this.disabled() || index < 0 || index >= this.question().choices.length) {
|
|
13155
|
+
return;
|
|
13156
|
+
}
|
|
13157
|
+
this.submitted.set(true);
|
|
13158
|
+
this.answer.emit(index);
|
|
13159
|
+
}
|
|
13160
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantQuestionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
13161
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantQuestionCardComponent, isStandalone: true, selector: "nh-assistant-question-card", inputs: { question: { classPropertyName: "question", publicName: "question", isSignal: true, isRequired: true, transformFunction: null }, canAnswer: { classPropertyName: "canAnswer", publicName: "canAnswer", isSignal: true, isRequired: false, transformFunction: null }, addresseeName: { classPropertyName: "addresseeName", publicName: "addresseeName", isSignal: true, isRequired: false, transformFunction: null }, answering: { classPropertyName: "answering", publicName: "answering", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { answer: "answer" }, host: { properties: { "attr.data-status": "effectiveStatus()" } }, ngImport: i0, template: "<section class=\"card\" [attr.aria-labelledby]=\"questionId\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n <h3>{{ 'nh-assistant.question.title' | translate }}</h3>\n <span class=\"status\">{{ 'nh-assistant.question.status.' + effectiveStatus() | translate }}</span>\n </header>\n\n <p class=\"question\" [id]=\"questionId\">{{ question().question }}</p>\n\n @if (actionable() && canAnswer()) {\n <div class=\"choices\" role=\"group\" [attr.aria-labelledby]=\"questionId\">\n @for (choice of question().choices; track $index) {\n <button\n class=\"choice\"\n type=\"button\"\n data-choice\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.question.choose-label' | translate: { choice }\"\n (click)=\"choose($index)\">\n {{ choice }}\n </button>\n }\n </div>\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.question.expires-in' | translate: { time: countdown() } }}\n </p>\n @if (answering()) {\n <p class=\"answering\" role=\"status\">{{ 'nh-assistant.question.answering' | translate }}</p>\n }\n } @else {\n <ul class=\"choices read-only\" [attr.aria-label]=\"'nh-assistant.question.choices' | translate\">\n @for (choice of question().choices; track $index) {\n <li class=\"choice\" [attr.data-chosen]=\"$index === chosen() ? 'true' : null\">\n @if ($index === chosen()) {\n <nh-assistant-icon name=\"check\" />\n }\n <span>{{ choice }}</span>\n </li>\n }\n </ul>\n @switch (effectiveStatus()) {\n @case ('pending') {\n <p class=\"waiting-for-other\" role=\"status\" data-waiting-for>\n <nh-assistant-icon name=\"users\" />\n @if (addresseeName(); as name) {\n {{ 'nh-assistant.question.waiting-for' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.question.waiting-for-participant' | translate }}\n }\n </p>\n }\n @case ('answered') {\n @if (chosenText(); as text) {\n <p class=\"outcome\" data-answer>{{ 'nh-assistant.question.answered' | translate: { choice: text } }}</p>\n }\n }\n @case ('expired') {\n <p class=\"outcome\">{{ 'nh-assistant.question.expired' | translate }}</p>\n }\n @case ('cancelled') {\n <p class=\"outcome\">{{ 'nh-assistant.question.cancelled' | translate }}</p>\n }\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-accent);--nha-status-background: var(--nha-surface-strong)}:host([data-status=answered]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=expired]),:host([data-status=cancelled]){--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}.question{margin:8px 0 0;font-size:14px;white-space:pre-wrap;overflow-wrap:anywhere}.choices{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 0}.choices.read-only{flex-direction:column;gap:4px;padding:0;list-style:none}.choices.read-only .choice{display:flex;align-items:center;gap:6px;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.choices.read-only .choice[data-chosen=true]{color:var(--nha-text);font-weight:700}button.choice{min-height:36px;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;color:var(--nha-text);background:transparent;font:inherit;font-size:13px;font-weight:700;text-align:start;overflow-wrap:anywhere;cursor:pointer}button.choice:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button.choice:hover:not(:disabled){border-color:var(--nha-accent);background:var(--nha-surface-strong)}button.choice:disabled{cursor:not-allowed;opacity:.55}.expiry,.answering,.waiting-for-other,.outcome{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.outcome{color:var(--nha-text)}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
13162
|
+
}
|
|
13163
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantQuestionCardComponent, decorators: [{
|
|
13164
|
+
type: Component,
|
|
13165
|
+
args: [{ selector: 'nh-assistant-question-card', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
13166
|
+
'[attr.data-status]': 'effectiveStatus()'
|
|
13167
|
+
}, template: "<section class=\"card\" [attr.aria-labelledby]=\"questionId\">\n <header class=\"header\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n <h3>{{ 'nh-assistant.question.title' | translate }}</h3>\n <span class=\"status\">{{ 'nh-assistant.question.status.' + effectiveStatus() | translate }}</span>\n </header>\n\n <p class=\"question\" [id]=\"questionId\">{{ question().question }}</p>\n\n @if (actionable() && canAnswer()) {\n <div class=\"choices\" role=\"group\" [attr.aria-labelledby]=\"questionId\">\n @for (choice of question().choices; track $index) {\n <button\n class=\"choice\"\n type=\"button\"\n data-choice\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'nh-assistant.question.choose-label' | translate: { choice }\"\n (click)=\"choose($index)\">\n {{ choice }}\n </button>\n }\n </div>\n <p class=\"expiry\" aria-live=\"off\">\n <nh-assistant-icon name=\"clock\" />\n {{ 'nh-assistant.question.expires-in' | translate: { time: countdown() } }}\n </p>\n @if (answering()) {\n <p class=\"answering\" role=\"status\">{{ 'nh-assistant.question.answering' | translate }}</p>\n }\n } @else {\n <ul class=\"choices read-only\" [attr.aria-label]=\"'nh-assistant.question.choices' | translate\">\n @for (choice of question().choices; track $index) {\n <li class=\"choice\" [attr.data-chosen]=\"$index === chosen() ? 'true' : null\">\n @if ($index === chosen()) {\n <nh-assistant-icon name=\"check\" />\n }\n <span>{{ choice }}</span>\n </li>\n }\n </ul>\n @switch (effectiveStatus()) {\n @case ('pending') {\n <p class=\"waiting-for-other\" role=\"status\" data-waiting-for>\n <nh-assistant-icon name=\"users\" />\n @if (addresseeName(); as name) {\n {{ 'nh-assistant.question.waiting-for' | translate: { name } }}\n } @else {\n {{ 'nh-assistant.question.waiting-for-participant' | translate }}\n }\n </p>\n }\n @case ('answered') {\n @if (chosenText(); as text) {\n <p class=\"outcome\" data-answer>{{ 'nh-assistant.question.answered' | translate: { choice: text } }}</p>\n }\n }\n @case ('expired') {\n <p class=\"outcome\">{{ 'nh-assistant.question.expired' | translate }}</p>\n }\n @case ('cancelled') {\n <p class=\"outcome\">{{ 'nh-assistant.question.cancelled' | translate }}</p>\n }\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-accent);--nha-status-background: var(--nha-surface-strong)}:host([data-status=answered]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=expired]),:host([data-status=cancelled]){--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}.question{margin:8px 0 0;font-size:14px;white-space:pre-wrap;overflow-wrap:anywhere}.choices{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 0}.choices.read-only{flex-direction:column;gap:4px;padding:0;list-style:none}.choices.read-only .choice{display:flex;align-items:center;gap:6px;color:var(--nha-text-muted);font-size:13px;overflow-wrap:anywhere}.choices.read-only .choice[data-chosen=true]{color:var(--nha-text);font-weight:700}button.choice{min-height:36px;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 14px;color:var(--nha-text);background:transparent;font:inherit;font-size:13px;font-weight:700;text-align:start;overflow-wrap:anywhere;cursor:pointer}button.choice:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}button.choice:hover:not(:disabled){border-color:var(--nha-accent);background:var(--nha-surface-strong)}button.choice:disabled{cursor:not-allowed;opacity:.55}.expiry,.answering,.waiting-for-other,.outcome{display:flex;align-items:center;gap:6px;margin:10px 0 0;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.outcome{color:var(--nha-text)}\n"] }]
|
|
13168
|
+
}], ctorParameters: () => [], propDecorators: { question: [{ type: i0.Input, args: [{ isSignal: true, alias: "question", required: true }] }], canAnswer: [{ type: i0.Input, args: [{ isSignal: true, alias: "canAnswer", required: false }] }], addresseeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "addresseeName", required: false }] }], answering: [{ type: i0.Input, args: [{ isSignal: true, alias: "answering", required: false }] }], answer: [{ type: i0.Output, args: ["answer"] }] } });
|
|
13169
|
+
|
|
11624
13170
|
let nextId$3 = 0;
|
|
11625
13171
|
const statusIcons = {
|
|
11626
13172
|
running: 'tool',
|
|
11627
13173
|
succeeded: 'check',
|
|
11628
13174
|
failed: 'warning',
|
|
11629
13175
|
'awaiting-approval': 'clock',
|
|
13176
|
+
// An ask_question call waits for the person it asked.
|
|
13177
|
+
'awaiting-answer': 'clock',
|
|
11630
13178
|
rejected: 'x',
|
|
11631
13179
|
// Ended without running: its proposal expired, was withdrawn or became stale.
|
|
11632
13180
|
'not-executed': 'stop'
|
|
@@ -11644,18 +13192,19 @@ class NhAssistantToolCallCardComponent {
|
|
|
11644
13192
|
this.expanded.update(expanded => !expanded);
|
|
11645
13193
|
}
|
|
11646
13194
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantToolCallCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11647
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantToolCallCardComponent, isStandalone: true, selector: "nh-assistant-tool-call-card", inputs: { part: { classPropertyName: "part", publicName: "part", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-status": "part().status" } }, ngImport: i0, template: "<article class=\"card\" [attr.aria-label]=\"'nh-assistant.tool-call.label' | translate: { name: part().displayName }\">\n <header class=\"header\">\n <span class=\"status-icon\" [class.spinning]=\"part().status === 'running'\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n </span>\n <span class=\"title\">{{ part().displayName }}</span>\n @if (part().grantSource; as grantSource) {\n <span class=\"grant\" [attr.title]=\"'nh-assistant.tool-call.grant-source.' + grantSource + '-hint' | translate\">\n {{ 'nh-assistant.tool-call.grant-source.' + grantSource | translate }}\n </span>\n }\n <span class=\"status\">{{ 'nh-assistant.tool-call.status.' + part().status | translate }}</span>\n @if (hasDetails()) {\n <button\n class=\"toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"detailsId\"\n [attr.aria-label]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n (click)=\"toggle()\">\n <nh-assistant-icon name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n }\n </header>\n\n @if (part().resultCode; as resultCode) {\n <p class=\"result-code\">\n {{ ['nh-assistant.result-codes.' + resultCode, 'nh-assistant.errors.' + resultCode] | nhAssistantTranslate: resultCode }}\n </p>\n }\n\n @if (hasDetails()) {\n <div class=\"details\" [id]=\"detailsId\" [hidden]=\"!expanded()\">\n <p class=\"label\">{{ 'nh-assistant.tool-call.tool-id' | translate }}</p>\n <code>{{ part().toolId }}</code>\n @if (part().argumentsPreview; as argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.arguments' | translate }}</p>\n <pre>{{ argumentsPreview }}</pre>\n }\n @if (part().resultPreview; as resultPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <pre>{{ resultPreview }}</pre>\n } @else if (part().restricted) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <p class=\"restricted\">{{ 'nh-assistant.tool-call.restricted' | translate }}</p>\n }\n </div>\n }\n</article>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=failed]){--nha-status-color: var(--nha-danger);--nha-status-background: var(--nha-danger-soft)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=rejected]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .card{border-left-style:dashed}.card{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:8px 10px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;min-width:0}.status-icon{display:inline-flex;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.status{flex:none;border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:28px;height:28px}.toggle:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.toggle:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.toggle:disabled{cursor:not-allowed;opacity:.5}.rotated{transform:rotate(180deg)}.result-code{margin:6px 0 0;color:var(--nha-text-muted);font-size:12px}.details{margin-top:8px}.label{margin:8px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}pre{max-height:180px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}nh-assistant-icon{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}.grant{flex:none;padding:1px 6px;border:1px solid var(--nh-assistant-border, currentColor);border-radius:999px;font-size:.75em;opacity:.85}.restricted{margin:0;font-style:italic;opacity:.8}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
13195
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantToolCallCardComponent, isStandalone: true, selector: "nh-assistant-tool-call-card", inputs: { part: { classPropertyName: "part", publicName: "part", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-status": "part().status" } }, ngImport: i0, template: "<article class=\"card\" [attr.aria-label]=\"'nh-assistant.tool-call.label' | translate: { name: part().displayName }\">\n <header class=\"header\">\n <span class=\"status-icon\" [class.spinning]=\"part().status === 'running'\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n </span>\n <span class=\"title\">{{ part().displayName }}</span>\n @if (part().grantSource; as grantSource) {\n <span class=\"grant\" [attr.title]=\"'nh-assistant.tool-call.grant-source.' + grantSource + '-hint' | translate\">\n {{ 'nh-assistant.tool-call.grant-source.' + grantSource | translate }}\n </span>\n }\n <span class=\"status\">{{ 'nh-assistant.tool-call.status.' + part().status | translate }}</span>\n @if (hasDetails()) {\n <button\n class=\"toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"detailsId\"\n [attr.aria-label]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n (click)=\"toggle()\">\n <nh-assistant-icon name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n }\n </header>\n\n @if (part().resultCode; as resultCode) {\n <p class=\"result-code\">\n {{ ['nh-assistant.result-codes.' + resultCode, 'nh-assistant.errors.' + resultCode] | nhAssistantTranslate: resultCode }}\n </p>\n }\n\n @if (hasDetails()) {\n <div class=\"details\" [id]=\"detailsId\" [hidden]=\"!expanded()\">\n <p class=\"label\">{{ 'nh-assistant.tool-call.tool-id' | translate }}</p>\n <code>{{ part().toolId }}</code>\n @if (part().argumentsPreview; as argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.arguments' | translate }}</p>\n <pre>{{ argumentsPreview }}</pre>\n }\n @if (part().resultPreview; as resultPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <pre>{{ resultPreview }}</pre>\n } @else if (part().restricted) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <p class=\"restricted\">{{ 'nh-assistant.tool-call.restricted' | translate }}</p>\n }\n </div>\n }\n</article>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=failed]){--nha-status-color: var(--nha-danger);--nha-status-background: var(--nha-danger-soft)}:host([data-status=awaiting-approval]),:host([data-status=awaiting-answer]){--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=rejected]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .card{border-left-style:dashed}.card{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:8px 10px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;min-width:0}.status-icon{display:inline-flex;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.status{flex:none;border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:28px;height:28px}.toggle:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.toggle:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.toggle:disabled{cursor:not-allowed;opacity:.5}.rotated{transform:rotate(180deg)}.result-code{margin:6px 0 0;color:var(--nha-text-muted);font-size:12px}.details{margin-top:8px}.label{margin:8px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}pre{max-height:180px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}nh-assistant-icon{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}.grant{flex:none;padding:1px 6px;border:1px solid var(--nh-assistant-border, currentColor);border-radius:999px;font-size:.75em;opacity:.85}.restricted{margin:0;font-style:italic;opacity:.8}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11648
13196
|
}
|
|
11649
13197
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantToolCallCardComponent, decorators: [{
|
|
11650
13198
|
type: Component,
|
|
11651
13199
|
args: [{ selector: 'nh-assistant-tool-call-card', standalone: true, imports: [TranslatePipe, NhAssistantTranslatePipe, NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
11652
13200
|
'[attr.data-status]': 'part().status'
|
|
11653
|
-
}, template: "<article class=\"card\" [attr.aria-label]=\"'nh-assistant.tool-call.label' | translate: { name: part().displayName }\">\n <header class=\"header\">\n <span class=\"status-icon\" [class.spinning]=\"part().status === 'running'\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n </span>\n <span class=\"title\">{{ part().displayName }}</span>\n @if (part().grantSource; as grantSource) {\n <span class=\"grant\" [attr.title]=\"'nh-assistant.tool-call.grant-source.' + grantSource + '-hint' | translate\">\n {{ 'nh-assistant.tool-call.grant-source.' + grantSource | translate }}\n </span>\n }\n <span class=\"status\">{{ 'nh-assistant.tool-call.status.' + part().status | translate }}</span>\n @if (hasDetails()) {\n <button\n class=\"toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"detailsId\"\n [attr.aria-label]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n (click)=\"toggle()\">\n <nh-assistant-icon name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n }\n </header>\n\n @if (part().resultCode; as resultCode) {\n <p class=\"result-code\">\n {{ ['nh-assistant.result-codes.' + resultCode, 'nh-assistant.errors.' + resultCode] | nhAssistantTranslate: resultCode }}\n </p>\n }\n\n @if (hasDetails()) {\n <div class=\"details\" [id]=\"detailsId\" [hidden]=\"!expanded()\">\n <p class=\"label\">{{ 'nh-assistant.tool-call.tool-id' | translate }}</p>\n <code>{{ part().toolId }}</code>\n @if (part().argumentsPreview; as argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.arguments' | translate }}</p>\n <pre>{{ argumentsPreview }}</pre>\n }\n @if (part().resultPreview; as resultPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <pre>{{ resultPreview }}</pre>\n } @else if (part().restricted) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <p class=\"restricted\">{{ 'nh-assistant.tool-call.restricted' | translate }}</p>\n }\n </div>\n }\n</article>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=failed]){--nha-status-color: var(--nha-danger);--nha-status-background: var(--nha-danger-soft)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=rejected]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .card{border-left-style:dashed}.card{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:8px 10px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;min-width:0}.status-icon{display:inline-flex;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.status{flex:none;border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:28px;height:28px}.toggle:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.toggle:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.toggle:disabled{cursor:not-allowed;opacity:.5}.rotated{transform:rotate(180deg)}.result-code{margin:6px 0 0;color:var(--nha-text-muted);font-size:12px}.details{margin-top:8px}.label{margin:8px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}pre{max-height:180px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}nh-assistant-icon{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}.grant{flex:none;padding:1px 6px;border:1px solid var(--nh-assistant-border, currentColor);border-radius:999px;font-size:.75em;opacity:.85}.restricted{margin:0;font-style:italic;opacity:.8}\n"] }]
|
|
13201
|
+
}, template: "<article class=\"card\" [attr.aria-label]=\"'nh-assistant.tool-call.label' | translate: { name: part().displayName }\">\n <header class=\"header\">\n <span class=\"status-icon\" [class.spinning]=\"part().status === 'running'\">\n <nh-assistant-icon [name]=\"statusIcon()\" />\n </span>\n <span class=\"title\">{{ part().displayName }}</span>\n @if (part().grantSource; as grantSource) {\n <span class=\"grant\" [attr.title]=\"'nh-assistant.tool-call.grant-source.' + grantSource + '-hint' | translate\">\n {{ 'nh-assistant.tool-call.grant-source.' + grantSource | translate }}\n </span>\n }\n <span class=\"status\">{{ 'nh-assistant.tool-call.status.' + part().status | translate }}</span>\n @if (hasDetails()) {\n <button\n class=\"toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"detailsId\"\n [attr.aria-label]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-call.hide-details' : 'nh-assistant.tool-call.show-details') | translate\"\n (click)=\"toggle()\">\n <nh-assistant-icon name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n }\n </header>\n\n @if (part().resultCode; as resultCode) {\n <p class=\"result-code\">\n {{ ['nh-assistant.result-codes.' + resultCode, 'nh-assistant.errors.' + resultCode] | nhAssistantTranslate: resultCode }}\n </p>\n }\n\n @if (hasDetails()) {\n <div class=\"details\" [id]=\"detailsId\" [hidden]=\"!expanded()\">\n <p class=\"label\">{{ 'nh-assistant.tool-call.tool-id' | translate }}</p>\n <code>{{ part().toolId }}</code>\n @if (part().argumentsPreview; as argumentsPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.arguments' | translate }}</p>\n <pre>{{ argumentsPreview }}</pre>\n }\n @if (part().resultPreview; as resultPreview) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <pre>{{ resultPreview }}</pre>\n } @else if (part().restricted) {\n <p class=\"label\">{{ 'nh-assistant.tool-call.result' | translate }}</p>\n <p class=\"restricted\">{{ 'nh-assistant.tool-call.restricted' | translate }}</p>\n }\n </div>\n }\n</article>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted);--nha-status-background: var(--nha-surface-strong)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success);--nha-status-background: var(--nha-success-soft)}:host([data-status=failed]){--nha-status-color: var(--nha-danger);--nha-status-background: var(--nha-danger-soft)}:host([data-status=awaiting-approval]),:host([data-status=awaiting-answer]){--nha-status-color: var(--nha-warning);--nha-status-background: var(--nha-warning-soft)}:host([data-status=rejected]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .card{border-left-style:dashed}.card{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);padding:8px 10px;color:var(--nha-text);background:var(--nha-background)}.header{display:flex;align-items:center;gap:8px;min-width:0}.status-icon{display:inline-flex;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.status{flex:none;border-radius:999px;padding:2px 8px;color:var(--nha-status-color);background:var(--nha-status-background);font-size:11px;font-weight:700}.toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;width:28px;height:28px}.toggle:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.toggle:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.toggle:disabled{cursor:not-allowed;opacity:.5}.rotated{transform:rotate(180deg)}.result-code{margin:6px 0 0;color:var(--nha-text-muted);font-size:12px}.details{margin-top:8px}.label{margin:8px 0 4px;color:var(--nha-text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}pre{max-height:180px;margin:0;overflow:auto;border-radius:8px;padding:8px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px;white-space:pre-wrap;word-break:break-word}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}nh-assistant-icon{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}.grant{flex:none;padding:1px 6px;border:1px solid var(--nh-assistant-border, currentColor);border-radius:999px;font-size:.75em;opacity:.85}.restricted{margin:0;font-style:italic;opacity:.8}\n"] }]
|
|
11654
13202
|
}], propDecorators: { part: [{ type: i0.Input, args: [{ isSignal: true, alias: "part", required: true }] }] } });
|
|
11655
13203
|
|
|
11656
13204
|
let nextId$2 = 0;
|
|
11657
13205
|
const stateIcons = {
|
|
11658
13206
|
'awaiting-approval': 'clock',
|
|
13207
|
+
'awaiting-answer': 'clock',
|
|
11659
13208
|
running: 'tool',
|
|
11660
13209
|
failed: 'warning',
|
|
11661
13210
|
'not-executed': 'stop',
|
|
@@ -11674,7 +13223,7 @@ class NhAssistantToolCallGroupComponent {
|
|
|
11674
13223
|
/** The call that currently needs attention or runs; the latest one when several do. */
|
|
11675
13224
|
this.current = computed(() => {
|
|
11676
13225
|
const calls = this.calls();
|
|
11677
|
-
return findLast(calls, call => call.status === 'awaiting-approval')
|
|
13226
|
+
return findLast(calls, call => call.status === 'awaiting-approval' || call.status === 'awaiting-answer')
|
|
11678
13227
|
?? findLast(calls, call => call.status === 'running')
|
|
11679
13228
|
?? null;
|
|
11680
13229
|
}, ...(ngDevMode ? [{ debugName: "current" }] : []));
|
|
@@ -11686,7 +13235,7 @@ class NhAssistantToolCallGroupComponent {
|
|
|
11686
13235
|
this.state = computed(() => {
|
|
11687
13236
|
const current = this.current();
|
|
11688
13237
|
if (current) {
|
|
11689
|
-
return current.status === 'awaiting-approval'
|
|
13238
|
+
return current.status === 'awaiting-approval' || current.status === 'awaiting-answer' ? current.status : 'running';
|
|
11690
13239
|
}
|
|
11691
13240
|
if (this.failed() > 0) {
|
|
11692
13241
|
return 'failed';
|
|
@@ -11699,16 +13248,16 @@ class NhAssistantToolCallGroupComponent {
|
|
|
11699
13248
|
this.expanded.update(expanded => !expanded);
|
|
11700
13249
|
}
|
|
11701
13250
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantToolCallGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11702
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantToolCallGroupComponent, isStandalone: true, selector: "nh-assistant-tool-call-group", inputs: { calls: { classPropertyName: "calls", publicName: "calls", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-status": "state()" } }, ngImport: i0, template: "<section class=\"group\">\n <button\n class=\"summary\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"callsId\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-group.hide-calls' : 'nh-assistant.tool-group.show-calls') | translate\"\n (click)=\"toggle()\">\n <span class=\"status-icon\" [class.spinning]=\"state() === 'running'\">\n <nh-assistant-icon [name]=\"stateIcon()\" />\n </span>\n <span class=\"title\">\n @switch (state()) {\n @case ('running') {\n {{ 'nh-assistant.tool-group.running' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-approval') {\n {{ 'nh-assistant.tool-group.awaiting-approval' | translate: { name: current()?.displayName } }}\n }\n @default {\n {{ (total() === 1 ? 'nh-assistant.tool-group.used-one' : 'nh-assistant.tool-group.used-many') | translate: { count: total() } }}\n }\n }\n </span>\n @if (state() === 'running' || state() === 'awaiting-approval') {\n <span class=\"count\">{{ 'nh-assistant.tool-group.progress' | translate: { finished: finished(), total: total() } }}</span>\n } @else {\n @if (failed() > 0) {\n <span class=\"count failed\">{{ 'nh-assistant.tool-group.failed' | translate: { count: failed() } }}</span>\n }\n @if (notExecuted() > 0) {\n <span class=\"count not-executed\">{{ 'nh-assistant.tool-group.not-executed' | translate: { count: notExecuted() } }}</span>\n }\n }\n <nh-assistant-icon class=\"chevron\" name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n\n <div class=\"calls\" [id]=\"callsId\" [hidden]=\"!expanded()\">\n @if (expanded()) {\n @for (call of calls(); track call.invocationId) {\n <nh-assistant-tool-call-card [part]=\"call\" />\n }\n }\n </div>\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success)}:host([data-status=failed]){--nha-status-color: var(--nha-danger)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .group{border-left-style:dashed}.group{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);color:var(--nha-text);background:var(--nha-background)}.summary{display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:40px;border:0;border-radius:var(--nha-radius-control);padding:8px 10px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.summary:hover{background:var(--nha-surface)}.status-icon{display:inline-flex;flex:none;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.count{flex:none;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.count.failed,.count.not-executed{border-radius:999px;padding:2px 8px;font-size:11px;font-weight:700}.count.failed{color:var(--nha-danger);background:var(--nha-danger-soft)}.count.not-executed{color:var(--nha-text-muted);background:var(--nha-surface-strong)}.chevron{flex:none;color:var(--nha-text-muted)}.rotated{transform:rotate(180deg)}.calls{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--nha-border);padding:8px}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}.chevron{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantToolCallCardComponent, selector: "nh-assistant-tool-call-card", inputs: ["part"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
13251
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantToolCallGroupComponent, isStandalone: true, selector: "nh-assistant-tool-call-group", inputs: { calls: { classPropertyName: "calls", publicName: "calls", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-status": "state()" } }, ngImport: i0, template: "<section class=\"group\">\n <button\n class=\"summary\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"callsId\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-group.hide-calls' : 'nh-assistant.tool-group.show-calls') | translate\"\n (click)=\"toggle()\">\n <span class=\"status-icon\" [class.spinning]=\"state() === 'running'\">\n <nh-assistant-icon [name]=\"stateIcon()\" />\n </span>\n <span class=\"title\">\n @switch (state()) {\n @case ('running') {\n {{ 'nh-assistant.tool-group.running' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-approval') {\n {{ 'nh-assistant.tool-group.awaiting-approval' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-answer') {\n {{ 'nh-assistant.tool-group.awaiting-answer' | translate }}\n }\n @default {\n {{ (total() === 1 ? 'nh-assistant.tool-group.used-one' : 'nh-assistant.tool-group.used-many') | translate: { count: total() } }}\n }\n }\n </span>\n @if (state() === 'running' || state() === 'awaiting-approval' || state() === 'awaiting-answer') {\n <span class=\"count\">{{ 'nh-assistant.tool-group.progress' | translate: { finished: finished(), total: total() } }}</span>\n } @else {\n @if (failed() > 0) {\n <span class=\"count failed\">{{ 'nh-assistant.tool-group.failed' | translate: { count: failed() } }}</span>\n }\n @if (notExecuted() > 0) {\n <span class=\"count not-executed\">{{ 'nh-assistant.tool-group.not-executed' | translate: { count: notExecuted() } }}</span>\n }\n }\n <nh-assistant-icon class=\"chevron\" name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n\n <div class=\"calls\" [id]=\"callsId\" [hidden]=\"!expanded()\">\n @if (expanded()) {\n @for (call of calls(); track call.invocationId) {\n <nh-assistant-tool-call-card [part]=\"call\" />\n }\n }\n </div>\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success)}:host([data-status=failed]){--nha-status-color: var(--nha-danger)}:host([data-status=awaiting-approval]),:host([data-status=awaiting-answer]){--nha-status-color: var(--nha-warning)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .group{border-left-style:dashed}.group{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);color:var(--nha-text);background:var(--nha-background)}.summary{display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:40px;border:0;border-radius:var(--nha-radius-control);padding:8px 10px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.summary:hover{background:var(--nha-surface)}.status-icon{display:inline-flex;flex:none;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.count{flex:none;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.count.failed,.count.not-executed{border-radius:999px;padding:2px 8px;font-size:11px;font-weight:700}.count.failed{color:var(--nha-danger);background:var(--nha-danger-soft)}.count.not-executed{color:var(--nha-text-muted);background:var(--nha-surface-strong)}.chevron{flex:none;color:var(--nha-text-muted)}.rotated{transform:rotate(180deg)}.calls{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--nha-border);padding:8px}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}.chevron{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"], dependencies: [{ kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantToolCallCardComponent, selector: "nh-assistant-tool-call-card", inputs: ["part"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11703
13252
|
}
|
|
11704
13253
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantToolCallGroupComponent, decorators: [{
|
|
11705
13254
|
type: Component,
|
|
11706
13255
|
args: [{ selector: 'nh-assistant-tool-call-group', standalone: true, imports: [TranslatePipe, NhAssistantIconComponent, NhAssistantToolCallCardComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
11707
13256
|
'[attr.data-status]': 'state()'
|
|
11708
|
-
}, template: "<section class=\"group\">\n <button\n class=\"summary\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"callsId\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-group.hide-calls' : 'nh-assistant.tool-group.show-calls') | translate\"\n (click)=\"toggle()\">\n <span class=\"status-icon\" [class.spinning]=\"state() === 'running'\">\n <nh-assistant-icon [name]=\"stateIcon()\" />\n </span>\n <span class=\"title\">\n @switch (state()) {\n @case ('running') {\n {{ 'nh-assistant.tool-group.running' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-approval') {\n {{ 'nh-assistant.tool-group.awaiting-approval' | translate: { name: current()?.displayName } }}\n }\n @default {\n {{ (total() === 1 ? 'nh-assistant.tool-group.used-one' : 'nh-assistant.tool-group.used-many') | translate: { count: total() } }}\n }\n }\n </span>\n @if (state() === 'running' || state() === 'awaiting-approval') {\n <span class=\"count\">{{ 'nh-assistant.tool-group.progress' | translate: { finished: finished(), total: total() } }}</span>\n } @else {\n @if (failed() > 0) {\n <span class=\"count failed\">{{ 'nh-assistant.tool-group.failed' | translate: { count: failed() } }}</span>\n }\n @if (notExecuted() > 0) {\n <span class=\"count not-executed\">{{ 'nh-assistant.tool-group.not-executed' | translate: { count: notExecuted() } }}</span>\n }\n }\n <nh-assistant-icon class=\"chevron\" name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n\n <div class=\"calls\" [id]=\"callsId\" [hidden]=\"!expanded()\">\n @if (expanded()) {\n @for (call of calls(); track call.invocationId) {\n <nh-assistant-tool-call-card [part]=\"call\" />\n }\n }\n </div>\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success)}:host([data-status=failed]){--nha-status-color: var(--nha-danger)}:host([data-status=awaiting-approval]){--nha-status-color: var(--nha-warning)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .group{border-left-style:dashed}.group{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);color:var(--nha-text);background:var(--nha-background)}.summary{display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:40px;border:0;border-radius:var(--nha-radius-control);padding:8px 10px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.summary:hover{background:var(--nha-surface)}.status-icon{display:inline-flex;flex:none;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.count{flex:none;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.count.failed,.count.not-executed{border-radius:999px;padding:2px 8px;font-size:11px;font-weight:700}.count.failed{color:var(--nha-danger);background:var(--nha-danger-soft)}.count.not-executed{color:var(--nha-text-muted);background:var(--nha-surface-strong)}.chevron{flex:none;color:var(--nha-text-muted)}.rotated{transform:rotate(180deg)}.calls{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--nha-border);padding:8px}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}.chevron{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"] }]
|
|
13257
|
+
}, template: "<section class=\"group\">\n <button\n class=\"summary\"\n type=\"button\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"callsId\"\n [attr.title]=\"(expanded() ? 'nh-assistant.tool-group.hide-calls' : 'nh-assistant.tool-group.show-calls') | translate\"\n (click)=\"toggle()\">\n <span class=\"status-icon\" [class.spinning]=\"state() === 'running'\">\n <nh-assistant-icon [name]=\"stateIcon()\" />\n </span>\n <span class=\"title\">\n @switch (state()) {\n @case ('running') {\n {{ 'nh-assistant.tool-group.running' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-approval') {\n {{ 'nh-assistant.tool-group.awaiting-approval' | translate: { name: current()?.displayName } }}\n }\n @case ('awaiting-answer') {\n {{ 'nh-assistant.tool-group.awaiting-answer' | translate }}\n }\n @default {\n {{ (total() === 1 ? 'nh-assistant.tool-group.used-one' : 'nh-assistant.tool-group.used-many') | translate: { count: total() } }}\n }\n }\n </span>\n @if (state() === 'running' || state() === 'awaiting-approval' || state() === 'awaiting-answer') {\n <span class=\"count\">{{ 'nh-assistant.tool-group.progress' | translate: { finished: finished(), total: total() } }}</span>\n } @else {\n @if (failed() > 0) {\n <span class=\"count failed\">{{ 'nh-assistant.tool-group.failed' | translate: { count: failed() } }}</span>\n }\n @if (notExecuted() > 0) {\n <span class=\"count not-executed\">{{ 'nh-assistant.tool-group.not-executed' | translate: { count: notExecuted() } }}</span>\n }\n }\n <nh-assistant-icon class=\"chevron\" name=\"chevron-down\" [class.rotated]=\"expanded()\" />\n </button>\n\n <div class=\"calls\" [id]=\"callsId\" [hidden]=\"!expanded()\">\n @if (expanded()) {\n @for (call of calls(); track call.invocationId) {\n <nh-assistant-tool-call-card [part]=\"call\" />\n }\n }\n </div>\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:block;font:inherit;--nha-status-color: var(--nha-text-muted)}:host([data-status=succeeded]){--nha-status-color: var(--nha-success)}:host([data-status=failed]){--nha-status-color: var(--nha-danger)}:host([data-status=awaiting-approval]),:host([data-status=awaiting-answer]){--nha-status-color: var(--nha-warning)}:host([data-status=not-executed]){--nha-status-color: var(--nha-text-muted)}:host([data-status=not-executed]) .group{border-left-style:dashed}.group{border:1px solid var(--nha-border);border-left:3px solid var(--nha-status-color);border-radius:var(--nha-radius-control);color:var(--nha-text);background:var(--nha-background)}.summary{display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:40px;border:0;border-radius:var(--nha-radius-control);padding:8px 10px;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.summary:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.summary:hover{background:var(--nha-surface)}.status-icon{display:inline-flex;flex:none;color:var(--nha-status-color)}.title{flex:1;min-width:0;overflow:hidden;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.count{flex:none;color:var(--nha-text-muted);font-size:12px;font-variant-numeric:tabular-nums}.count.failed,.count.not-executed{border-radius:999px;padding:2px 8px;font-size:11px;font-weight:700}.count.failed{color:var(--nha-danger);background:var(--nha-danger-soft)}.count.not-executed{color:var(--nha-text-muted);background:var(--nha-surface-strong)}.chevron{flex:none;color:var(--nha-text-muted)}.rotated{transform:rotate(180deg)}.calls{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--nha-border);padding:8px}@media(prefers-reduced-motion:no-preference){.spinning{animation:nha-pulse 1.2s ease-in-out infinite}.chevron{transition:transform .16s ease}}@keyframes nha-pulse{50%{opacity:.35}}\n"] }]
|
|
11709
13258
|
}], propDecorators: { calls: [{ type: i0.Input, args: [{ isSignal: true, alias: "calls", required: true }] }] } });
|
|
11710
13259
|
function isActive(call) {
|
|
11711
|
-
return call.status === 'running' || call.status === 'awaiting-approval';
|
|
13260
|
+
return call.status === 'running' || call.status === 'awaiting-approval' || call.status === 'awaiting-answer';
|
|
11712
13261
|
}
|
|
11713
13262
|
function findLast(calls, predicate) {
|
|
11714
13263
|
for (let index = calls.length - 1; index >= 0; index--) {
|
|
@@ -11791,6 +13340,13 @@ class NhAssistantThreadComponent {
|
|
|
11791
13340
|
this.approvalDecision = output();
|
|
11792
13341
|
/** The decision about an approval card together with its approval id. */
|
|
11793
13342
|
this.approvalChoice = output();
|
|
13343
|
+
/** How the user resolves an uncertain hand-off they approved in this chat, with its approval id. */
|
|
13344
|
+
this.approvalResolution = output();
|
|
13345
|
+
/**
|
|
13346
|
+
* The answer the user chose for a question addressed to them, for example for
|
|
13347
|
+
* `NhAssistantStore.answerQuestion`. Only the addressee of a pending question gets choice buttons.
|
|
13348
|
+
*/
|
|
13349
|
+
this.questionAnswer = output();
|
|
11794
13350
|
/**
|
|
11795
13351
|
* The question to ask again after the viewer connected an MCP server from a connection card: the
|
|
11796
13352
|
* text of the user message the card answered. The panel sends it.
|
|
@@ -11817,7 +13373,8 @@ class NhAssistantThreadComponent {
|
|
|
11817
13373
|
const lastPart = last.parts[last.parts.length - 1];
|
|
11818
13374
|
return lastPart.type === 'tool-call'
|
|
11819
13375
|
&& lastPart.status !== 'running'
|
|
11820
|
-
&& lastPart.status !== 'awaiting-approval'
|
|
13376
|
+
&& lastPart.status !== 'awaiting-approval'
|
|
13377
|
+
&& lastPart.status !== 'awaiting-answer';
|
|
11821
13378
|
}, ...(ngDevMode ? [{ debugName: "working" }] : []));
|
|
11822
13379
|
/**
|
|
11823
13380
|
* The message in whose row the working indicator shows: the answer `writingMessageId` names.
|
|
@@ -11901,6 +13458,21 @@ class NhAssistantThreadComponent {
|
|
|
11901
13458
|
this.approvalDecision.emit(decision);
|
|
11902
13459
|
this.approvalChoice.emit({ approvalId: approval.approvalId, decision });
|
|
11903
13460
|
}
|
|
13461
|
+
resolveApproval(approval, resolution) {
|
|
13462
|
+
this.approvalResolution.emit({ approvalId: approval.approvalId, resolution });
|
|
13463
|
+
}
|
|
13464
|
+
/** Whether the current user may answer the question: it waits and is addressed to them. */
|
|
13465
|
+
canAnswer(question) {
|
|
13466
|
+
const currentActorId = this.currentActorId();
|
|
13467
|
+
return question.status === 'pending' && !!currentActorId && question.addresseeActorId === currentActorId;
|
|
13468
|
+
}
|
|
13469
|
+
/** The name of the person a question is addressed to, or `null` when the application provides none. */
|
|
13470
|
+
addresseeName(question) {
|
|
13471
|
+
return this.names().get(question.addresseeActorId) ?? null;
|
|
13472
|
+
}
|
|
13473
|
+
answerQuestion(question, choice) {
|
|
13474
|
+
this.questionAnswer.emit({ questionId: question.questionId, choice });
|
|
13475
|
+
}
|
|
11904
13476
|
/** Display name of another person's message, or `null` when the application provides none. */
|
|
11905
13477
|
authorName(message) {
|
|
11906
13478
|
return message.authorActorId ? this.names().get(message.authorActorId) ?? null : null;
|
|
@@ -11921,7 +13493,7 @@ class NhAssistantThreadComponent {
|
|
|
11921
13493
|
}
|
|
11922
13494
|
}
|
|
11923
13495
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantThreadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11924
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantThreadComponent, isStandalone: true, selector: "nh-assistant-thread", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, deciding: { classPropertyName: "deciding", publicName: "deciding", isSignal: true, isRequired: false, transformFunction: null }, markdown: { classPropertyName: "markdown", publicName: "markdown", isSignal: true, isRequired: false, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: false, transformFunction: null }, currentActorId: { classPropertyName: "currentActorId", publicName: "currentActorId", isSignal: true, isRequired: false, transformFunction: null }, canDecide: { classPropertyName: "canDecide", publicName: "canDecide", isSignal: true, isRequired: false, transformFunction: null }, decisionOwner: { classPropertyName: "decisionOwner", publicName: "decisionOwner", isSignal: true, isRequired: false, transformFunction: null }, approvalRights: { classPropertyName: "approvalRights", publicName: "approvalRights", isSignal: true, isRequired: false, transformFunction: null }, writingMessageId: { classPropertyName: "writingMessageId", publicName: "writingMessageId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalDecision: "approvalDecision", approvalChoice: "approvalChoice", retryMessage: "retryMessage" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true, isSignal: true }, { propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n <!-- The answer a turn still writes (writingMessageId) keeps the indicator under it, also when messages arrived after it. -->\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article\n class=\"message\"\n [attr.data-role]=\"message.role\"\n [attr.data-others]=\"isOthers(message) ? 'true' : null\"\n [attr.data-author]=\"isTrigger(message) ? 'trigger' : isRule(message) ? 'rule' : isApplication(message) ? 'application' : null\"\n [attr.aria-label]=\"isApplication(message) ? ('nh-assistant.thread.application-label' | translate) : null\">\n @if (isTrigger(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.trigger' | translate }}</p>\n } @else if (isRule(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.rule' | translate }}</p>\n } @else if (isApplication(message)) {\n <!-- The application's message reads as the application's, also when it names who in the application posted it. -->\n <p class=\"author\">\n <nh-assistant-icon class=\"author-icon\" name=\"bell\" />\n @if (message.application?.senderName; as sender) {\n <!-- The space keeps the sender and the tag apart for screen readers; the flex gap shows it. -->\n <span>{{ sender }}</span>{{ ' ' }}<span class=\"tag\">{{ 'nh-assistant.thread.application' | translate }}</span>\n } @else {\n <span>{{ 'nh-assistant.thread.application' | translate }}</span>\n }\n @if (message.application?.trusted) {\n <!-- People see which of the application's messages the assistant follows as an instruction. -->\n {{ ' ' }}<span class=\"tag trusted\">{{ 'nh-assistant.thread.application-trusted' | translate }}</span>\n }\n </p>\n @if (message.application?.title; as title) {\n <p class=\"application-title\">{{ title }}</p>\n }\n } @else if (isOthers(message)) {\n <p class=\"author\">{{ authorName(message) ?? ('nh-assistant.thread.participant' | translate) }}</p>\n } @else {\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n }\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if ((message.role === 'assistant' || isApplication(message)) && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('files') {\n <ul class=\"files\" [attr.aria-label]=\"'nh-assistant.thread.files' | translate\">\n @for (file of group.files; track $index) {\n <li class=\"file\">\n <nh-assistant-icon class=\"file-icon\" name=\"file\" />\n <span class=\"file-name\" [attr.title]=\"file.name\">{{ file.name }}</span>\n <span class=\"file-meta\">{{ 'nh-assistant.thread.file-meta' | translate: fileMeta(file) }}</span>\n </li>\n }\n </ul>\n }\n @case ('connection') {\n <nh-assistant-connection-required\n class=\"part\"\n [part]=\"group.part\"\n [canRetry]=\"!streaming()\"\n (retry)=\"retryAfterConnect(message)\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card\n class=\"part\"\n [approval]=\"group.part\"\n [deciding]=\"deciding()\"\n [canDecide]=\"rightFor(group.part).canDecide\"\n [decisionOwner]=\"rightFor(group.part).decisionOwner\"\n [waitingFor]=\"rightFor(group.part).waitingFor\"\n [canGiveFeedback]=\"rightFor(group.part).canGiveFeedback === true\"\n (decide)=\"choose(group.part, $event)\" />\n }\n }\n }\n @if (isApplication(message) && message.application?.link; as link) {\n <nh-assistant-message-link\n class=\"application-link\"\n [url]=\"link.url\"\n [label]=\"link.label || ('nh-assistant.thread.application-link' | translate)\" />\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:20px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:600}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-others=true]{align-items:flex-start}.message[data-others=true] .bubble{color:var(--nha-text);background:var(--nha-surface-strong)}.message[data-author=trigger]{align-items:stretch}.message[data-author=trigger] .bubble{max-width:none;color:var(--nha-text-muted);background:transparent;border:1px dashed var(--nha-border)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{padding-inline:0;background:transparent}.part{width:100%}.files{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;max-width:88%;min-width:0;margin:0;padding:0;list-style:none}.message:not([data-role=user]) .files,.message[data-others=true] .files{justify-content:flex-start}.file{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 10px;color:var(--nha-text);background:var(--nha-surface);font-size:12px}.file-icon{flex-shrink:0;color:var(--nha-text-muted)}.file-name{min-width:0;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.file-meta{flex-shrink:0;color:var(--nha-text-muted);white-space:nowrap}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown hr{margin:12px 0;border:0;border-top:1px solid var(--nha-border)}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}.message[data-author=application]{align-items:stretch;border-left:3px solid var(--nha-accent);border-radius:var(--nha-radius-control);padding:8px 12px;background:var(--nha-surface-strong)}.message[data-author=application] .author{display:flex;align-items:center;gap:6px}.message[data-author=application] .author-icon{color:var(--nha-accent)}.message[data-author=application] .tag{border:1px solid var(--nha-border);border-radius:999px;padding:0 6px;color:var(--nha-text-muted);font-weight:500}.message[data-author=application] .application-title{margin:0;color:var(--nha-text);font-size:14px;font-weight:600}.message[data-author=application] .bubble{max-width:none;padding:0;color:var(--nha-text);background:transparent}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantMessageLinkComponent, selector: "nh-assistant-message-link", inputs: ["url", "label"] }, { kind: "component", type: NhAssistantToolCallGroupComponent, selector: "nh-assistant-tool-call-group", inputs: ["calls"] }, { kind: "component", type: NhAssistantApprovalCardComponent, selector: "nh-assistant-approval-card", inputs: ["approval", "deciding", "canDecide", "decisionOwner", "waitingFor", "canGiveFeedback"], outputs: ["decide"] }, { kind: "component", type: NhAssistantConnectionRequiredComponent, selector: "nh-assistant-connection-required", inputs: ["part", "canRetry"], outputs: ["retry"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantMarkdownPipe, name: "nhAssistantMarkdown" }, { kind: "pipe", type: NhAssistantPartGroupsPipe, name: "nhAssistantPartGroups" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
13496
|
+
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", approvalResolution: "approvalResolution", questionAnswer: "questionAnswer", 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 (resolve)=\"resolveApproval(group.part, $event)\" />\n }\n @case ('question') {\n <nh-assistant-question-card\n class=\"part\"\n [question]=\"group.part\"\n [canAnswer]=\"canAnswer(group.part)\"\n [addresseeName]=\"addresseeName(group.part)\"\n [answering]=\"deciding()\"\n (answer)=\"answerQuestion(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", "resolve"] }, { kind: "component", type: NhAssistantConnectionRequiredComponent, selector: "nh-assistant-connection-required", inputs: ["part", "canRetry"], outputs: ["retry"] }, { kind: "component", type: NhAssistantQuestionCardComponent, selector: "nh-assistant-question-card", inputs: ["question", "canAnswer", "addresseeName", "answering"], outputs: ["answer"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantMarkdownPipe, name: "nhAssistantMarkdown" }, { kind: "pipe", type: NhAssistantPartGroupsPipe, name: "nhAssistantPartGroups" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11925
13497
|
}
|
|
11926
13498
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantThreadComponent, decorators: [{
|
|
11927
13499
|
type: Component,
|
|
@@ -11935,9 +13507,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
11935
13507
|
NhAssistantPartGroupsPipe,
|
|
11936
13508
|
NhAssistantToolCallGroupComponent,
|
|
11937
13509
|
NhAssistantApprovalCardComponent,
|
|
11938
|
-
NhAssistantConnectionRequiredComponent
|
|
11939
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"log\" role=\"log\" aria-live=\"polite\" [attr.aria-label]=\"'nh-assistant.thread.label' | translate\" [attr.aria-busy]=\"streaming()\">\n @if (virtual()) {\n <cdk-virtual-scroll-viewport class=\"scroller\" itemSize=\"120\" minBufferPx=\"1200\" maxBufferPx=\"2400\">\n <div class=\"row\" *cdkVirtualFor=\"let message of messages(); trackBy: trackMessage\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </cdk-virtual-scroll-viewport>\n } @else {\n <div class=\"scroller\" #scroller tabindex=\"0\">\n @for (message of messages(); track message.id) {\n <div class=\"row\">\n <ng-container [ngTemplateOutlet]=\"messageTemplate\" [ngTemplateOutletContext]=\"{ $implicit: message }\" />\n <!-- The answer a turn still writes (writingMessageId) keeps the indicator under it, also when messages arrived after it. -->\n @if (working() && message.id === workingAfterId()) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n @if (working() && workingAfterId() === null) {\n <ng-container [ngTemplateOutlet]=\"workingTemplate\" />\n }\n </div>\n }\n</div>\n\n<ng-template #messageTemplate let-message>\n <article\n class=\"message\"\n [attr.data-role]=\"message.role\"\n [attr.data-others]=\"isOthers(message) ? 'true' : null\"\n [attr.data-author]=\"isTrigger(message) ? 'trigger' : isRule(message) ? 'rule' : isApplication(message) ? 'application' : null\"\n [attr.aria-label]=\"isApplication(message) ? ('nh-assistant.thread.application-label' | translate) : null\">\n @if (isTrigger(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.trigger' | translate }}</p>\n } @else if (isRule(message)) {\n <p class=\"author\">{{ 'nh-assistant.thread.rule' | translate }}</p>\n } @else if (isApplication(message)) {\n <!-- The application's message reads as the application's, also when it names who in the application posted it. -->\n <p class=\"author\">\n <nh-assistant-icon class=\"author-icon\" name=\"bell\" />\n @if (message.application?.senderName; as sender) {\n <!-- The space keeps the sender and the tag apart for screen readers; the flex gap shows it. -->\n <span>{{ sender }}</span>{{ ' ' }}<span class=\"tag\">{{ 'nh-assistant.thread.application' | translate }}</span>\n } @else {\n <span>{{ 'nh-assistant.thread.application' | translate }}</span>\n }\n @if (message.application?.trusted) {\n <!-- People see which of the application's messages the assistant follows as an instruction. -->\n {{ ' ' }}<span class=\"tag trusted\">{{ 'nh-assistant.thread.application-trusted' | translate }}</span>\n }\n </p>\n @if (message.application?.title; as title) {\n <p class=\"application-title\">{{ title }}</p>\n }\n } @else if (isOthers(message)) {\n <p class=\"author\">{{ authorName(message) ?? ('nh-assistant.thread.participant' | translate) }}</p>\n } @else {\n <p class=\"author\">{{ 'nh-assistant.thread.' + (message.role === 'user' ? 'you' : message.role) | translate }}</p>\n }\n @for (group of message.parts | nhAssistantPartGroups; track group.key) {\n @switch (group.kind) {\n @case ('text') {\n @if ((message.role === 'assistant' || isApplication(message)) && markdown()) {\n <div class=\"bubble markdown\" [innerHTML]=\"group.part.text | nhAssistantMarkdown\"></div>\n } @else {\n <div class=\"bubble plain\">{{ group.part.text }}</div>\n }\n }\n @case ('tools') {\n <nh-assistant-tool-call-group class=\"part\" [calls]=\"group.calls\" />\n }\n @case ('files') {\n <ul class=\"files\" [attr.aria-label]=\"'nh-assistant.thread.files' | translate\">\n @for (file of group.files; track $index) {\n <li class=\"file\">\n <nh-assistant-icon class=\"file-icon\" name=\"file\" />\n <span class=\"file-name\" [attr.title]=\"file.name\">{{ file.name }}</span>\n <span class=\"file-meta\">{{ 'nh-assistant.thread.file-meta' | translate: fileMeta(file) }}</span>\n </li>\n }\n </ul>\n }\n @case ('connection') {\n <nh-assistant-connection-required\n class=\"part\"\n [part]=\"group.part\"\n [canRetry]=\"!streaming()\"\n (retry)=\"retryAfterConnect(message)\" />\n }\n @case ('approval') {\n <nh-assistant-approval-card\n class=\"part\"\n [approval]=\"group.part\"\n [deciding]=\"deciding()\"\n [canDecide]=\"rightFor(group.part).canDecide\"\n [decisionOwner]=\"rightFor(group.part).decisionOwner\"\n [waitingFor]=\"rightFor(group.part).waitingFor\"\n [canGiveFeedback]=\"rightFor(group.part).canGiveFeedback === true\"\n (decide)=\"choose(group.part, $event)\" />\n }\n }\n }\n @if (isApplication(message) && message.application?.link; as link) {\n <nh-assistant-message-link\n class=\"application-link\"\n [url]=\"link.url\"\n [label]=\"link.label || ('nh-assistant.thread.application-link' | translate)\" />\n }\n </article>\n</ng-template>\n\n<ng-template #workingTemplate>\n <p class=\"working\" role=\"status\">\n <span class=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></span>\n {{ 'nh-assistant.thread.working' | translate }}\n @if (elapsedSeconds() > 0) {\n <span class=\"elapsed\">{{ 'nh-assistant.thread.elapsed' | translate: { seconds: elapsedSeconds() } }}</span>\n }\n </p>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:flex;flex-direction:column;min-height:0;color:var(--nha-text)}.log{display:flex;flex:1;flex-direction:column;min-height:0}.scroller{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px;outline:none}.scroller:focus-visible{box-shadow:inset 0 0 0 2px var(--nha-focus)}cdk-virtual-scroll-viewport.scroller{height:100%}.row+.row{margin-top:20px}.message{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0}.message[data-role=user]{align-items:flex-end}.author{margin:0;color:var(--nha-text-muted);font-size:11px;font-weight:600}.bubble{max-width:100%;border-radius:var(--nha-radius-control);padding:8px 12px;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.plain{white-space:pre-wrap}.message[data-role=user] .bubble{max-width:88%;color:var(--nha-user-text);background:var(--nha-user-bubble)}.message[data-others=true]{align-items:flex-start}.message[data-others=true] .bubble{color:var(--nha-text);background:var(--nha-surface-strong)}.message[data-author=trigger]{align-items:stretch}.message[data-author=trigger] .bubble{max-width:none;color:var(--nha-text-muted);background:transparent;border:1px dashed var(--nha-border)}.message[data-role=assistant] .bubble,.message[data-role=tool] .bubble{padding-inline:0;background:transparent}.part{width:100%}.files{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;max-width:88%;min-width:0;margin:0;padding:0;list-style:none}.message:not([data-role=user]) .files,.message[data-others=true] .files{justify-content:flex-start}.file{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:4px 10px;color:var(--nha-text);background:var(--nha-surface);font-size:12px}.file-icon{flex-shrink:0;color:var(--nha-text-muted)}.file-name{min-width:0;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.file-meta{flex-shrink:0;color:var(--nha-text-muted);white-space:nowrap}:host ::ng-deep .markdown :first-child{margin-top:0}:host ::ng-deep .markdown :last-child{margin-bottom:0}:host ::ng-deep .markdown p,:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol,:host ::ng-deep .markdown pre,:host ::ng-deep .markdown blockquote,:host ::ng-deep .markdown table{margin:0 0 8px}:host ::ng-deep .markdown ul,:host ::ng-deep .markdown ol{padding-left:20px}:host ::ng-deep .markdown h1,:host ::ng-deep .markdown h2,:host ::ng-deep .markdown h3,:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{margin:10px 0 6px;font-size:15px;line-height:1.3}:host ::ng-deep .markdown hr{margin:12px 0;border:0;border-top:1px solid var(--nha-border)}:host ::ng-deep .markdown a{color:var(--nha-highlight);text-decoration:underline}:host ::ng-deep .markdown a:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}:host ::ng-deep .markdown code{border-radius:6px;padding:1px 4px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}:host ::ng-deep .markdown pre{overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong)}:host ::ng-deep .markdown pre code{padding:0;background:none}:host ::ng-deep .markdown blockquote{border-left:3px solid var(--nha-border);padding-left:10px;color:var(--nha-text-muted)}:host ::ng-deep .markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:13px}:host ::ng-deep .markdown th,:host ::ng-deep .markdown td{border:1px solid var(--nha-border);padding:4px 8px;text-align:left}.working{display:flex;align-items:center;gap:8px;margin:14px 0 0;color:var(--nha-text-muted);font-size:13px}.elapsed{font-variant-numeric:tabular-nums}.dots{display:inline-flex;gap:3px}.dots span{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.6}@media(prefers-reduced-motion:no-preference){.dots span{animation:nha-bounce 1s ease-in-out infinite}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}}@keyframes nha-bounce{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-3px);opacity:1}}.message[data-author=application]{align-items:stretch;border-left:3px solid var(--nha-accent);border-radius:var(--nha-radius-control);padding:8px 12px;background:var(--nha-surface-strong)}.message[data-author=application] .author{display:flex;align-items:center;gap:6px}.message[data-author=application] .author-icon{color:var(--nha-accent)}.message[data-author=application] .tag{border:1px solid var(--nha-border);border-radius:999px;padding:0 6px;color:var(--nha-text-muted);font-weight:500}.message[data-author=application] .application-title{margin:0;color:var(--nha-text);font-size:14px;font-weight:600}.message[data-author=application] .bubble{max-width:none;padding:0;color:var(--nha-text);background:transparent}\n"] }]
|
|
11940
|
-
}], ctorParameters: () => [], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], deciding: [{ type: i0.Input, args: [{ isSignal: true, alias: "deciding", required: false }] }], markdown: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdown", required: false }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: false }] }], currentActorId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentActorId", required: false }] }], canDecide: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDecide", required: false }] }], decisionOwner: [{ type: i0.Input, args: [{ isSignal: true, alias: "decisionOwner", required: false }] }], approvalRights: [{ type: i0.Input, args: [{ isSignal: true, alias: "approvalRights", required: false }] }], writingMessageId: [{ type: i0.Input, args: [{ isSignal: true, alias: "writingMessageId", required: false }] }], approvalDecision: [{ type: i0.Output, args: ["approvalDecision"] }], approvalChoice: [{ type: i0.Output, args: ["approvalChoice"] }], retryMessage: [{ type: i0.Output, args: ["retryMessage"] }], scroller: [{ type: i0.ViewChild, args: ['scroller', { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }] } });
|
|
13510
|
+
NhAssistantConnectionRequiredComponent,
|
|
13511
|
+
NhAssistantQuestionCardComponent
|
|
13512
|
+
], 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 (resolve)=\"resolveApproval(group.part, $event)\" />\n }\n @case ('question') {\n <nh-assistant-question-card\n class=\"part\"\n [question]=\"group.part\"\n [canAnswer]=\"canAnswer(group.part)\"\n [addresseeName]=\"addresseeName(group.part)\"\n [answering]=\"deciding()\"\n (answer)=\"answerQuestion(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"] }]
|
|
13513
|
+
}], 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"] }], approvalResolution: [{ type: i0.Output, args: ["approvalResolution"] }], questionAnswer: [{ type: i0.Output, args: ["questionAnswer"] }], retryMessage: [{ type: i0.Output, args: ["retryMessage"] }], scroller: [{ type: i0.ViewChild, args: ['scroller', { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }] } });
|
|
11941
13514
|
|
|
11942
13515
|
let nextId$1 = 0;
|
|
11943
13516
|
/**
|
|
@@ -11986,8 +13559,23 @@ class NhAssistantPanelComponent {
|
|
|
11986
13559
|
if (this.store.streaming() || this.conversation()?.status === 'running') {
|
|
11987
13560
|
return 'running';
|
|
11988
13561
|
}
|
|
11989
|
-
|
|
13562
|
+
if (this.conversation()?.status !== 'waiting-for-approval') {
|
|
13563
|
+
return null;
|
|
13564
|
+
}
|
|
13565
|
+
// A turn that asked a question waits for its answer, not for an approval.
|
|
13566
|
+
return this.conversation()?.pendingQuestion ? 'waiting-for-answer' : 'waiting-for-approval';
|
|
11990
13567
|
}, ...(ngDevMode ? [{ debugName: "composerStatus" }] : []));
|
|
13568
|
+
/**
|
|
13569
|
+
* Who the composer says the conversation waits for, when it is someone else: the addressee of a
|
|
13570
|
+
* pending question, otherwise the person whose turn waits.
|
|
13571
|
+
*/
|
|
13572
|
+
this.composerStatusActor = computed(() => {
|
|
13573
|
+
if (this.composerStatus() === 'waiting-for-answer') {
|
|
13574
|
+
const addressee = this.store.questionAddressee();
|
|
13575
|
+
return addressee ? addressee.displayName ?? '' : null;
|
|
13576
|
+
}
|
|
13577
|
+
return this.activeMemberName();
|
|
13578
|
+
}, ...(ngDevMode ? [{ debugName: "composerStatusActor" }] : []));
|
|
11991
13579
|
/** Name of another participant whose turn runs or waits, or `null`. */
|
|
11992
13580
|
this.activeMemberName = computed(() => {
|
|
11993
13581
|
const member = this.store.activeMember();
|
|
@@ -12126,7 +13714,9 @@ class NhAssistantPanelComponent {
|
|
|
12126
13714
|
}
|
|
12127
13715
|
/**
|
|
12128
13716
|
* Opens the panel for an invitation link or a clicked notification in the URL fragment and
|
|
12129
|
-
* removes the fragment, so a reload or a shared screenshot does not reuse the token.
|
|
13717
|
+
* removes the fragment, so a reload or a shared screenshot does not reuse the token. A clicked
|
|
13718
|
+
* notification about the proposals of a run goes to `NhAssistantPushService.openRun$` while the
|
|
13719
|
+
* application subscribes, and otherwise opens its conversation.
|
|
12130
13720
|
*/
|
|
12131
13721
|
openFromLocation() {
|
|
12132
13722
|
const location = globalThis.location;
|
|
@@ -12134,7 +13724,7 @@ class NhAssistantPanelComponent {
|
|
|
12134
13724
|
const separatorIndex = hash.indexOf('=');
|
|
12135
13725
|
const name = separatorIndex < 0 ? hash : hash.slice(0, separatorIndex);
|
|
12136
13726
|
const value = separatorIndex < 0 ? '' : hash.slice(separatorIndex + 1);
|
|
12137
|
-
if (!value || (name !== NH_ASSISTANT_JOIN_FRAGMENT && name !== NH_ASSISTANT_CONVERSATION_FRAGMENT)) {
|
|
13727
|
+
if (!value || (name !== NH_ASSISTANT_JOIN_FRAGMENT && name !== NH_ASSISTANT_CONVERSATION_FRAGMENT && name !== NH_ASSISTANT_RUN_FRAGMENT)) {
|
|
12138
13728
|
return;
|
|
12139
13729
|
}
|
|
12140
13730
|
globalThis.history?.replaceState(globalThis.history.state, '', location.pathname + location.search);
|
|
@@ -12146,6 +13736,10 @@ class NhAssistantPanelComponent {
|
|
|
12146
13736
|
if (tokenIndex <= 0) {
|
|
12147
13737
|
return;
|
|
12148
13738
|
}
|
|
13739
|
+
if (name === NH_ASSISTANT_RUN_FRAGMENT) {
|
|
13740
|
+
this.push.openNotification(decodeURIComponent(value.slice(tokenIndex + 1)), decodeURIComponent(value.slice(0, tokenIndex)));
|
|
13741
|
+
return;
|
|
13742
|
+
}
|
|
12149
13743
|
const conversationId = decodeURIComponent(value.slice(0, tokenIndex));
|
|
12150
13744
|
const token = decodeURIComponent(value.slice(tokenIndex + 1));
|
|
12151
13745
|
this.panel.open();
|
|
@@ -12158,11 +13752,18 @@ class NhAssistantPanelComponent {
|
|
|
12158
13752
|
decideApproval(choice) {
|
|
12159
13753
|
this.store.decide(choice.decision, undefined, choice.approvalId);
|
|
12160
13754
|
}
|
|
13755
|
+
resolveApproval(choice) {
|
|
13756
|
+
void this.store.resolveApproval(choice.approvalId, choice.resolution);
|
|
13757
|
+
}
|
|
13758
|
+
/** Answers the question the conversation waits for; only its addressee gets the choices. */
|
|
13759
|
+
answerQuestion(answer) {
|
|
13760
|
+
this.store.answerQuestion(answer.questionId, answer.choice);
|
|
13761
|
+
}
|
|
12161
13762
|
cancel() {
|
|
12162
13763
|
void this.store.cancel();
|
|
12163
13764
|
}
|
|
12164
13765
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12165
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantPanelComponent, isStandalone: true, selector: "nh-assistant-panel", viewQueries: [{ propertyName: "drawer", first: true, predicate: ["drawer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #drawer>\n <section class=\"drawer\" role=\"dialog\" aria-modal=\"false\" [attr.aria-labelledby]=\"titleId\">\n <header class=\"header\">\n <div class=\"heading\">\n <h2 [id]=\"titleId\">{{ 'nh-assistant.panel.title' | translate }}</h2>\n </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n @if (push.state() !== 'unavailable') {\n <button\n class=\"icon-button notification-button\"\n type=\"button\"\n [class.active]=\"push.state() === 'on'\"\n [class.off]=\"!push.settings()?.pushEnabled\"\n [class.blocked]=\"push.state() === 'blocked'\"\n [disabled]=\"push.busy()\"\n [attr.aria-pressed]=\"push.settings()?.pushEnabled === true\"\n [attr.aria-label]=\"notificationsLabel() | translate\"\n [attr.title]=\"('nh-assistant.preferences.notifications-state.' + push.state() | translate) + ' \u00B7 ' + (notificationsLabel() | translate)\"\n (click)=\"toggleNotifications()\">\n <nh-assistant-icon name=\"bell\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showConversations()\"\n [attr.aria-expanded]=\"showConversations()\"\n [attr.aria-label]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n [attr.title]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n (click)=\"toggleConversations()\">\n <nh-assistant-icon name=\"list\" />\n </button>\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showPreferences()\"\n [attr.aria-expanded]=\"showPreferences()\"\n [attr.aria-label]=\"'nh-assistant.panel.open-preferences' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-preferences' | translate\"\n (click)=\"togglePreferences()\">\n <nh-assistant-icon name=\"settings\" />\n </button>\n @if (adminRoute && store.canAdminister()) {\n <a\n class=\"icon-button\"\n [routerLink]=\"adminRoute\"\n [attr.aria-label]=\"'nh-assistant.panel.open-admin' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-admin' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"admin\" />\n </a>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"newConversation()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.close' | translate\"\n [attr.title]=\"'nh-assistant.panel.close' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n </header>\n\n @if (store.enabled()) {\n <nh-assistant-activity [items]=\"store.activity()\" (conversationSelect)=\"openConversation($event)\" />\n }\n\n <div class=\"body\">\n @if (store.statusLoading() && !store.enabled()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.panel.loading' | translate }}</p>\n </div>\n } @else if (!store.enabled()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"warning\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.unavailable-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.unavailable-description' | translate }}</p>\n </div>\n } @else {\n @if (showPreferences()) {\n <nh-assistant-preferences class=\"overlay-view\" (closed)=\"showPreferences.set(false)\" />\n }\n\n @if (showShare()) {\n <nh-assistant-share class=\"overlay-view\" [section]=\"shareSection()\" (closed)=\"showShare.set(false)\" />\n }\n\n @if (showConversations()) {\n <nh-assistant-conversation-list\n class=\"overlay-view\"\n [conversations]=\"store.conversations()\"\n [total]=\"store.conversationsTotal()\"\n [activeConversationId]=\"conversation()?.id ?? null\"\n [loading]=\"store.conversationsLoading()\"\n (conversationSelect)=\"openConversation($event)\"\n (conversationDelete)=\"deleteConversation($event)\"\n (conversationCreate)=\"newConversation()\" />\n }\n\n @if (store.conversationLoading()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.thread.loading' | translate }}</p>\n </div>\n } @else if (messages().length === 0 && !store.streaming()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"assistant\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.empty-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.empty-description' | translate }}</p>\n </div>\n } @else {\n <nh-assistant-thread\n class=\"thread\"\n [attr.inert]=\"showPreferences() || showShare() || showConversations() ? '' : null\"\n [messages]=\"messages()\"\n [streaming]=\"busy()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n [members]=\"store.members()\"\n [currentActorId]=\"conversation()?.currentActorId ?? null\"\n [canDecide]=\"store.canDecide()\"\n [decisionOwner]=\"activeMemberName()\"\n [approvalRights]=\"store.approvalRights()\"\n [writingMessageId]=\"store.writingMessageId()\"\n (approvalChoice)=\"decideApproval($event)\"\n (retryMessage)=\"store.send($event)\" />\n }\n }\n </div>\n\n @if (notificationError() ?? store.error(); as error) {\n <div class=\"error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ errorKeys() | nhAssistantTranslate: error.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearError(); notificationError.set(null)\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n } @else if (store.notice(); as notice) {\n <div class=\"turn-notice\" role=\"status\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ noticeKeys() | nhAssistantTranslate: notice.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearNotice()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n }\n\n @if (store.enabled() && !showPreferences() && !showShare()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n } @else if (lastTurnFailed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.last-turn-failed' | translate }}</p>\n }\n @if (store.collaboration() || store.pageContext()) {\n <div class=\"conversation-actions\">\n @if (store.collaboration()) {\n @if (!conversation() || store.isOwner()) {\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [attr.aria-label]=\"'nh-assistant.panel.share' | translate\"\n [attr.title]=\"'nh-assistant.panel.share' | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'link'\"\n (click)=\"toggleShare('link')\">\n <nh-assistant-icon name=\"link\" />\n </button>\n }\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [class.active]=\"shared()\"\n [attr.aria-label]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.title]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'members'\"\n (click)=\"toggleShare('members')\">\n <nh-assistant-icon name=\"users\" />\n </button>\n }\n @if (store.pageContext(); as context) {\n <button\n class=\"icon-button page-context-button\"\n [class.active]=\"!store.pageContextExcluded()\"\n type=\"button\"\n [attr.aria-pressed]=\"!store.pageContextExcluded()\"\n [attr.aria-label]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n [attr.title]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n (click)=\"store.setPageContextExcluded(!store.pageContextExcluded())\">\n <nh-assistant-icon name=\"page\" />\n </button>\n }\n </div>\n }\n @if (store.queuedMessages().length > 0) {\n <section class=\"message-queue\" [attr.aria-label]=\"'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length }\">\n <div class=\"queue-heading\">\n <span aria-live=\"polite\">{{ 'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length } }}</span>\n @if (store.queuePaused()) {\n <button type=\"button\" class=\"queue-resume\" [disabled]=\"editingQueuedId() !== null\" (click)=\"store.resumeQueue()\">\n {{ 'nh-assistant.queue.resume' | translate }}\n </button>\n }\n </div>\n <ol class=\"queue-items\">\n @for (item of store.queuedMessages(); track item.id) {\n <li class=\"queue-item\" [class.failed]=\"item.state === 'failed'\">\n @if (editingQueuedId() === item.id && item.state !== 'sending') {\n <div class=\"queue-edit\">\n <textarea rows=\"2\" [value]=\"queuedDraft()\" (input)=\"changeQueuedDraft($event)\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\"></textarea>\n <div class=\"queue-buttons\">\n <button type=\"button\" class=\"icon-button\" [disabled]=\"!validQueuedDraft()\"\n [attr.aria-label]=\"'nh-assistant.queue.save' | translate\" [attr.title]=\"'nh-assistant.queue.save' | translate\"\n (click)=\"saveQueuedMessage(item.id)\"><nh-assistant-icon name=\"check\" /></button>\n <button type=\"button\" class=\"icon-button\" [attr.aria-label]=\"'nh-assistant.queue.cancel-edit' | translate\"\n [attr.title]=\"'nh-assistant.queue.cancel-edit' | translate\"\n (click)=\"cancelQueueEdit()\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n </div>\n } @else {\n <div class=\"queue-message\">\n <p [title]=\"item.text\">{{ item.text }}</p>\n @if (item.files?.length) {\n <span class=\"queue-state queue-files\" data-queue-files>{{ 'nh-assistant.queue.files' | translate: { count: item.files!.length, names: fileNames(item.files!) } }}</span>\n }\n @if (item.state !== 'queued') {\n <span class=\"queue-state\">{{ 'nh-assistant.queue.state.' + item.state | translate }}</span>\n }\n </div>\n <div class=\"queue-buttons\">\n @if (store.canSteer() && item.state === 'queued') {\n <button type=\"button\" class=\"queue-steer\" [disabled]=\"editingQueuedId() !== null\"\n [attr.title]=\"'nh-assistant.queue.steer-hint' | translate\"\n (click)=\"store.steerQueuedMessage(item.id)\">{{ 'nh-assistant.queue.steer' | translate }}</button>\n }\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\" [attr.title]=\"'nh-assistant.queue.edit' | translate\"\n (click)=\"editQueuedMessage(item.id, item.text)\"><nh-assistant-icon name=\"edit\" /></button>\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.remove' | translate\" [attr.title]=\"'nh-assistant.queue.remove' | translate\"\n (click)=\"store.removeQueuedMessage(item.id)\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n }\n </li>\n }\n </ol>\n </section>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [queueWhileBusy]=\"true\"\n [status]=\"composerStatus()\"\n [statusActor]=\"activeMemberName()\"\n [canStop]=\"canStop()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n [uploads]=\"store.uploads()\"\n [attachments]=\"store.attachments()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (attach)=\"attach($event)\"\n (removeAttachment)=\"store.removeAttachment($event)\"\n (cancel)=\"cancel()\">\n @if (store.agents().length > 1) {\n <nh-assistant-agent-picker\n nhAssistantComposerControls\n [compact]=\"true\"\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </nh-assistant-composer>\n </footer>\n }\n </section>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}.drawer{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){.drawer{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:contents}.drawer{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;border-left:1px solid var(--nha-border);color:var(--nha-text);background:var(--nha-background);box-shadow:var(--nha-shadow);font-family:var(--nha-font);font-size:14px}.drawer *,.drawer *:before,.drawer *:after{box-sizing:border-box}.header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px 12px;border-bottom:1px solid var(--nha-border);padding:12px 12px 12px 16px}.heading{display:contents}h2{grid-row:1;min-width:0;margin:0;overflow:hidden;font-size:16px;font-weight:750;letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap}.header-actions{display:flex;flex:none;grid-column:2;grid-row:1;gap:2px;min-width:0}.header-actions .icon-button{width:32px;height:32px}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;text-decoration:none}.icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.icon-button:disabled{cursor:not-allowed;opacity:.5}.icon-button.active{color:var(--nha-highlight);background:var(--nha-surface-strong)}.body{position:relative;display:flex;flex:1;flex-direction:column;min-height:0;background:var(--nha-background)}.thread{flex:1;min-height:0}.overlay-view{position:absolute;z-index:1;inset:0;border-bottom:1px solid var(--nha-border);background:var(--nha-background)}.state{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:24px;color:var(--nha-text-muted);text-align:center}.state p{max-width:32ch;margin:0;font-size:13px}.state-icon{margin-bottom:8px;color:var(--nha-highlight);font-size:28px}.state .state-title{color:var(--nha-text);font-size:15px;font-weight:700}.error{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-danger);background:var(--nha-danger-soft)}.error p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.turn-notice{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-warning);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-warning);background:var(--nha-warning-soft)}.turn-notice p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.footer{padding:12px 16px 14px}.conversation-actions{display:flex;align-items:center;gap:4px;margin:0 -4px 6px}.page-context-button{margin-left:auto}.message-queue{margin-bottom:10px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);background:var(--nha-background);overflow:hidden;font-size:12px}.queue-heading{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px;color:var(--nha-text-muted)}.queue-items{max-height:180px;overflow-y:auto;margin:0;padding:0;list-style:none}.queue-item{display:flex;align-items:center;gap:8px;border-top:1px solid var(--nha-border);padding:6px 8px 6px 10px}.queue-item.failed{border-left:2px solid var(--nha-danger)}.queue-message{flex:1;min-width:0}.queue-message p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;margin:0}.queue-state{color:var(--nha-text-muted);font-size:11px}.queue-files{display:block;overflow-wrap:anywhere}.queue-buttons{display:flex;flex-shrink:0;align-items:center;gap:2px}.queue-buttons .icon-button{width:28px;height:30px}.queue-resume,.queue-steer{border:0;border-radius:6px;padding:6px;color:var(--nha-highlight);background:transparent;font:inherit;cursor:pointer}.queue-resume:hover,.queue-steer:hover{background:var(--nha-surface)}.queue-resume:focus-visible,.queue-steer:focus-visible{outline:2px solid var(--nha-focus)}.queue-resume:disabled,.queue-steer:disabled{cursor:not-allowed;opacity:.5}.queue-edit{width:100%}.queue-edit textarea{box-sizing:border-box;width:100%;border:1px solid var(--nha-border);border-radius:6px;padding:8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;resize:vertical}.queue-edit .queue-buttons{justify-content:flex-end}.notification-button{position:relative}.notification-button.off:after{content:\"\";position:absolute;width:18px;height:2px;border-radius:1px;background:currentColor;transform:rotate(-45deg)}.notification-button.blocked{color:var(--nha-warning)}@media(max-width:359px){.header{gap:6px;padding-inline:12px}.header-actions .icon-button{width:28px;height:32px}}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantActivityComponent, selector: "nh-assistant-activity", inputs: ["items"], outputs: ["conversationSelect"] }, { kind: "component", type: NhAssistantAgentPickerComponent, selector: "nh-assistant-agent-picker", inputs: ["agents", "selectedAgentId", "disabled", "compact"], outputs: ["agentChange"] }, { kind: "component", type: NhAssistantComposerComponent, selector: "nh-assistant-composer", inputs: ["disabled", "sendDisabled", "busy", "queueWhileBusy", "status", "statusActor", "canStop", "maxLength", "restore", "uploads", "attachments"], outputs: ["send", "cancel", "restored", "attach", "removeAttachment"] }, { kind: "component", type: NhAssistantConversationListComponent, selector: "nh-assistant-conversation-list", inputs: ["conversations", "total", "activeConversationId", "loading", "disabled"], outputs: ["conversationSelect", "conversationDelete", "conversationCreate"] }, { kind: "component", type: NhAssistantPreferencesComponent, selector: "nh-assistant-preferences", outputs: ["closed", "saved"] }, { kind: "component", type: NhAssistantShareComponent, selector: "nh-assistant-share", inputs: ["section"], outputs: ["closed"] }, { kind: "component", type: NhAssistantThreadComponent, selector: "nh-assistant-thread", inputs: ["messages", "streaming", "deciding", "markdown", "members", "currentActorId", "canDecide", "decisionOwner", "approvalRights", "writingMessageId"], outputs: ["approvalDecision", "approvalChoice", "retryMessage"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
13766
|
+
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 (approvalResolution)=\"resolveApproval($event)\"\n (questionAnswer)=\"answerQuestion($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]=\"composerStatusActor()\"\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", "approvalResolution", "questionAnswer", "retryMessage"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12166
13767
|
}
|
|
12167
13768
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantPanelComponent, decorators: [{
|
|
12168
13769
|
type: Component,
|
|
@@ -12178,7 +13779,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
12178
13779
|
NhAssistantPreferencesComponent,
|
|
12179
13780
|
NhAssistantShareComponent,
|
|
12180
13781
|
NhAssistantThreadComponent
|
|
12181
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #drawer>\n <section class=\"drawer\" role=\"dialog\" aria-modal=\"false\" [attr.aria-labelledby]=\"titleId\">\n <header class=\"header\">\n <div class=\"heading\">\n <h2 [id]=\"titleId\">{{ 'nh-assistant.panel.title' | translate }}</h2>\n </div>\n <div class=\"header-actions\">\n @if (store.enabled()) {\n @if (push.state() !== 'unavailable') {\n <button\n class=\"icon-button notification-button\"\n type=\"button\"\n [class.active]=\"push.state() === 'on'\"\n [class.off]=\"!push.settings()?.pushEnabled\"\n [class.blocked]=\"push.state() === 'blocked'\"\n [disabled]=\"push.busy()\"\n [attr.aria-pressed]=\"push.settings()?.pushEnabled === true\"\n [attr.aria-label]=\"notificationsLabel() | translate\"\n [attr.title]=\"('nh-assistant.preferences.notifications-state.' + push.state() | translate) + ' \u00B7 ' + (notificationsLabel() | translate)\"\n (click)=\"toggleNotifications()\">\n <nh-assistant-icon name=\"bell\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showConversations()\"\n [attr.aria-expanded]=\"showConversations()\"\n [attr.aria-label]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n [attr.title]=\"(showConversations() ? 'nh-assistant.panel.hide-conversations' : 'nh-assistant.panel.show-conversations') | translate\"\n (click)=\"toggleConversations()\">\n <nh-assistant-icon name=\"list\" />\n </button>\n <button\n class=\"icon-button\"\n type=\"button\"\n [class.active]=\"showPreferences()\"\n [attr.aria-expanded]=\"showPreferences()\"\n [attr.aria-label]=\"'nh-assistant.panel.open-preferences' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-preferences' | translate\"\n (click)=\"togglePreferences()\">\n <nh-assistant-icon name=\"settings\" />\n </button>\n @if (adminRoute && store.canAdminister()) {\n <a\n class=\"icon-button\"\n [routerLink]=\"adminRoute\"\n [attr.aria-label]=\"'nh-assistant.panel.open-admin' | translate\"\n [attr.title]=\"'nh-assistant.panel.open-admin' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"admin\" />\n </a>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.new-conversation' | translate\"\n [attr.title]=\"'nh-assistant.panel.new-conversation' | translate\"\n (click)=\"newConversation()\">\n <nh-assistant-icon name=\"plus\" />\n </button>\n }\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.close' | translate\"\n [attr.title]=\"'nh-assistant.panel.close' | translate\"\n (click)=\"panel.close()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n </header>\n\n @if (store.enabled()) {\n <nh-assistant-activity [items]=\"store.activity()\" (conversationSelect)=\"openConversation($event)\" />\n }\n\n <div class=\"body\">\n @if (store.statusLoading() && !store.enabled()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.panel.loading' | translate }}</p>\n </div>\n } @else if (!store.enabled()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"warning\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.unavailable-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.unavailable-description' | translate }}</p>\n </div>\n } @else {\n @if (showPreferences()) {\n <nh-assistant-preferences class=\"overlay-view\" (closed)=\"showPreferences.set(false)\" />\n }\n\n @if (showShare()) {\n <nh-assistant-share class=\"overlay-view\" [section]=\"shareSection()\" (closed)=\"showShare.set(false)\" />\n }\n\n @if (showConversations()) {\n <nh-assistant-conversation-list\n class=\"overlay-view\"\n [conversations]=\"store.conversations()\"\n [total]=\"store.conversationsTotal()\"\n [activeConversationId]=\"conversation()?.id ?? null\"\n [loading]=\"store.conversationsLoading()\"\n (conversationSelect)=\"openConversation($event)\"\n (conversationDelete)=\"deleteConversation($event)\"\n (conversationCreate)=\"newConversation()\" />\n }\n\n @if (store.conversationLoading()) {\n <div class=\"state\" role=\"status\">\n <p class=\"state-title\">{{ 'nh-assistant.thread.loading' | translate }}</p>\n </div>\n } @else if (messages().length === 0 && !store.streaming()) {\n <div class=\"state\">\n <nh-assistant-icon class=\"state-icon\" name=\"assistant\" />\n <p class=\"state-title\">{{ 'nh-assistant.panel.empty-title' | translate }}</p>\n <p>{{ 'nh-assistant.panel.empty-description' | translate }}</p>\n </div>\n } @else {\n <nh-assistant-thread\n class=\"thread\"\n [attr.inert]=\"showPreferences() || showShare() || showConversations() ? '' : null\"\n [messages]=\"messages()\"\n [streaming]=\"busy()\"\n [deciding]=\"store.deciding()\"\n [markdown]=\"markdown\"\n [members]=\"store.members()\"\n [currentActorId]=\"conversation()?.currentActorId ?? null\"\n [canDecide]=\"store.canDecide()\"\n [decisionOwner]=\"activeMemberName()\"\n [approvalRights]=\"store.approvalRights()\"\n [writingMessageId]=\"store.writingMessageId()\"\n (approvalChoice)=\"decideApproval($event)\"\n (retryMessage)=\"store.send($event)\" />\n }\n }\n </div>\n\n @if (notificationError() ?? store.error(); as error) {\n <div class=\"error\" role=\"alert\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ errorKeys() | nhAssistantTranslate: error.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearError(); notificationError.set(null)\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n } @else if (store.notice(); as notice) {\n <div class=\"turn-notice\" role=\"status\">\n <nh-assistant-icon name=\"warning\" />\n <p>{{ noticeKeys() | nhAssistantTranslate: notice.code }}</p>\n <button\n class=\"icon-button\"\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.panel.dismiss-error' | translate\"\n [attr.title]=\"'nh-assistant.panel.dismiss-error' | translate\"\n (click)=\"store.clearNotice()\">\n <nh-assistant-icon name=\"close\" />\n </button>\n </div>\n }\n\n @if (store.enabled() && !showPreferences() && !showShare()) {\n <footer class=\"footer\" (focusin)=\"refreshPageContext()\">\n @if (closed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.conversation-closed' | translate }}</p>\n } @else if (lastTurnFailed()) {\n <p class=\"notice\">{{ 'nh-assistant.panel.last-turn-failed' | translate }}</p>\n }\n @if (store.collaboration() || store.pageContext()) {\n <div class=\"conversation-actions\">\n @if (store.collaboration()) {\n @if (!conversation() || store.isOwner()) {\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [attr.aria-label]=\"'nh-assistant.panel.share' | translate\"\n [attr.title]=\"'nh-assistant.panel.share' | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'link'\"\n (click)=\"toggleShare('link')\">\n <nh-assistant-icon name=\"link\" />\n </button>\n }\n <button class=\"icon-button\" type=\"button\" [disabled]=\"!canShare()\"\n [class.active]=\"shared()\"\n [attr.aria-label]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.title]=\"(store.isOwner() || !conversation() ? 'nh-assistant.panel.add-members' : 'nh-assistant.panel.members') | translate\"\n [attr.aria-expanded]=\"showShare() && shareSection() === 'members'\"\n (click)=\"toggleShare('members')\">\n <nh-assistant-icon name=\"users\" />\n </button>\n }\n @if (store.pageContext(); as context) {\n <button\n class=\"icon-button page-context-button\"\n [class.active]=\"!store.pageContextExcluded()\"\n type=\"button\"\n [attr.aria-pressed]=\"!store.pageContextExcluded()\"\n [attr.aria-label]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n [attr.title]=\"(store.pageContextExcluded() ? 'nh-assistant.page-context.include' : 'nh-assistant.page-context.exclude') | translate: { page: describeContext(context) }\"\n (click)=\"store.setPageContextExcluded(!store.pageContextExcluded())\">\n <nh-assistant-icon name=\"page\" />\n </button>\n }\n </div>\n }\n @if (store.queuedMessages().length > 0) {\n <section class=\"message-queue\" [attr.aria-label]=\"'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length }\">\n <div class=\"queue-heading\">\n <span aria-live=\"polite\">{{ 'nh-assistant.queue.title' | translate: { count: store.queuedMessages().length } }}</span>\n @if (store.queuePaused()) {\n <button type=\"button\" class=\"queue-resume\" [disabled]=\"editingQueuedId() !== null\" (click)=\"store.resumeQueue()\">\n {{ 'nh-assistant.queue.resume' | translate }}\n </button>\n }\n </div>\n <ol class=\"queue-items\">\n @for (item of store.queuedMessages(); track item.id) {\n <li class=\"queue-item\" [class.failed]=\"item.state === 'failed'\">\n @if (editingQueuedId() === item.id && item.state !== 'sending') {\n <div class=\"queue-edit\">\n <textarea rows=\"2\" [value]=\"queuedDraft()\" (input)=\"changeQueuedDraft($event)\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\"></textarea>\n <div class=\"queue-buttons\">\n <button type=\"button\" class=\"icon-button\" [disabled]=\"!validQueuedDraft()\"\n [attr.aria-label]=\"'nh-assistant.queue.save' | translate\" [attr.title]=\"'nh-assistant.queue.save' | translate\"\n (click)=\"saveQueuedMessage(item.id)\"><nh-assistant-icon name=\"check\" /></button>\n <button type=\"button\" class=\"icon-button\" [attr.aria-label]=\"'nh-assistant.queue.cancel-edit' | translate\"\n [attr.title]=\"'nh-assistant.queue.cancel-edit' | translate\"\n (click)=\"cancelQueueEdit()\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n </div>\n } @else {\n <div class=\"queue-message\">\n <p [title]=\"item.text\">{{ item.text }}</p>\n @if (item.files?.length) {\n <span class=\"queue-state queue-files\" data-queue-files>{{ 'nh-assistant.queue.files' | translate: { count: item.files!.length, names: fileNames(item.files!) } }}</span>\n }\n @if (item.state !== 'queued') {\n <span class=\"queue-state\">{{ 'nh-assistant.queue.state.' + item.state | translate }}</span>\n }\n </div>\n <div class=\"queue-buttons\">\n @if (store.canSteer() && item.state === 'queued') {\n <button type=\"button\" class=\"queue-steer\" [disabled]=\"editingQueuedId() !== null\"\n [attr.title]=\"'nh-assistant.queue.steer-hint' | translate\"\n (click)=\"store.steerQueuedMessage(item.id)\">{{ 'nh-assistant.queue.steer' | translate }}</button>\n }\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.edit' | translate\" [attr.title]=\"'nh-assistant.queue.edit' | translate\"\n (click)=\"editQueuedMessage(item.id, item.text)\"><nh-assistant-icon name=\"edit\" /></button>\n <button type=\"button\" class=\"icon-button\" [disabled]=\"item.state === 'sending'\"\n [attr.aria-label]=\"'nh-assistant.queue.remove' | translate\" [attr.title]=\"'nh-assistant.queue.remove' | translate\"\n (click)=\"store.removeQueuedMessage(item.id)\"><nh-assistant-icon name=\"close\" /></button>\n </div>\n }\n </li>\n }\n </ol>\n </section>\n }\n <nh-assistant-composer\n [disabled]=\"closed()\"\n [sendDisabled]=\"composerDisabled()\"\n [busy]=\"busy()\"\n [queueWhileBusy]=\"true\"\n [status]=\"composerStatus()\"\n [statusActor]=\"activeMemberName()\"\n [canStop]=\"canStop()\"\n [maxLength]=\"store.limits()?.maxMessageChars ?? null\"\n [restore]=\"store.restoredDraft()\"\n [uploads]=\"store.uploads()\"\n [attachments]=\"store.attachments()\"\n (restored)=\"store.consumeRestoredDraft()\"\n (send)=\"send($event)\"\n (attach)=\"attach($event)\"\n (removeAttachment)=\"store.removeAttachment($event)\"\n (cancel)=\"cancel()\">\n @if (store.agents().length > 1) {\n <nh-assistant-agent-picker\n nhAssistantComposerControls\n [compact]=\"true\"\n [agents]=\"store.agents()\"\n [selectedAgentId]=\"store.selectedAgentId()\"\n (agentChange)=\"store.selectAgent($event)\" />\n }\n </nh-assistant-composer>\n </footer>\n }\n </section>\n</ng-template>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}.drawer{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){.drawer{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display:contents}.drawer{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;border-left:1px solid var(--nha-border);color:var(--nha-text);background:var(--nha-background);box-shadow:var(--nha-shadow);font-family:var(--nha-font);font-size:14px}.drawer *,.drawer *:before,.drawer *:after{box-sizing:border-box}.header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px 12px;border-bottom:1px solid var(--nha-border);padding:12px 12px 12px 16px}.heading{display:contents}h2{grid-row:1;min-width:0;margin:0;overflow:hidden;font-size:16px;font-weight:750;letter-spacing:-.01em;text-overflow:ellipsis;white-space:nowrap}.header-actions{display:flex;flex:none;grid-column:2;grid-row:1;gap:2px;min-width:0}.header-actions .icon-button{width:32px;height:32px}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid transparent;border-radius:var(--nha-radius-control);color:var(--nha-text-muted);background:transparent;cursor:pointer;text-decoration:none}.icon-button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.icon-button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.icon-button:disabled{cursor:not-allowed;opacity:.5}.icon-button.active{color:var(--nha-highlight);background:var(--nha-surface-strong)}.body{position:relative;display:flex;flex:1;flex-direction:column;min-height:0;background:var(--nha-background)}.thread{flex:1;min-height:0}.overlay-view{position:absolute;z-index:1;inset:0;border-bottom:1px solid var(--nha-border);background:var(--nha-background)}.state{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:24px;color:var(--nha-text-muted);text-align:center}.state p{max-width:32ch;margin:0;font-size:13px}.state-icon{margin-bottom:8px;color:var(--nha-highlight);font-size:28px}.state .state-title{color:var(--nha-text);font-size:15px;font-weight:700}.error{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-danger);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-danger);background:var(--nha-danger-soft)}.error p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.turn-notice{display:flex;align-items:center;gap:8px;margin:0 12px 8px;border:1px solid var(--nha-warning);border-radius:var(--nha-radius-control);padding:4px 4px 4px 12px;color:var(--nha-warning);background:var(--nha-warning-soft)}.turn-notice p{flex:1;margin:0;color:var(--nha-text);font-size:13px}.footer{padding:12px 16px 14px}.conversation-actions{display:flex;align-items:center;gap:4px;margin:0 -4px 6px}.page-context-button{margin-left:auto}.message-queue{margin-bottom:10px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);background:var(--nha-background);overflow:hidden;font-size:12px}.queue-heading{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px;color:var(--nha-text-muted)}.queue-items{max-height:180px;overflow-y:auto;margin:0;padding:0;list-style:none}.queue-item{display:flex;align-items:center;gap:8px;border-top:1px solid var(--nha-border);padding:6px 8px 6px 10px}.queue-item.failed{border-left:2px solid var(--nha-danger)}.queue-message{flex:1;min-width:0}.queue-message p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;margin:0}.queue-state{color:var(--nha-text-muted);font-size:11px}.queue-files{display:block;overflow-wrap:anywhere}.queue-buttons{display:flex;flex-shrink:0;align-items:center;gap:2px}.queue-buttons .icon-button{width:28px;height:30px}.queue-resume,.queue-steer{border:0;border-radius:6px;padding:6px;color:var(--nha-highlight);background:transparent;font:inherit;cursor:pointer}.queue-resume:hover,.queue-steer:hover{background:var(--nha-surface)}.queue-resume:focus-visible,.queue-steer:focus-visible{outline:2px solid var(--nha-focus)}.queue-resume:disabled,.queue-steer:disabled{cursor:not-allowed;opacity:.5}.queue-edit{width:100%}.queue-edit textarea{box-sizing:border-box;width:100%;border:1px solid var(--nha-border);border-radius:6px;padding:8px;color:var(--nha-text);background:var(--nha-surface);font:inherit;resize:vertical}.queue-edit .queue-buttons{justify-content:flex-end}.notification-button{position:relative}.notification-button.off:after{content:\"\";position:absolute;width:18px;height:2px;border-radius:1px;background:currentColor;transform:rotate(-45deg)}.notification-button.blocked{color:var(--nha-warning)}@media(max-width:359px){.header{gap:6px;padding-inline:12px}.header-actions .icon-button{width:28px;height:32px}}.notice{margin:0 0 8px;color:var(--nha-text-muted);font-size:12px}\n"] }]
|
|
13782
|
+
], 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 (approvalResolution)=\"resolveApproval($event)\"\n (questionAnswer)=\"answerQuestion($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]=\"composerStatusActor()\"\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"] }]
|
|
12182
13783
|
}], ctorParameters: () => [], propDecorators: { drawer: [{ type: i0.ViewChild, args: ['drawer', { isSignal: true }] }] } });
|
|
12183
13784
|
|
|
12184
13785
|
/**
|
|
@@ -12269,6 +13870,552 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
12269
13870
|
`, 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;vertical-align:middle}.subject-badge{position:relative;display:inline-flex;align-items:center;gap:4px;min-height:22px;border:1px solid var(--nha-border);border-radius:999px;padding:1px 8px 1px 6px;color:var(--nha-text-muted);background:var(--nha-surface-strong);font-family:var(--nha-font);font-size:12px;font-weight:700;line-height:1;white-space:nowrap}.subject-badge nh-assistant-icon{font-size:13px}.subject-badge[data-state=decide]{border-color:var(--nha-accent);color:var(--nha-accent-contrast);background:var(--nha-accent)}.subject-badge[data-state=working]{padding-right:6px}.count{font-variant-numeric:tabular-nums}.working{width:8px;height:8px;border:2px solid color-mix(in srgb,var(--nha-highlight) 30%,transparent);border-top-color:var(--nha-highlight);border-radius:50%;animation:nh-assistant-subject-spin .9s linear infinite}.subject-badge[data-state=decide] .working{border-color:color-mix(in srgb,var(--nha-accent-contrast) 35%,transparent);border-top-color:var(--nha-accent-contrast)}@media(prefers-reduced-motion:reduce){.working{border-color:var(--nha-highlight);animation:none}.subject-badge[data-state=decide] .working{border-color:var(--nha-accent-contrast)}}@keyframes nh-assistant-subject-spin{to{transform:rotate(360deg)}}.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
12270
13871
|
}], ctorParameters: () => [], propDecorators: { subjectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "subjectType", required: true }] }], subjectId: [{ type: i0.Input, args: [{ isSignal: true, alias: "subjectId", required: true }] }] } });
|
|
12271
13872
|
|
|
13873
|
+
/** Links that leave the bundle: only these schemes, and they open in a new tab. */
|
|
13874
|
+
const nhAssistantExternalLinkPattern = /^(?:https?:|mailto:)/i;
|
|
13875
|
+
const externalProtocols = new Set(['http:', 'https:', 'mailto:']);
|
|
13876
|
+
const schemePattern = /^[a-z][a-z0-9+.-]*:/i;
|
|
13877
|
+
const controlCharacters = /[\u0000-\u001f\u007f]/;
|
|
13878
|
+
const maxDiagramReason = 300;
|
|
13879
|
+
function decodeOrNull(value, decode) {
|
|
13880
|
+
try {
|
|
13881
|
+
return decode(value);
|
|
13882
|
+
}
|
|
13883
|
+
catch {
|
|
13884
|
+
return null;
|
|
13885
|
+
}
|
|
13886
|
+
}
|
|
13887
|
+
/**
|
|
13888
|
+
* The normalized form of a bundle path: forward slashes only, without `.` and `..` segments and
|
|
13889
|
+
* without a leading slash. `null` for a path that names a scheme, escapes the bundle's root or
|
|
13890
|
+
* holds a backslash or control character.
|
|
13891
|
+
*/
|
|
13892
|
+
function nhAssistantBundlePath(path) {
|
|
13893
|
+
const trimmed = path.trim();
|
|
13894
|
+
if (!trimmed || trimmed.includes('\\') || controlCharacters.test(trimmed) || schemePattern.test(trimmed) || trimmed.startsWith('//')) {
|
|
13895
|
+
return null;
|
|
13896
|
+
}
|
|
13897
|
+
const segments = [];
|
|
13898
|
+
for (const segment of trimmed.split('/')) {
|
|
13899
|
+
if (segment === '' || segment === '.') {
|
|
13900
|
+
continue;
|
|
13901
|
+
}
|
|
13902
|
+
if (segment === '..') {
|
|
13903
|
+
if (segments.length === 0) {
|
|
13904
|
+
return null;
|
|
13905
|
+
}
|
|
13906
|
+
segments.pop();
|
|
13907
|
+
continue;
|
|
13908
|
+
}
|
|
13909
|
+
segments.push(segment);
|
|
13910
|
+
}
|
|
13911
|
+
return segments.length > 0 ? segments.join('/') : null;
|
|
13912
|
+
}
|
|
13913
|
+
/**
|
|
13914
|
+
* Resolves a relative link of the document at `base` within its bundle: from the document's
|
|
13915
|
+
* folder, or from the bundle's root when it starts with `/`. The query is ignored.
|
|
13916
|
+
*/
|
|
13917
|
+
function nhAssistantResolveBundleLink(base, href) {
|
|
13918
|
+
const hashIndex = href.indexOf('#');
|
|
13919
|
+
const target = hashIndex >= 0 ? href.slice(0, hashIndex) : href;
|
|
13920
|
+
const fragment = hashIndex >= 0 ? decodeOrNull(href.slice(hashIndex + 1), decodeURIComponent) : null;
|
|
13921
|
+
const pathPart = decodeOrNull(target.split('?')[0], decodeURI);
|
|
13922
|
+
if (pathPart === null || pathPart.trim() === '' || (hashIndex >= 0 && fragment === null)) {
|
|
13923
|
+
return null;
|
|
13924
|
+
}
|
|
13925
|
+
const folder = base ? base.split('/').slice(0, -1).join('/') : '';
|
|
13926
|
+
const joined = pathPart.startsWith('/') || !folder ? pathPart : `${folder}/${pathPart}`;
|
|
13927
|
+
const path = schemePattern.test(pathPart) || pathPart.startsWith('//') ? null : nhAssistantBundlePath(joined);
|
|
13928
|
+
return path ? { path, fragment: fragment || null } : null;
|
|
13929
|
+
}
|
|
13930
|
+
/** The fragment of a heading: lower case, punctuation removed, spaces as dashes. */
|
|
13931
|
+
function slugOf(text) {
|
|
13932
|
+
const slug = text
|
|
13933
|
+
.toLowerCase()
|
|
13934
|
+
.trim()
|
|
13935
|
+
.replace(/[^\p{L}\p{N}\s_-]/gu, '')
|
|
13936
|
+
.replace(/\s+/g, '-');
|
|
13937
|
+
return slug || 'section';
|
|
13938
|
+
}
|
|
13939
|
+
/** The state of one rendering, which the Markdown renderer and the sanitizer hooks share. */
|
|
13940
|
+
class DocumentRendering {
|
|
13941
|
+
constructor(options) {
|
|
13942
|
+
this.options = options;
|
|
13943
|
+
this.headings = [];
|
|
13944
|
+
/** The bundle hrefs this rendering wrote, the only relative hrefs the sanitizer keeps. */
|
|
13945
|
+
this.bundleHrefs = new Set();
|
|
13946
|
+
this.slugs = new Map();
|
|
13947
|
+
this.ownPath = options.path ? nhAssistantBundlePath(options.path) : null;
|
|
13948
|
+
this.siblings = new Set(options.siblingPaths
|
|
13949
|
+
.map(path => nhAssistantBundlePath(path))
|
|
13950
|
+
.filter((path) => !!path));
|
|
13951
|
+
}
|
|
13952
|
+
addHeading(text, level) {
|
|
13953
|
+
const base = slugOf(text);
|
|
13954
|
+
const seen = this.slugs.get(base) ?? 0;
|
|
13955
|
+
this.slugs.set(base, seen + 1);
|
|
13956
|
+
const fragment = seen === 0 ? base : `${base}-${seen}`;
|
|
13957
|
+
const heading = { id: `${this.options.idPrefix}${fragment}`, fragment, level, text };
|
|
13958
|
+
this.headings.push(heading);
|
|
13959
|
+
return heading;
|
|
13960
|
+
}
|
|
13961
|
+
/**
|
|
13962
|
+
* The href to write for a link, or `null` to show only its text: a fragment of this
|
|
13963
|
+
* document, an `https:`, `http:` or `mailto:` address, or a sibling of the bundle. Every
|
|
13964
|
+
* other scheme, such as `javascript:`, `data:` or `file:`, and every path outside the bundle
|
|
13965
|
+
* is refused.
|
|
13966
|
+
*/
|
|
13967
|
+
hrefOf(raw) {
|
|
13968
|
+
const href = raw.trim();
|
|
13969
|
+
if (!href || controlCharacters.test(href)) {
|
|
13970
|
+
return null;
|
|
13971
|
+
}
|
|
13972
|
+
if (href.startsWith('#')) {
|
|
13973
|
+
return href.length > 1 ? href : null;
|
|
13974
|
+
}
|
|
13975
|
+
if (nhAssistantExternalLinkPattern.test(href)) {
|
|
13976
|
+
return this.externalHref(href);
|
|
13977
|
+
}
|
|
13978
|
+
const resolved = schemePattern.test(href) || href.startsWith('//') ? null : nhAssistantResolveBundleLink(this.ownPath, href);
|
|
13979
|
+
if (!resolved) {
|
|
13980
|
+
return null;
|
|
13981
|
+
}
|
|
13982
|
+
const fragment = resolved.fragment ? `#${encodeURIComponent(resolved.fragment)}` : '';
|
|
13983
|
+
if (resolved.path === this.ownPath) {
|
|
13984
|
+
return fragment || null;
|
|
13985
|
+
}
|
|
13986
|
+
if (!this.siblings.has(resolved.path)) {
|
|
13987
|
+
return null;
|
|
13988
|
+
}
|
|
13989
|
+
const bundleHref = `${encodeURI(resolved.path)}${fragment}`;
|
|
13990
|
+
this.bundleHrefs.add(bundleHref);
|
|
13991
|
+
return bundleHref;
|
|
13992
|
+
}
|
|
13993
|
+
externalHref(href) {
|
|
13994
|
+
try {
|
|
13995
|
+
const url = new URL(href);
|
|
13996
|
+
return externalProtocols.has(url.protocol) ? url.href : null;
|
|
13997
|
+
}
|
|
13998
|
+
catch {
|
|
13999
|
+
return null;
|
|
14000
|
+
}
|
|
14001
|
+
}
|
|
14002
|
+
}
|
|
14003
|
+
/** CSS that could run code or load something, which a diagram's styles may not contain. */
|
|
14004
|
+
function isUnsafeCss(css) {
|
|
14005
|
+
if (/\\|@import|@font-face|expression\s*\(|-moz-binding|behavior\s*:|image-set\s*\(|\bimage\s*\(|cross-fade\s*\(|\bsrc\s*\(/i.test(css)) {
|
|
14006
|
+
return true;
|
|
14007
|
+
}
|
|
14008
|
+
return hasExternalReference(css);
|
|
14009
|
+
}
|
|
14010
|
+
/** `url(...)` that names anything but a fragment of the diagram itself, such as `url(#arrow)`. */
|
|
14011
|
+
function hasExternalReference(value) {
|
|
14012
|
+
for (const match of value.matchAll(/url\s*\(\s*(['"]?)\s*([^)'"]*)/gi)) {
|
|
14013
|
+
if (!match[2].trim().startsWith('#')) {
|
|
14014
|
+
return true;
|
|
14015
|
+
}
|
|
14016
|
+
}
|
|
14017
|
+
return false;
|
|
14018
|
+
}
|
|
14019
|
+
/** The reason a renderer gave, as one short line; empty when it gave none. */
|
|
14020
|
+
function nhAssistantDiagramReason(error) {
|
|
14021
|
+
const text = error instanceof Error ? error.message : typeof error === 'string' ? error : '';
|
|
14022
|
+
const line = text.replace(/\s+/g, ' ').trim();
|
|
14023
|
+
return line.length > maxDiagramReason ? `${line.slice(0, maxDiagramReason - 1)}…` : line;
|
|
14024
|
+
}
|
|
14025
|
+
/**
|
|
14026
|
+
* Renders untrusted Markdown documents of a bundle with the assistant's safety defaults: inline
|
|
14027
|
+
* HTML shows as text, images as their alt text, links only to fragments, `https:`, `http:`,
|
|
14028
|
+
* `mailto:` and sibling documents, and DOMPurify sanitizes the result. Top-level fenced code
|
|
14029
|
+
* blocks of a diagram language become diagram segments. Internal to `nh-assistant-document`.
|
|
14030
|
+
*/
|
|
14031
|
+
class NhAssistantDocumentMarkdownRenderer {
|
|
14032
|
+
constructor() {
|
|
14033
|
+
this.document = inject(DOCUMENT);
|
|
14034
|
+
this.documentPurifier = null;
|
|
14035
|
+
this.diagramPurifier = null;
|
|
14036
|
+
/** The rendering being sanitized; the purifier's hooks read it. */
|
|
14037
|
+
this.current = null;
|
|
14038
|
+
}
|
|
14039
|
+
render(markdown, options) {
|
|
14040
|
+
const rendering = new DocumentRendering(options);
|
|
14041
|
+
const purifier = this.getDocumentPurifier();
|
|
14042
|
+
if (!purifier) {
|
|
14043
|
+
return { segments: [{ kind: 'html', html: `<p>${nhAssistantEscapeHtml(markdown)}</p>` }], headings: [] };
|
|
14044
|
+
}
|
|
14045
|
+
const marked = this.createMarked(rendering);
|
|
14046
|
+
const tokens = marked.lexer(markdown);
|
|
14047
|
+
const diagramLanguages = new Set(options.diagramLanguages.map(language => language.toLowerCase()));
|
|
14048
|
+
const segments = [];
|
|
14049
|
+
let pending = [];
|
|
14050
|
+
const flush = () => {
|
|
14051
|
+
if (pending.length === 0) {
|
|
14052
|
+
return;
|
|
14053
|
+
}
|
|
14054
|
+
const html = marked.parser(Object.assign(pending, { links: tokens.links }));
|
|
14055
|
+
segments.push({ kind: 'html', html: this.sanitize(purifier, rendering, html) });
|
|
14056
|
+
pending = [];
|
|
14057
|
+
};
|
|
14058
|
+
for (const token of tokens) {
|
|
14059
|
+
const language = token.type === 'code' ? token.lang?.trim().split(/\s+/)[0]?.toLowerCase() : undefined;
|
|
14060
|
+
if (language && diagramLanguages.has(language)) {
|
|
14061
|
+
flush();
|
|
14062
|
+
segments.push({ kind: 'diagram', language, source: token.text });
|
|
14063
|
+
continue;
|
|
14064
|
+
}
|
|
14065
|
+
pending.push(token);
|
|
14066
|
+
}
|
|
14067
|
+
flush();
|
|
14068
|
+
return { segments, headings: rendering.headings };
|
|
14069
|
+
}
|
|
14070
|
+
/**
|
|
14071
|
+
* Sanitizes a renderer's SVG: SVG and its filters only, without scripts, event handlers,
|
|
14072
|
+
* links, images, `use`, foreign content, external references or CSS that could load or run
|
|
14073
|
+
* anything. `null` when the result is not one SVG element.
|
|
14074
|
+
*/
|
|
14075
|
+
sanitizeDiagram(svg) {
|
|
14076
|
+
const purifier = this.getDiagramPurifier();
|
|
14077
|
+
if (!purifier) {
|
|
14078
|
+
return null;
|
|
14079
|
+
}
|
|
14080
|
+
const fragment = purifier.sanitize(svg, {
|
|
14081
|
+
USE_PROFILES: { svg: true, svgFilters: true },
|
|
14082
|
+
FORBID_TAGS: ['a', 'image', 'use', 'feImage', 'foreignObject', 'script', 'iframe'],
|
|
14083
|
+
FORBID_ATTR: ['href', 'xlink:href'],
|
|
14084
|
+
ALLOW_DATA_ATTR: false,
|
|
14085
|
+
RETURN_DOM_FRAGMENT: true
|
|
14086
|
+
});
|
|
14087
|
+
const elements = Array.from(fragment.children);
|
|
14088
|
+
const root = elements[0];
|
|
14089
|
+
if (elements.length !== 1 || root.namespaceURI !== 'http://www.w3.org/2000/svg' || root.localName !== 'svg') {
|
|
14090
|
+
return null;
|
|
14091
|
+
}
|
|
14092
|
+
return root;
|
|
14093
|
+
}
|
|
14094
|
+
createMarked(rendering) {
|
|
14095
|
+
return new Marked({
|
|
14096
|
+
gfm: true,
|
|
14097
|
+
breaks: false,
|
|
14098
|
+
async: false,
|
|
14099
|
+
renderer: {
|
|
14100
|
+
html(token) {
|
|
14101
|
+
return nhAssistantEscapeHtml(token.text);
|
|
14102
|
+
},
|
|
14103
|
+
image(token) {
|
|
14104
|
+
return nhAssistantEscapeHtml(token.text);
|
|
14105
|
+
},
|
|
14106
|
+
heading(token) {
|
|
14107
|
+
const text = this.parser.parseInline(token.tokens, this.parser.textRenderer);
|
|
14108
|
+
const heading = rendering.addHeading(text, token.depth);
|
|
14109
|
+
return `<h${token.depth} id="${nhAssistantEscapeHtml(heading.id)}">${this.parser.parseInline(token.tokens)}</h${token.depth}>\n`;
|
|
14110
|
+
},
|
|
14111
|
+
link(token) {
|
|
14112
|
+
const label = this.parser.parseInline(token.tokens);
|
|
14113
|
+
const href = rendering.hrefOf(token.href);
|
|
14114
|
+
if (!href) {
|
|
14115
|
+
return label;
|
|
14116
|
+
}
|
|
14117
|
+
const title = token.title ? ` title="${nhAssistantEscapeHtml(token.title)}"` : '';
|
|
14118
|
+
return `<a href="${nhAssistantEscapeHtml(href)}"${title}>${label}</a>`;
|
|
14119
|
+
}
|
|
14120
|
+
}
|
|
14121
|
+
});
|
|
14122
|
+
}
|
|
14123
|
+
sanitize(purifier, rendering, html) {
|
|
14124
|
+
this.current = rendering;
|
|
14125
|
+
try {
|
|
14126
|
+
return purifier.sanitize(html, {
|
|
14127
|
+
ALLOWED_TAGS: [...nhAssistantMarkdownTags],
|
|
14128
|
+
ALLOWED_ATTR: [...nhAssistantMarkdownAttributes, 'id'],
|
|
14129
|
+
ALLOWED_URI_REGEXP: /^(?:https?:|mailto:|#)/i,
|
|
14130
|
+
ALLOW_DATA_ATTR: false,
|
|
14131
|
+
ALLOW_ARIA_ATTR: false
|
|
14132
|
+
});
|
|
14133
|
+
}
|
|
14134
|
+
finally {
|
|
14135
|
+
this.current = null;
|
|
14136
|
+
}
|
|
14137
|
+
}
|
|
14138
|
+
createPurifier() {
|
|
14139
|
+
const view = this.document.defaultView;
|
|
14140
|
+
if (!view) {
|
|
14141
|
+
return null;
|
|
14142
|
+
}
|
|
14143
|
+
const purifier = createDOMPurify(view);
|
|
14144
|
+
return purifier.isSupported ? purifier : null;
|
|
14145
|
+
}
|
|
14146
|
+
getDocumentPurifier() {
|
|
14147
|
+
if (this.documentPurifier) {
|
|
14148
|
+
return this.documentPurifier;
|
|
14149
|
+
}
|
|
14150
|
+
const purifier = this.createPurifier();
|
|
14151
|
+
if (!purifier) {
|
|
14152
|
+
return null;
|
|
14153
|
+
}
|
|
14154
|
+
purifier.addHook('uponSanitizeAttribute', (_node, event) => {
|
|
14155
|
+
const rendering = this.current;
|
|
14156
|
+
if (event.attrName === 'href' && rendering?.bundleHrefs.has(event.attrValue)) {
|
|
14157
|
+
// A sibling document this rendering resolved itself; the URI pattern knows no paths.
|
|
14158
|
+
event.forceKeepAttr = true;
|
|
14159
|
+
}
|
|
14160
|
+
else if (event.attrName === 'id' && !(rendering && event.attrValue.startsWith(rendering.options.idPrefix))) {
|
|
14161
|
+
event.keepAttr = false;
|
|
14162
|
+
}
|
|
14163
|
+
});
|
|
14164
|
+
purifier.addHook('afterSanitizeAttributes', node => {
|
|
14165
|
+
const href = node.tagName === 'A' ? node.getAttribute('href') : null;
|
|
14166
|
+
if (href && nhAssistantExternalLinkPattern.test(href)) {
|
|
14167
|
+
node.setAttribute('target', '_blank');
|
|
14168
|
+
node.setAttribute('rel', 'noopener noreferrer');
|
|
14169
|
+
}
|
|
14170
|
+
});
|
|
14171
|
+
this.documentPurifier = purifier;
|
|
14172
|
+
return purifier;
|
|
14173
|
+
}
|
|
14174
|
+
getDiagramPurifier() {
|
|
14175
|
+
if (this.diagramPurifier) {
|
|
14176
|
+
return this.diagramPurifier;
|
|
14177
|
+
}
|
|
14178
|
+
const purifier = this.createPurifier();
|
|
14179
|
+
if (!purifier) {
|
|
14180
|
+
return null;
|
|
14181
|
+
}
|
|
14182
|
+
purifier.addHook('uponSanitizeElement', (node, event) => {
|
|
14183
|
+
if (event.tagName === 'style' && isUnsafeCss(node.textContent ?? '')) {
|
|
14184
|
+
node.textContent = '';
|
|
14185
|
+
}
|
|
14186
|
+
});
|
|
14187
|
+
purifier.addHook('uponSanitizeAttribute', (_node, event) => {
|
|
14188
|
+
const unsafe = event.attrName === 'style' ? isUnsafeCss(event.attrValue) : hasExternalReference(event.attrValue);
|
|
14189
|
+
if (unsafe) {
|
|
14190
|
+
event.keepAttr = false;
|
|
14191
|
+
}
|
|
14192
|
+
});
|
|
14193
|
+
this.diagramPurifier = purifier;
|
|
14194
|
+
return purifier;
|
|
14195
|
+
}
|
|
14196
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentMarkdownRenderer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
14197
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentMarkdownRenderer, providedIn: 'root' }); }
|
|
14198
|
+
}
|
|
14199
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentMarkdownRenderer, decorators: [{
|
|
14200
|
+
type: Injectable,
|
|
14201
|
+
args: [{ providedIn: 'root' }]
|
|
14202
|
+
}] });
|
|
14203
|
+
|
|
14204
|
+
/** Sizes the drawing inside its own shadow root, where the diagram's styles stay contained. */
|
|
14205
|
+
const canvasStyles = ':host { display: block; } svg { display: block; max-width: 100%; height: auto; margin: 0 auto; }';
|
|
14206
|
+
/**
|
|
14207
|
+
* One diagram of a document: the source while it is drawn or when no renderer draws it, the
|
|
14208
|
+
* sanitized SVG once drawn, and the source with the reason when it cannot be drawn. The SVG
|
|
14209
|
+
* goes into a shadow root, so its styles never reach the page. Internal to
|
|
14210
|
+
* `nh-assistant-document`.
|
|
14211
|
+
*/
|
|
14212
|
+
class NhAssistantDocumentDiagramComponent {
|
|
14213
|
+
failure() {
|
|
14214
|
+
const state = this.state();
|
|
14215
|
+
return state.kind === 'failed' ? state : null;
|
|
14216
|
+
}
|
|
14217
|
+
constructor() {
|
|
14218
|
+
this.markdown = inject(NhAssistantDocumentMarkdownRenderer);
|
|
14219
|
+
this.browser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
14220
|
+
this.canvas = viewChild.required('canvas');
|
|
14221
|
+
this.generation = 0;
|
|
14222
|
+
/** The block's text. */
|
|
14223
|
+
this.source = input.required(...(ngDevMode ? [{ debugName: "source" }] : []));
|
|
14224
|
+
/** The block's language in lower case. */
|
|
14225
|
+
this.language = input.required(...(ngDevMode ? [{ debugName: "language" }] : []));
|
|
14226
|
+
this.renderer = input(null, ...(ngDevMode ? [{ debugName: "renderer" }] : []));
|
|
14227
|
+
this.state = signal({ kind: 'source' }, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
14228
|
+
effect(() => {
|
|
14229
|
+
const source = this.source();
|
|
14230
|
+
const language = this.language();
|
|
14231
|
+
const renderer = this.renderer();
|
|
14232
|
+
untracked(() => {
|
|
14233
|
+
void this.draw(source, language, renderer);
|
|
14234
|
+
});
|
|
14235
|
+
});
|
|
14236
|
+
}
|
|
14237
|
+
async draw(source, language, renderer) {
|
|
14238
|
+
const generation = ++this.generation;
|
|
14239
|
+
if (!this.browser || !renderer) {
|
|
14240
|
+
this.state.set({ kind: 'source' });
|
|
14241
|
+
return;
|
|
14242
|
+
}
|
|
14243
|
+
this.state.set({ kind: 'drawing' });
|
|
14244
|
+
let svg;
|
|
14245
|
+
try {
|
|
14246
|
+
svg = await renderer.render(source, language);
|
|
14247
|
+
}
|
|
14248
|
+
catch (error) {
|
|
14249
|
+
if (generation === this.generation) {
|
|
14250
|
+
const reason = nhAssistantDiagramReason(error);
|
|
14251
|
+
this.state.set({ kind: 'failed', reason, reasonKey: reason ? null : 'nh-assistant.document.diagram-no-reason' });
|
|
14252
|
+
}
|
|
14253
|
+
return;
|
|
14254
|
+
}
|
|
14255
|
+
if (generation !== this.generation) {
|
|
14256
|
+
return;
|
|
14257
|
+
}
|
|
14258
|
+
const drawing = typeof svg === 'string' ? this.markdown.sanitizeDiagram(svg) : null;
|
|
14259
|
+
if (!drawing) {
|
|
14260
|
+
this.state.set({ kind: 'failed', reason: '', reasonKey: 'nh-assistant.document.diagram-not-svg' });
|
|
14261
|
+
return;
|
|
14262
|
+
}
|
|
14263
|
+
this.paint(drawing);
|
|
14264
|
+
this.state.set({ kind: 'drawn' });
|
|
14265
|
+
}
|
|
14266
|
+
paint(drawing) {
|
|
14267
|
+
const canvas = this.canvas().nativeElement;
|
|
14268
|
+
const shadow = canvas.shadowRoot ?? canvas.attachShadow({ mode: 'open' });
|
|
14269
|
+
const style = canvas.ownerDocument.createElement('style');
|
|
14270
|
+
style.textContent = canvasStyles;
|
|
14271
|
+
shadow.replaceChildren(style, drawing);
|
|
14272
|
+
}
|
|
14273
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentDiagramComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14274
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantDocumentDiagramComponent, isStandalone: true, selector: "nh-assistant-document-diagram", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: true, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: true, transformFunction: null }, renderer: { classPropertyName: "renderer", publicName: "renderer", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "canvas", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
14275
|
+
<figure class="diagram" [attr.data-diagram-state]="state().kind" [attr.aria-busy]="state().kind === 'drawing'">
|
|
14276
|
+
<div #canvas class="canvas" [hidden]="state().kind !== 'drawn'"></div>
|
|
14277
|
+
@if (state().kind !== 'drawn') {
|
|
14278
|
+
<pre class="source"><code>{{ source() }}</code></pre>
|
|
14279
|
+
}
|
|
14280
|
+
@if (failure(); as failed) {
|
|
14281
|
+
<figcaption class="failure" role="note">
|
|
14282
|
+
{{ 'nh-assistant.document.diagram-failed' | translate: { reason: failed.reasonKey ? (failed.reasonKey | translate) : failed.reason } }}
|
|
14283
|
+
</figcaption>
|
|
14284
|
+
}
|
|
14285
|
+
</figure>
|
|
14286
|
+
`, isInline: true, styles: [":host{display:block;margin:0 0 12px}.diagram{margin:0}.canvas{overflow-x:auto}.source{margin:0;overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}.failure{margin-top:6px;color:var(--nha-danger);font-size:13px}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14287
|
+
}
|
|
14288
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentDiagramComponent, decorators: [{
|
|
14289
|
+
type: Component,
|
|
14290
|
+
args: [{ selector: 'nh-assistant-document-diagram', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
14291
|
+
<figure class="diagram" [attr.data-diagram-state]="state().kind" [attr.aria-busy]="state().kind === 'drawing'">
|
|
14292
|
+
<div #canvas class="canvas" [hidden]="state().kind !== 'drawn'"></div>
|
|
14293
|
+
@if (state().kind !== 'drawn') {
|
|
14294
|
+
<pre class="source"><code>{{ source() }}</code></pre>
|
|
14295
|
+
}
|
|
14296
|
+
@if (failure(); as failed) {
|
|
14297
|
+
<figcaption class="failure" role="note">
|
|
14298
|
+
{{ 'nh-assistant.document.diagram-failed' | translate: { reason: failed.reasonKey ? (failed.reasonKey | translate) : failed.reason } }}
|
|
14299
|
+
</figcaption>
|
|
14300
|
+
}
|
|
14301
|
+
</figure>
|
|
14302
|
+
`, styles: [":host{display:block;margin:0 0 12px}.diagram{margin:0}.canvas{overflow-x:auto}.source{margin:0;overflow-x:auto;border-radius:8px;padding:8px;background:var(--nha-surface-strong);font-family:var(--nha-mono);font-size:12.5px}.failure{margin-top:6px;color:var(--nha-danger);font-size:13px}\n"] }]
|
|
14303
|
+
}], ctorParameters: () => [], propDecorators: { canvas: [{ type: i0.ViewChild, args: ['canvas', { isSignal: true }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: true }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: true }] }], renderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderer", required: false }] }] } });
|
|
14304
|
+
|
|
14305
|
+
let nextDocumentId = 0;
|
|
14306
|
+
function decoded(value, decode) {
|
|
14307
|
+
try {
|
|
14308
|
+
return decode(value);
|
|
14309
|
+
}
|
|
14310
|
+
catch {
|
|
14311
|
+
return value;
|
|
14312
|
+
}
|
|
14313
|
+
}
|
|
14314
|
+
/**
|
|
14315
|
+
* Renders an untrusted Markdown document, for example one file of a skill or knowledge bundle,
|
|
14316
|
+
* with the assistant's safety defaults: inline HTML shows as text, images as their alt text, and
|
|
14317
|
+
* a link keeps its address only for a heading of the document, a sibling of the bundle or an
|
|
14318
|
+
* `https:`, `http:` or `mailto:` address; `javascript:`, `data:` and every other scheme show as
|
|
14319
|
+
* text. Relative links resolve from the document's `path` against `siblingPaths`.
|
|
14320
|
+
*
|
|
14321
|
+
* Fenced code blocks of the languages of `diagramRenderer` become diagrams: the application's
|
|
14322
|
+
* renderer draws them, the document sanitizes its SVG and shows it in a shadow root, and a block
|
|
14323
|
+
* it cannot draw shows its source with the reason. Without a renderer they stay code.
|
|
14324
|
+
*
|
|
14325
|
+
* `linkClick` reports every link the reader activates; `headingsChange` the headings once they
|
|
14326
|
+
* are in the page. The texts are `nh-assistant.document.*`, which `provideNhAssistant` merges;
|
|
14327
|
+
* an application without it starts `NhAssistantTranslationMerger` or translates the keys itself.
|
|
14328
|
+
*/
|
|
14329
|
+
class NhAssistantDocumentComponent {
|
|
14330
|
+
constructor() {
|
|
14331
|
+
this.markdownRenderer = inject(NhAssistantDocumentMarkdownRenderer);
|
|
14332
|
+
this.sanitizer = inject(DomSanitizer);
|
|
14333
|
+
this.host = inject(ElementRef);
|
|
14334
|
+
this.idPrefix = `nh-document-${++nextDocumentId}-`;
|
|
14335
|
+
/** The document's Markdown. Treated as untrusted. */
|
|
14336
|
+
this.markdown = input.required(...(ngDevMode ? [{ debugName: "markdown" }] : []));
|
|
14337
|
+
/** The document's own path in its bundle, for example `guides/setup.md`. */
|
|
14338
|
+
this.path = input(null, ...(ngDevMode ? [{ debugName: "path" }] : []));
|
|
14339
|
+
/** The paths of the other documents in the bundle that its links may open. */
|
|
14340
|
+
this.siblingPaths = input([], ...(ngDevMode ? [{ debugName: "siblingPaths" }] : []));
|
|
14341
|
+
/** Draws the bundle's diagrams; the application loads its drawing library lazily. */
|
|
14342
|
+
this.diagramRenderer = input(null, ...(ngDevMode ? [{ debugName: "diagramRenderer" }] : []));
|
|
14343
|
+
/** A link the reader activated; see `NhAssistantDocumentLinkEvent`. */
|
|
14344
|
+
this.linkClick = output();
|
|
14345
|
+
/** The headings, in document order, each time they changed and are in the page. */
|
|
14346
|
+
this.headingsChange = output();
|
|
14347
|
+
this.rendered = computed(() => this.markdownRenderer.render(this.markdown() ?? '', {
|
|
14348
|
+
path: this.path(),
|
|
14349
|
+
siblingPaths: this.siblingPaths() ?? [],
|
|
14350
|
+
diagramLanguages: this.diagramRenderer()?.languages ?? [],
|
|
14351
|
+
idPrefix: this.idPrefix
|
|
14352
|
+
}), ...(ngDevMode ? [{ debugName: "rendered" }] : []));
|
|
14353
|
+
/** The headings of the rendered document. */
|
|
14354
|
+
this.headings = computed(() => this.rendered().headings, ...(ngDevMode ? [{ debugName: "headings" }] : []));
|
|
14355
|
+
this.parts = computed(() => this.rendered().segments.map(segment => {
|
|
14356
|
+
if (segment.kind === 'diagram') {
|
|
14357
|
+
return segment;
|
|
14358
|
+
}
|
|
14359
|
+
// DOMPurify sanitized the HTML; Angular's own sanitizer would drop the heading ids.
|
|
14360
|
+
return { kind: 'html', html: this.sanitizer.bypassSecurityTrustHtml(segment.html) };
|
|
14361
|
+
}), ...(ngDevMode ? [{ debugName: "parts" }] : []));
|
|
14362
|
+
afterRenderEffect(() => {
|
|
14363
|
+
this.headingsChange.emit(this.headings());
|
|
14364
|
+
});
|
|
14365
|
+
}
|
|
14366
|
+
/**
|
|
14367
|
+
* Scrolls to a heading of the document by its fragment and focuses it; false when the
|
|
14368
|
+
* document has no such heading.
|
|
14369
|
+
*/
|
|
14370
|
+
scrollToHeading(fragment) {
|
|
14371
|
+
const heading = this.headings().find(item => item.fragment === fragment);
|
|
14372
|
+
const element = heading ? this.host.nativeElement.querySelector(`[id="${CSS.escape(heading.id)}"]`) : null;
|
|
14373
|
+
if (!element) {
|
|
14374
|
+
return false;
|
|
14375
|
+
}
|
|
14376
|
+
if (!element.hasAttribute('tabindex')) {
|
|
14377
|
+
element.setAttribute('tabindex', '-1');
|
|
14378
|
+
}
|
|
14379
|
+
element.scrollIntoView({ block: 'start' });
|
|
14380
|
+
element.focus({ preventScroll: true });
|
|
14381
|
+
return true;
|
|
14382
|
+
}
|
|
14383
|
+
onClick(event) {
|
|
14384
|
+
const target = event.target instanceof Element ? event.target : null;
|
|
14385
|
+
const anchor = target?.closest('a[href]');
|
|
14386
|
+
if (!anchor || !this.host.nativeElement.contains(anchor)) {
|
|
14387
|
+
return;
|
|
14388
|
+
}
|
|
14389
|
+
const href = anchor.getAttribute('href') ?? '';
|
|
14390
|
+
if (href.startsWith('#')) {
|
|
14391
|
+
const fragment = decoded(href.slice(1), decodeURIComponent);
|
|
14392
|
+
event.preventDefault();
|
|
14393
|
+
this.scrollToHeading(fragment);
|
|
14394
|
+
this.linkClick.emit({ kind: 'anchor', href, path: null, fragment, event });
|
|
14395
|
+
return;
|
|
14396
|
+
}
|
|
14397
|
+
if (nhAssistantExternalLinkPattern.test(href)) {
|
|
14398
|
+
this.linkClick.emit({ kind: 'external', href, path: null, fragment: null, event });
|
|
14399
|
+
return;
|
|
14400
|
+
}
|
|
14401
|
+
// A sibling of the bundle: the application opens it, the browser does not navigate.
|
|
14402
|
+
event.preventDefault();
|
|
14403
|
+
const hashIndex = href.indexOf('#');
|
|
14404
|
+
const path = decoded(hashIndex >= 0 ? href.slice(0, hashIndex) : href, decodeURI);
|
|
14405
|
+
const fragment = hashIndex >= 0 ? decoded(href.slice(hashIndex + 1), decodeURIComponent) : null;
|
|
14406
|
+
this.linkClick.emit({ kind: 'document', href, path, fragment, event });
|
|
14407
|
+
}
|
|
14408
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14409
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantDocumentComponent, isStandalone: true, selector: "nh-assistant-document", inputs: { markdown: { classPropertyName: "markdown", publicName: "markdown", isSignal: true, isRequired: true, transformFunction: null }, path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: false, transformFunction: null }, siblingPaths: { classPropertyName: "siblingPaths", publicName: "siblingPaths", isSignal: true, isRequired: false, transformFunction: null }, diagramRenderer: { classPropertyName: "diagramRenderer", publicName: "diagramRenderer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { linkClick: "linkClick", headingsChange: "headingsChange" }, host: { listeners: { "click": "onClick($event)" }, classAttribute: "nh-assistant-document" }, ngImport: i0, template: "@for (part of parts(); track $index) {\n @if (part.kind === 'html') {\n <div class=\"document-part markdown\" [innerHTML]=\"part.html\"></div>\n } @else {\n <nh-assistant-document-diagram [source]=\"part.source\" [language]=\"part.language\" [renderer]=\"diagramRenderer()\" />\n }\n}\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;color:var(--nha-text);font-family:var(--nha-font);line-height:1.55}.document-part{display:contents}: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}: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 12px}: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:20px 0 8px;line-height:1.3;scroll-margin-top:16px}:host ::ng-deep .markdown h1{font-size:1.6em}:host ::ng-deep .markdown h2{font-size:1.35em}:host ::ng-deep .markdown h3{font-size:1.15em}:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{font-size:1em}:host ::ng-deep .markdown [tabindex=\"-1\"]:focus{outline:none}\n"], dependencies: [{ kind: "component", type: NhAssistantDocumentDiagramComponent, selector: "nh-assistant-document-diagram", inputs: ["source", "language", "renderer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14410
|
+
}
|
|
14411
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantDocumentComponent, decorators: [{
|
|
14412
|
+
type: Component,
|
|
14413
|
+
args: [{ selector: 'nh-assistant-document', standalone: true, imports: [NhAssistantDocumentDiagramComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
14414
|
+
class: 'nh-assistant-document',
|
|
14415
|
+
'(click)': 'onClick($event)'
|
|
14416
|
+
}, template: "@for (part of parts(); track $index) {\n @if (part.kind === 'html') {\n <div class=\"document-part markdown\" [innerHTML]=\"part.html\"></div>\n } @else {\n <nh-assistant-document-diagram [source]=\"part.source\" [language]=\"part.language\" [renderer]=\"diagramRenderer()\" />\n }\n}\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;color:var(--nha-text);font-family:var(--nha-font);line-height:1.55}.document-part{display:contents}: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}: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 12px}: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:20px 0 8px;line-height:1.3;scroll-margin-top:16px}:host ::ng-deep .markdown h1{font-size:1.6em}:host ::ng-deep .markdown h2{font-size:1.35em}:host ::ng-deep .markdown h3{font-size:1.15em}:host ::ng-deep .markdown h4,:host ::ng-deep .markdown h5,:host ::ng-deep .markdown h6{font-size:1em}:host ::ng-deep .markdown [tabindex=\"-1\"]:focus{outline:none}\n"] }]
|
|
14417
|
+
}], ctorParameters: () => [], propDecorators: { markdown: [{ type: i0.Input, args: [{ isSignal: true, alias: "markdown", required: true }] }], path: [{ type: i0.Input, args: [{ isSignal: true, alias: "path", required: false }] }], siblingPaths: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingPaths", required: false }] }], diagramRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "diagramRenderer", required: false }] }], linkClick: [{ type: i0.Output, args: ["linkClick"] }], headingsChange: [{ type: i0.Output, args: ["headingsChange"] }] } });
|
|
14418
|
+
|
|
12272
14419
|
let nextId = 0;
|
|
12273
14420
|
const searchDelayMs = 250;
|
|
12274
14421
|
/**
|
|
@@ -12511,5 +14658,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
12511
14658
|
* Generated bundle index. Do not edit.
|
|
12512
14659
|
*/
|
|
12513
14660
|
|
|
12514
|
-
export { NH_ASSISTANT_ACCESS_POLICY, NH_ASSISTANT_CONFIG, NH_ASSISTANT_CONVERSATION_FRAGMENT, NH_ASSISTANT_ERROR_CODES, NH_ASSISTANT_FEEDBACK_CATEGORIES, NH_ASSISTANT_FEEDBACK_GROUPS, NH_ASSISTANT_FETCH, NH_ASSISTANT_ICONS, NH_ASSISTANT_JOIN_FRAGMENT, NH_ASSISTANT_MAX_BULK_FEEDBACK, NH_ASSISTANT_MAX_CUSTOM_INSTRUCTIONS, NH_ASSISTANT_MAX_FEEDBACK_TEXT, NH_ASSISTANT_MAX_PROPOSAL_LOOKUP, NH_ASSISTANT_MAX_SUBJECT_SUMMARY, NH_ASSISTANT_MCP_AUTHORIZATION_MESSAGE, NH_ASSISTANT_MCP_AUTHORIZATION_WINDOW, NH_ASSISTANT_MESSAGE_QUEUED_NOTICE_CODE, NH_ASSISTANT_NO_ANSWER_NOTICE_CODE, NH_ASSISTANT_PAGE_CONTEXT_LIMITS, NH_ASSISTANT_PANEL_MOBILE_QUERY, NH_ASSISTANT_PANEL_WIDTH, NH_ASSISTANT_RESULT_PREVIEW_LENGTH, NH_ASSISTANT_RUN_HISTORY_MAX_PAGE, NH_ASSISTANT_RUN_RESULT_MAX_LENGTH, NH_ASSISTANT_SERVER_ERROR_CODES, NH_ASSISTANT_SSE_EVENT_TYPES, NH_ASSISTANT_SUBJECT_SEARCH, NH_ASSISTANT_SYSTEM_GLOBAL_ID, NH_ASSISTANT_SYSTEM_SUBJECT_TYPE, NH_ASSISTANT_TRANSLATIONS, NH_ASSISTANT_UPLOAD, NH_ASSISTANT_UPLOAD_HEADER, NH_ASSISTANT_VIRTUAL_SCROLL_THRESHOLD, NhAssistantActivityComponent, NhAssistantAdminApiService, NhAssistantAgentPickerComponent, NhAssistantAgentRunApiService, NhAssistantAllowAllAccessPolicy, NhAssistantApiError, NhAssistantApiService, NhAssistantApprovalCardComponent, NhAssistantClientErrorCodes, NhAssistantComposerComponent, NhAssistantConnectionRequiredComponent, NhAssistantConversationListComponent, NhAssistantLauncherComponent, NhAssistantLiveService, NhAssistantMcpConnectService, NhAssistantMcpConnectionsComponent, NhAssistantMcpPopupAuthorizationWindow, NhAssistantPanelComponent, NhAssistantPanelService, NhAssistantPreferencesComponent, NhAssistantProposalFeedbackComponent, NhAssistantPushService, NhAssistantShareComponent, NhAssistantSseParser, NhAssistantStore, NhAssistantSubjectBadgeComponent, NhAssistantSubjectSummaryService, NhAssistantThreadComponent, NhAssistantToolCallCardComponent, NhAssistantToolCallGroupComponent, NhAssistantTranslationMerger, applyNhAssistantApprovalDecision, applyNhAssistantConversationChange, applyNhAssistantEvent, applyNhAssistantLiveEvent, describeNhAssistantClientContext, formatNhAssistantCountdown, nhAssistantCodeForStatus, nhAssistantConnectMcp, nhAssistantErrorMessageKey, nhAssistantIsUnread, nhAssistantLatestTurnHasText, nhAssistantMcpAuthorizationFromFragment, nhAssistantShareLink, nhAssistantXhrUpload, normalizeNhAssistantClientContext, provideNhAssistant, toNhAssistantError, NH_ASSISTANT_DASH_CASE as ɵNH_ASSISTANT_DASH_CASE, NhAssistantIconComponent as ɵNhAssistantIconComponent, NhAssistantMarkdownPipe as ɵNhAssistantMarkdownPipe, NhAssistantPickerComponent as ɵNhAssistantPickerComponent, NhAssistantSubjectLinkComponent as ɵNhAssistantSubjectLinkComponent, NhAssistantTranslatePipe as ɵNhAssistantTranslatePipe, nhAssistantCodeKeys as ɵnhAssistantCodeKeys, nhAssistantErrorKeys as ɵnhAssistantErrorKeys, nhAssistantErrorOf as ɵnhAssistantErrorOf, nhAssistantMediaTypeOf as ɵnhAssistantMediaTypeOf, nhAssistantReloadOnAgentWork as ɵnhAssistantReloadOnAgentWork, nhAssistantWatchAgentWork as ɵnhAssistantWatchAgentWork, toNhAssistantError as ɵtoNhAssistantError };
|
|
14661
|
+
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, NhAssistantDocumentComponent, NhAssistantLauncherComponent, NhAssistantLiveService, NhAssistantMcpConnectService, NhAssistantMcpConnectionsComponent, NhAssistantMcpPopupAuthorizationWindow, NhAssistantPanelComponent, NhAssistantPanelService, NhAssistantPreferencesComponent, NhAssistantProposalFeedbackComponent, NhAssistantPushService, NhAssistantQuestionCardComponent, NhAssistantShareComponent, NhAssistantSseParser, NhAssistantStore, NhAssistantSubjectBadgeComponent, NhAssistantSubjectSummaryService, NhAssistantThreadComponent, NhAssistantToolCallCardComponent, NhAssistantToolCallGroupComponent, NhAssistantTranslationMerger, applyNhAssistantApprovalDecision, applyNhAssistantConversationChange, applyNhAssistantEvent, applyNhAssistantLiveEvent, applyNhAssistantQuestionAnswer, 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 };
|
|
12515
14662
|
//# sourceMappingURL=newheap-platform-ai-chat.mjs.map
|