@newheap/platform-ai-chat 0.19.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 +12 -1
- package/fesm2022/newheap-platform-ai-chat-admin.mjs +119 -26
- package/fesm2022/newheap-platform-ai-chat-admin.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-testing.mjs +363 -7
- package/fesm2022/newheap-platform-ai-chat-testing.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat.mjs +1074 -59
- package/fesm2022/newheap-platform-ai-chat.mjs.map +1 -1
- package/i18n/en.json +60 -3
- package/i18n/nl.json +60 -3
- package/index.d.ts +377 -16
- package/package.json +1 -1
- package/testing/index.d.ts +43 -2
|
@@ -3,7 +3,7 @@ import { inject, signal, DestroyRef, input, computed, ChangeDetectionStrategy, C
|
|
|
3
3
|
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
|
4
4
|
import { NhAssistantAdminApiService, ɵtoNhAssistantError as _toNhAssistantError, ɵnhAssistantErrorKeys as _nhAssistantErrorKeys, ɵNhAssistantIconComponent as _NhAssistantIconComponent, ɵNhAssistantTranslatePipe as _NhAssistantTranslatePipe, NhAssistantClientErrorCodes, NH_ASSISTANT_PACKAGE_LOCK_ALL, NH_ASSISTANT_PACKAGE_LOCK_FIELDS, ɵNhAssistantPickerComponent as _NhAssistantPickerComponent, ɵNH_ASSISTANT_DASH_CASE as _NH_ASSISTANT_DASH_CASE, NhAssistantPanelService, NH_ASSISTANT_FEEDBACK_CATEGORIES, NH_ASSISTANT_SYSTEM_SUBJECT_TYPE, ɵnhAssistantCodeKeys as _nhAssistantCodeKeys, ɵNhAssistantSubjectLinkComponent as _NhAssistantSubjectLinkComponent, NH_ASSISTANT_AGENT_PACKAGE_MAX_AGENTS, NH_ASSISTANT_AGENT_PACKAGE_MAX_BYTES, NhAssistantStore, nhAssistantErrorMessageKey, NhAssistantMcpConnectService, ɵnhAssistantErrorOf as _nhAssistantErrorOf } from '@newheap/platform-ai-chat';
|
|
5
5
|
import { DatePipe, NgComponentOutlet, DOCUMENT, DecimalPipe, PercentPipe, NgTemplateOutlet } from '@angular/common';
|
|
6
|
-
import { Subscription, forkJoin,
|
|
6
|
+
import { Subscription, forkJoin, map, startWith, of, switchMap, tap, defer, concat, merge, catchError } from 'rxjs';
|
|
7
7
|
import { NhAssistantRunResultComponent, ɵNhAssistantRunNowDialogComponent as _NhAssistantRunNowDialogComponent } from '@newheap/platform-ai-chat/agent-runs';
|
|
8
8
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
9
9
|
|
|
@@ -1326,6 +1326,16 @@ class NhAssistantAdminAgentEditorComponent {
|
|
|
1326
1326
|
this.cancelled = output();
|
|
1327
1327
|
this.uses = ['chat', 'background', 'both'];
|
|
1328
1328
|
this.id = `nh-assistant-agent-editor-${nextId$m++}`;
|
|
1329
|
+
this.language = toSignal(this.translate.onLangChange.pipe(map(event => event.lang), startWith(this.translate.currentLang)), { initialValue: this.translate.currentLang });
|
|
1330
|
+
/**
|
|
1331
|
+
* The agent's name in the title, as the agent list shows it: an agent in code names itself with a
|
|
1332
|
+
* translation key, which reads in the reader's language.
|
|
1333
|
+
*/
|
|
1334
|
+
this.titleName = computed(() => {
|
|
1335
|
+
this.language();
|
|
1336
|
+
const agent = this.agent();
|
|
1337
|
+
return agent ? agentDisplayName(this.translate, agent) : '';
|
|
1338
|
+
}, ...(ngDevMode ? [{ debugName: "titleName" }] : []));
|
|
1329
1339
|
this.max = NH_ASSISTANT_MAX_INSTRUCTIONS;
|
|
1330
1340
|
this.autonomyLevels = ['observe', 'explain', 'propose', 'simulate', 'execute'];
|
|
1331
1341
|
this.classifications = ['public', 'internal', 'confidential', 'restricted'];
|
|
@@ -1662,7 +1672,7 @@ class NhAssistantAdminAgentEditorComponent {
|
|
|
1662
1672
|
return typeof shown === 'string' && shown.length > 0 && shown !== text ? { key: text, shown } : null;
|
|
1663
1673
|
}
|
|
1664
1674
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1665
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAdminAgentEditorComponent, isStandalone: true, selector: "nh-assistant-admin-agent-editor", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: false, transformFunction: null }, tools: { classPropertyName: "tools", publicName: "tools", isSignal: true, isRequired: false, transformFunction: null }, servers: { classPropertyName: "servers", publicName: "servers", isSignal: true, isRequired: false, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, catalogUnavailable: { classPropertyName: "catalogUnavailable", publicName: "catalogUnavailable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", workRequested: "workRequested", cancelled: "cancelled" }, ngImport: i0, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (agent(); as current) {\n {{ 'nh-assistant.admin.agent-editor.edit-title' | translate: { name: current.displayName } }}\n } @else {\n {{ 'nh-assistant.admin.agent-editor.new-title' | translate }}\n }\n </h3>\n @if (agent(); as current) {\n <!-- Fields the agent's package locks show read-only below; unlinking makes them change here. -->\n <nh-assistant-package-lock [lock]=\"lock()\" [agentId]=\"current.id\" part=\"agent\" (unlinked)=\"onUnlinked()\" />\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.agent-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-id'\"\n [value]=\"agentId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"id + '-id-hint'\"\n [attr.aria-invalid]=\"submitted() && idInvalid() ? true : null\"\n (input)=\"agentId.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">\n <span [class.error-text]=\"submitted() && idInvalid()\">\n {{ (submitted() && idInvalid() ? 'nh-assistant.admin.invalid-id' : 'nh-assistant.admin.agent-editor.id-hint') | translate }}\n </span>\n </p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.agent-editor.display-name' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('displayName')\" /></label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [disabled]=\"locked('displayName')\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"submitted() && nameMissing() ? true : null\"\n [attr.aria-describedby]=\"id + '-name-hint'\"\n (input)=\"displayName.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-name-hint'\">\n @if (submitted() && nameMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n }\n </p>\n </div>\n </div>\n\n @if (choosesUse()) {\n <fieldset class=\"subsection\" data-agent-use [disabled]=\"locked('offeredInChat')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('offeredInChat')\" /></legend>\n <div class=\"uses\">\n @for (option of uses; track option) {\n <label class=\"use\" [class.selected]=\"use() === option\">\n <input type=\"radio\" [name]=\"id + '-use'\" [value]=\"option\" [checked]=\"use() === option\" (change)=\"use.set(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.use.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.use.' + option + '-hint' | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (isNew() && use() !== 'chat') {\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.use.next' | translate }}</p>\n }\n @if (isNew()) {\n <label class=\"check described\" data-switch-on-now>\n <input type=\"checkbox\" [checked]=\"switchOnNow()\" (change)=\"switchOnNow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.switch-on-now' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.switch-on-now-hint' | translate }}</span>\n </span>\n </label>\n @if (use() !== 'chat') {\n <!-- An agent that works on its own may first work in shadow, once it has run settings. -->\n <label class=\"check described\" data-starts-in-shadow>\n <input type=\"checkbox\" [checked]=\"startsInShadow()\" (change)=\"startsInShadow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.starts-in-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.starts-in-shadow-hint' | translate }}</span>\n </span>\n </label>\n }\n }\n </fieldset>\n\n @if (catalogUnavailable()) {\n <!-- Without the run catalog the kinds of objects and policies are unknown: what the agent works on stays as it is. -->\n <p class=\"message warning\" role=\"note\" data-catalog-unavailable>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.agent-editor.catalog-unavailable' | translate }}\n </p>\n } @else {\n <fieldset\n class=\"subsection\"\n data-works-on\n [disabled]=\"locked('worksOn')\"\n [attr.aria-describedby]=\"id + '-works-on-hint ' + id + '-works-on-error'\"\n [attr.aria-invalid]=\"(submitted() && worksOnMissing()) || fieldError('worksOn') ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.works-on.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('worksOn')\" /></legend>\n <p class=\"muted\" [id]=\"id + '-works-on-hint'\">{{ 'nh-assistant.admin.agent-editor.works-on.hint' | translate }}</p>\n <div class=\"uses\">\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'all'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"all\" [checked]=\"worksOnScope() === 'all'\" (change)=\"worksOnScope.set('all')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.all' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.all-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'types'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"types\" [checked]=\"worksOnScope() === 'types'\" (change)=\"worksOnScope.set('types')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.types' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.types-hint' | translate }}</span>\n </span>\n </label>\n </div>\n\n @if (worksOnScope() === 'types') {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.works-on.types' | translate\" data-works-on-types>\n @for (type of subjectTypes(); track type.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"worksOnTypes().includes(type.id)\" (change)=\"toggleWorksOnType(type.id, checked($event))\" />\n <span>{{ type.pluralName ?? type.name }} <span class=\"mono muted\">{{ type.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.no-types' | translate }}</p>\n }\n </div>\n @if (fieldError('worksOnSubjectTypes'); as key) {\n <p class=\"hint\"><span class=\"error-text\">{{ key | translate }}</span></p>\n } @else if (tooManyTypes()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.too-many' | translate }}</span></p>\n }\n }\n\n @if (knownTypes().length > 0) {\n <p class=\"hint\" data-known-types>{{ 'nh-assistant.admin.agent-editor.works-on.known' | translate: { types: knownTypes().join(', ') } }}</p>\n }\n\n <label class=\"check described\">\n <input type=\"checkbox\" [checked]=\"worksOnApplication()\" (change)=\"worksOnApplication.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.application' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.application-hint' | translate }}</span>\n </span>\n </label>\n\n @if (divisionsListed()) {\n <label class=\"check described\" data-per-division>\n <input\n type=\"checkbox\"\n [checked]=\"perDivision()\"\n [attr.aria-invalid]=\"fieldError('perDivision') ? true : null\"\n [attr.aria-describedby]=\"fieldError('perDivision') ? id + '-per-division-error' : null\"\n (change)=\"perDivision.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.per-division' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.per-division-hint' | translate }}</span>\n </span>\n </label>\n @if (fieldError('perDivision'); as key) {\n <p class=\"hint\" [id]=\"id + '-per-division-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n }\n\n <p class=\"hint\" [id]=\"id + '-works-on-error'\" aria-live=\"polite\">\n @if (submitted() && worksOnMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.missing' | translate }}</span>\n } @else if (fieldError('worksOn'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy' | translate }}</label>\n <select\n [id]=\"id + '-run-policy'\"\n [attr.aria-describedby]=\"id + '-run-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('runPolicy') ? true : null\"\n (change)=\"runPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"runPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"runPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-run-policy-hint'\">\n @if (fieldError('runPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.run-policy-hint' | translate }}\n }\n </p>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-view-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy' | translate }}</label>\n <select\n [id]=\"id + '-view-policy'\"\n [attr.aria-describedby]=\"id + '-view-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('viewPolicy') ? true : null\"\n (change)=\"viewPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"viewPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"viewPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-view-policy-hint'\">\n @if (fieldError('viewPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.view-policy-hint' | translate }}\n }\n </p>\n </div>\n </div>\n </fieldset>\n }\n }\n\n @if (agentGroups().length > 0 && !catalogUnavailable()) {\n <fieldset\n class=\"subsection\"\n data-agent-groups\n [attr.aria-describedby]=\"id + '-groups-hint ' + id + '-groups-error'\"\n [attr.aria-invalid]=\"groupsError() ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.groups.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-groups-hint'\">{{ 'nh-assistant.admin.agent-editor.groups.hint' | translate }}</p>\n @if (isVariant()) {\n <p class=\"hint\" data-groups-variant>{{ 'nh-assistant.admin.agent-editor.groups.shadow-variant' | translate }}</p>\n } @else {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.groups.title' | translate\">\n @for (group of agentGroups(); track group.id) {\n <label class=\"check described\" [attr.data-agent-group]=\"group.id\">\n <input type=\"checkbox\" [checked]=\"groups().includes(group.id)\" (change)=\"toggleGroup(group.id, checked($event))\" />\n <span>\n <strong>{{ group.name }}</strong>\n @if (group.description; as description) {\n <span class=\"muted\">{{ description }}</span>\n }\n @if (codeGroups().includes(group.id)) {\n <span class=\"muted\" data-group-in-code>{{ 'nh-assistant.admin.agent-editor.groups.in-code' | translate }}</span>\n }\n </span>\n </label>\n }\n </div>\n }\n <p class=\"hint\" [id]=\"id + '-groups-error'\" aria-live=\"polite\">\n @if (groupsError(); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n </fieldset>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.agent-editor.description' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('description')\" /></label>\n <input type=\"text\" [id]=\"id + '-description'\" [disabled]=\"locked('description')\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <!-- The instructions, from text or an asset, lock together. -->\n <fieldset class=\"stack\" data-agent-instructions [disabled]=\"locked('instructions')\">\n @if (choosesUse()) {\n <nh-assistant-instructions-asset\n [idPrefix]=\"id + '-instructions'\"\n [available]=\"assetsAvailable()\"\n [(source)]=\"instructionsSource\"\n [(reference)]=\"instructionsAsset\"\n [problem]=\"assetProblem()\"\n [error]=\"assetError()\" />\n }\n @if (instructionsSource() === 'inline') {\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('instructions')\" /></label>\n <textarea\n rows=\"8\"\n [id]=\"id + '-instructions'\"\n [value]=\"instructions()\"\n [attr.aria-describedby]=\"id + '-instructions-hint'\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"instructions.set(value($event))\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span [class.error-text]=\"tooLong()\">\n {{ (tooLong() ? 'nh-assistant.admin.too-long' : 'nh-assistant.admin.agent-editor.instructions-hint') | translate }}\n </span>\n <span class=\"counter\" [class.error-text]=\"tooLong()\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: max } }}</span>\n </p>\n </div>\n }\n </fieldset>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('autonomy')\" /></label>\n <select [id]=\"id + '-autonomy'\" [disabled]=\"locked('autonomy')\" [attr.aria-describedby]=\"id + '-autonomy-hint'\" (change)=\"autonomy.set($any(value($event)))\">\n @for (level of autonomyLevels; track level) {\n <option [value]=\"level\" [selected]=\"autonomy() === level\">{{ 'nh-assistant.admin.agents.autonomy.' + level | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-autonomy-hint'\">{{ 'nh-assistant.admin.agent-editor.autonomy-hint' | translate }}</p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.agent-editor.required-policy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('requiredPolicy')\" /></label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\n [disabled]=\"locked('requiredPolicy')\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"id + '-policy-hint'\"\n (input)=\"requiredPolicy.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.agent-editor.required-policy-hint' | translate }}</p>\n </div>\n\n @if (choosesProfile()) {\n <div class=\"field\" data-agent-profile>\n <label [for]=\"id + '-profile'\">{{ 'nh-assistant.admin.agent-editor.profile' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('profile')\" /></label>\n <select\n [id]=\"id + '-profile'\"\n [disabled]=\"locked('profile')\"\n [attr.aria-describedby]=\"id + '-profile-hint' + (fieldError('profile') ? ' ' + id + '-profile-error' : '')\"\n [attr.aria-invalid]=\"fieldError('profile') ? true : null\"\n (change)=\"profile.set(value($event))\">\n @if (isNew()) {\n <option value=\"\" [selected]=\"profile() === ''\">{{ 'nh-assistant.admin.agent-editor.profile-default' | translate }}</option>\n }\n @for (name of profileChoices(); track name) {\n <option [value]=\"name\" [selected]=\"profile() === name\">{{ name }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-profile-hint'\">{{ 'nh-assistant.admin.agent-editor.profile-hint' | translate }}</p>\n @if (fieldError('profile'); as key) {\n <p class=\"hint\" [id]=\"id + '-profile-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n\n @if (choosesUse()) {\n <div class=\"field\" data-agent-classification>\n <label [for]=\"id + '-classification'\">{{ 'nh-assistant.admin.agent-editor.classification' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('dataClassification')\" /></label>\n <select\n [id]=\"id + '-classification'\"\n [disabled]=\"locked('dataClassification')\"\n [attr.aria-describedby]=\"id + '-classification-hint' + (fieldError('dataClassification') ? ' ' + id + '-classification-error' : '')\"\n [attr.aria-invalid]=\"fieldError('dataClassification') ? true : null\"\n (change)=\"dataClassification.set($any(value($event)))\">\n @for (classification of classifications; track classification) {\n <option [value]=\"classification\" [selected]=\"dataClassification() === classification\">\n {{ 'nh-assistant.admin.run-config.skills.classification.' + classification | translate }}\n </option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-classification-hint'\">{{ 'nh-assistant.admin.agent-editor.classification-hint' | translate }}</p>\n @for (warning of warnings(); track warning) {\n <p class=\"message warning\" [attr.data-agent-editor-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n @if (fieldError('dataClassification'); as key) {\n <p class=\"hint\" [id]=\"id + '-classification-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n </div>\n\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.state-hint' | translate }}</p>\n\n <fieldset class=\"subsection\" data-agent-tool-selectors [disabled]=\"locked('toolSelectors')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('toolSelectors')\" /></legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.tool-selectors-hint' | translate }}</p>\n\n @if (toolSelectors().length === 0) {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n } @else {\n <ul class=\"chips\">\n @for (selector of toolSelectors(); track selector) {\n <li class=\"chip\">\n <span>{{ selector }}</span>\n <button\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n [attr.title]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n (click)=\"removeSelector(selector)\">\n <nh-assistant-icon name=\"x\" />\n </button>\n </li>\n }\n </ul>\n <p class=\"muted\" role=\"status\">{{ 'nh-assistant.admin.agent-editor.matches' | translate: { count: matchCount() } }}</p>\n }\n\n <div class=\"inline\">\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.add-selector' | translate\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.selector-placeholder' | translate\"\n [attr.aria-invalid]=\"selectorInvalid() ? true : null\"\n [value]=\"newSelector()\"\n (input)=\"newSelector.set(value($event))\"\n (keydown)=\"onSelectorKeydown($event)\" />\n <button class=\"secondary\" type=\"button\" [disabled]=\"newSelector().trim().length === 0 || selectorInvalid()\" (click)=\"addSelector()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agent-editor.add-selector' | translate }}\n </button>\n </div>\n\n <div class=\"field\">\n <label class=\"label\" [for]=\"id + '-catalog-filter'\">{{ 'nh-assistant.admin.agent-editor.catalog' | translate }}</label>\n <input\n type=\"search\"\n [id]=\"id + '-catalog-filter'\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.catalog-filter' | translate\"\n [value]=\"catalogFilter()\"\n (input)=\"catalogFilter.set(value($event))\" />\n <ul class=\"catalog\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.catalog' | translate\">\n @for (tool of filteredTools(); track tool.id) {\n <li>\n <label>\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(tool.id) || isCovered(tool.id)\"\n [disabled]=\"isCovered(tool.id)\"\n (change)=\"toggleTool(tool.id, checked($event))\" />\n <span class=\"tool-id\">{{ tool.id }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.source.' + tool.source | translate }}</span>\n <span class=\"badge\" [class.warning]=\"tool.effect !== 'read-only'\">{{ 'nh-assistant.admin.effect.' + tool.effect | translate }}</span>\n <span class=\"muted\">{{ tool.description }}</span>\n </label>\n </li>\n } @empty {\n <li class=\"muted\">{{ 'nh-assistant.admin.agent-editor.catalog-empty' | translate }}</li>\n }\n </ul>\n </div>\n </fieldset>\n\n <fieldset class=\"subsection\">\n <legend>{{ 'nh-assistant.admin.agent-editor.mcp-servers' | translate }}</legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-hint' | translate }}</p>\n @for (server of servers(); track server.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"mcpServerIds().includes(server.id)\" (change)=\"toggleServer(server.id, checked($event))\" />\n <span>{{ server.displayName }} <span class=\"mono muted\">{{ server.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-empty' | translate }}</p>\n }\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=\"secondary\" type=\"button\" (click)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"saving() || tooLong()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\n\n<nh-assistant-agent-metadata [agent]=\"metadataAgent()\" [entries]=\"metadataEntries()\" (agentVersionChanged)=\"fieldsChanged($event)\" />\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAgentMetadataComponent, selector: "nh-assistant-agent-metadata", inputs: ["agent", "entries"], outputs: ["agentVersionChanged"] }, { kind: "component", type: NhAssistantInstructionsAssetComponent, selector: "nh-assistant-instructions-asset", inputs: ["idPrefix", "available", "source", "reference", "problem", "error"], outputs: ["sourceChange", "referenceChange", "touched"] }, { kind: "component", type: NhAssistantPackageLockComponent, selector: "nh-assistant-package-lock", inputs: ["lock", "agentId", "part", "unlinkable"], outputs: ["unlinked"] }, { kind: "component", type: NhAssistantPackageLockedMarkComponent, selector: "nh-assistant-package-locked-mark", inputs: ["lock"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1675
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAdminAgentEditorComponent, isStandalone: true, selector: "nh-assistant-admin-agent-editor", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: false, transformFunction: null }, tools: { classPropertyName: "tools", publicName: "tools", isSignal: true, isRequired: false, transformFunction: null }, servers: { classPropertyName: "servers", publicName: "servers", isSignal: true, isRequired: false, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, catalogUnavailable: { classPropertyName: "catalogUnavailable", publicName: "catalogUnavailable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", workRequested: "workRequested", cancelled: "cancelled" }, ngImport: i0, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (agent()) {\n {{ 'nh-assistant.admin.agent-editor.edit-title' | translate: { name: titleName() } }}\n } @else {\n {{ 'nh-assistant.admin.agent-editor.new-title' | translate }}\n }\n </h3>\n @if (agent(); as current) {\n <!-- Fields the agent's package locks show read-only below; unlinking makes them change here. -->\n <nh-assistant-package-lock [lock]=\"lock()\" [agentId]=\"current.id\" part=\"agent\" (unlinked)=\"onUnlinked()\" />\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.agent-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-id'\"\n [value]=\"agentId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"id + '-id-hint'\"\n [attr.aria-invalid]=\"submitted() && idInvalid() ? true : null\"\n (input)=\"agentId.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">\n <span [class.error-text]=\"submitted() && idInvalid()\">\n {{ (submitted() && idInvalid() ? 'nh-assistant.admin.invalid-id' : 'nh-assistant.admin.agent-editor.id-hint') | translate }}\n </span>\n </p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.agent-editor.display-name' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('displayName')\" /></label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [disabled]=\"locked('displayName')\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"submitted() && nameMissing() ? true : null\"\n [attr.aria-describedby]=\"id + '-name-hint'\"\n (input)=\"displayName.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-name-hint'\">\n @if (submitted() && nameMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n }\n </p>\n </div>\n </div>\n\n @if (choosesUse()) {\n <fieldset class=\"subsection\" data-agent-use [disabled]=\"locked('offeredInChat')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('offeredInChat')\" /></legend>\n <div class=\"uses\">\n @for (option of uses; track option) {\n <label class=\"use\" [class.selected]=\"use() === option\">\n <input type=\"radio\" [name]=\"id + '-use'\" [value]=\"option\" [checked]=\"use() === option\" (change)=\"use.set(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.use.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.use.' + option + '-hint' | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (isNew() && use() !== 'chat') {\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.use.next' | translate }}</p>\n }\n @if (isNew()) {\n <label class=\"check described\" data-switch-on-now>\n <input type=\"checkbox\" [checked]=\"switchOnNow()\" (change)=\"switchOnNow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.switch-on-now' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.switch-on-now-hint' | translate }}</span>\n </span>\n </label>\n @if (use() !== 'chat') {\n <!-- An agent that works on its own may first work in shadow, once it has run settings. -->\n <label class=\"check described\" data-starts-in-shadow>\n <input type=\"checkbox\" [checked]=\"startsInShadow()\" (change)=\"startsInShadow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.starts-in-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.starts-in-shadow-hint' | translate }}</span>\n </span>\n </label>\n }\n }\n </fieldset>\n\n @if (catalogUnavailable()) {\n <!-- Without the run catalog the kinds of objects and policies are unknown: what the agent works on stays as it is. -->\n <p class=\"message warning\" role=\"note\" data-catalog-unavailable>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.agent-editor.catalog-unavailable' | translate }}\n </p>\n } @else {\n <fieldset\n class=\"subsection\"\n data-works-on\n [disabled]=\"locked('worksOn')\"\n [attr.aria-describedby]=\"id + '-works-on-hint ' + id + '-works-on-error'\"\n [attr.aria-invalid]=\"(submitted() && worksOnMissing()) || fieldError('worksOn') ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.works-on.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('worksOn')\" /></legend>\n <p class=\"muted\" [id]=\"id + '-works-on-hint'\">{{ 'nh-assistant.admin.agent-editor.works-on.hint' | translate }}</p>\n <div class=\"uses\">\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'all'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"all\" [checked]=\"worksOnScope() === 'all'\" (change)=\"worksOnScope.set('all')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.all' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.all-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'types'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"types\" [checked]=\"worksOnScope() === 'types'\" (change)=\"worksOnScope.set('types')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.types' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.types-hint' | translate }}</span>\n </span>\n </label>\n </div>\n\n @if (worksOnScope() === 'types') {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.works-on.types' | translate\" data-works-on-types>\n @for (type of subjectTypes(); track type.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"worksOnTypes().includes(type.id)\" (change)=\"toggleWorksOnType(type.id, checked($event))\" />\n <span>{{ type.pluralName ?? type.name }} <span class=\"mono muted\">{{ type.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.no-types' | translate }}</p>\n }\n </div>\n @if (fieldError('worksOnSubjectTypes'); as key) {\n <p class=\"hint\"><span class=\"error-text\">{{ key | translate }}</span></p>\n } @else if (tooManyTypes()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.too-many' | translate }}</span></p>\n }\n }\n\n @if (knownTypes().length > 0) {\n <p class=\"hint\" data-known-types>{{ 'nh-assistant.admin.agent-editor.works-on.known' | translate: { types: knownTypes().join(', ') } }}</p>\n }\n\n <label class=\"check described\">\n <input type=\"checkbox\" [checked]=\"worksOnApplication()\" (change)=\"worksOnApplication.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.application' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.application-hint' | translate }}</span>\n </span>\n </label>\n\n @if (divisionsListed()) {\n <label class=\"check described\" data-per-division>\n <input\n type=\"checkbox\"\n [checked]=\"perDivision()\"\n [attr.aria-invalid]=\"fieldError('perDivision') ? true : null\"\n [attr.aria-describedby]=\"fieldError('perDivision') ? id + '-per-division-error' : null\"\n (change)=\"perDivision.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.per-division' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.per-division-hint' | translate }}</span>\n </span>\n </label>\n @if (fieldError('perDivision'); as key) {\n <p class=\"hint\" [id]=\"id + '-per-division-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n }\n\n <p class=\"hint\" [id]=\"id + '-works-on-error'\" aria-live=\"polite\">\n @if (submitted() && worksOnMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.missing' | translate }}</span>\n } @else if (fieldError('worksOn'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy' | translate }}</label>\n <select\n [id]=\"id + '-run-policy'\"\n [attr.aria-describedby]=\"id + '-run-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('runPolicy') ? true : null\"\n (change)=\"runPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"runPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"runPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-run-policy-hint'\">\n @if (fieldError('runPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.run-policy-hint' | translate }}\n }\n </p>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-view-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy' | translate }}</label>\n <select\n [id]=\"id + '-view-policy'\"\n [attr.aria-describedby]=\"id + '-view-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('viewPolicy') ? true : null\"\n (change)=\"viewPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"viewPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"viewPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-view-policy-hint'\">\n @if (fieldError('viewPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.view-policy-hint' | translate }}\n }\n </p>\n </div>\n </div>\n </fieldset>\n }\n }\n\n @if (agentGroups().length > 0 && !catalogUnavailable()) {\n <fieldset\n class=\"subsection\"\n data-agent-groups\n [attr.aria-describedby]=\"id + '-groups-hint ' + id + '-groups-error'\"\n [attr.aria-invalid]=\"groupsError() ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.groups.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-groups-hint'\">{{ 'nh-assistant.admin.agent-editor.groups.hint' | translate }}</p>\n @if (isVariant()) {\n <p class=\"hint\" data-groups-variant>{{ 'nh-assistant.admin.agent-editor.groups.shadow-variant' | translate }}</p>\n } @else {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.groups.title' | translate\">\n @for (group of agentGroups(); track group.id) {\n <label class=\"check described\" [attr.data-agent-group]=\"group.id\">\n <input type=\"checkbox\" [checked]=\"groups().includes(group.id)\" (change)=\"toggleGroup(group.id, checked($event))\" />\n <span>\n <strong>{{ group.name }}</strong>\n @if (group.description; as description) {\n <span class=\"muted\">{{ description }}</span>\n }\n @if (codeGroups().includes(group.id)) {\n <span class=\"muted\" data-group-in-code>{{ 'nh-assistant.admin.agent-editor.groups.in-code' | translate }}</span>\n }\n </span>\n </label>\n }\n </div>\n }\n <p class=\"hint\" [id]=\"id + '-groups-error'\" aria-live=\"polite\">\n @if (groupsError(); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n </fieldset>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.agent-editor.description' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('description')\" /></label>\n <input type=\"text\" [id]=\"id + '-description'\" [disabled]=\"locked('description')\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <!-- The instructions, from text or an asset, lock together. -->\n <fieldset class=\"stack\" data-agent-instructions [disabled]=\"locked('instructions')\">\n @if (choosesUse()) {\n <nh-assistant-instructions-asset\n [idPrefix]=\"id + '-instructions'\"\n [available]=\"assetsAvailable()\"\n [(source)]=\"instructionsSource\"\n [(reference)]=\"instructionsAsset\"\n [problem]=\"assetProblem()\"\n [error]=\"assetError()\" />\n }\n @if (instructionsSource() === 'inline') {\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('instructions')\" /></label>\n <textarea\n rows=\"8\"\n [id]=\"id + '-instructions'\"\n [value]=\"instructions()\"\n [attr.aria-describedby]=\"id + '-instructions-hint'\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"instructions.set(value($event))\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span [class.error-text]=\"tooLong()\">\n {{ (tooLong() ? 'nh-assistant.admin.too-long' : 'nh-assistant.admin.agent-editor.instructions-hint') | translate }}\n </span>\n <span class=\"counter\" [class.error-text]=\"tooLong()\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: max } }}</span>\n </p>\n </div>\n }\n </fieldset>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('autonomy')\" /></label>\n <select [id]=\"id + '-autonomy'\" [disabled]=\"locked('autonomy')\" [attr.aria-describedby]=\"id + '-autonomy-hint'\" (change)=\"autonomy.set($any(value($event)))\">\n @for (level of autonomyLevels; track level) {\n <option [value]=\"level\" [selected]=\"autonomy() === level\">{{ 'nh-assistant.admin.agents.autonomy.' + level | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-autonomy-hint'\">{{ 'nh-assistant.admin.agent-editor.autonomy-hint' | translate }}</p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.agent-editor.required-policy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('requiredPolicy')\" /></label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\n [disabled]=\"locked('requiredPolicy')\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"id + '-policy-hint'\"\n (input)=\"requiredPolicy.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.agent-editor.required-policy-hint' | translate }}</p>\n </div>\n\n @if (choosesProfile()) {\n <div class=\"field\" data-agent-profile>\n <label [for]=\"id + '-profile'\">{{ 'nh-assistant.admin.agent-editor.profile' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('profile')\" /></label>\n <select\n [id]=\"id + '-profile'\"\n [disabled]=\"locked('profile')\"\n [attr.aria-describedby]=\"id + '-profile-hint' + (fieldError('profile') ? ' ' + id + '-profile-error' : '')\"\n [attr.aria-invalid]=\"fieldError('profile') ? true : null\"\n (change)=\"profile.set(value($event))\">\n @if (isNew()) {\n <option value=\"\" [selected]=\"profile() === ''\">{{ 'nh-assistant.admin.agent-editor.profile-default' | translate }}</option>\n }\n @for (name of profileChoices(); track name) {\n <option [value]=\"name\" [selected]=\"profile() === name\">{{ name }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-profile-hint'\">{{ 'nh-assistant.admin.agent-editor.profile-hint' | translate }}</p>\n @if (fieldError('profile'); as key) {\n <p class=\"hint\" [id]=\"id + '-profile-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n\n @if (choosesUse()) {\n <div class=\"field\" data-agent-classification>\n <label [for]=\"id + '-classification'\">{{ 'nh-assistant.admin.agent-editor.classification' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('dataClassification')\" /></label>\n <select\n [id]=\"id + '-classification'\"\n [disabled]=\"locked('dataClassification')\"\n [attr.aria-describedby]=\"id + '-classification-hint' + (fieldError('dataClassification') ? ' ' + id + '-classification-error' : '')\"\n [attr.aria-invalid]=\"fieldError('dataClassification') ? true : null\"\n (change)=\"dataClassification.set($any(value($event)))\">\n @for (classification of classifications; track classification) {\n <option [value]=\"classification\" [selected]=\"dataClassification() === classification\">\n {{ 'nh-assistant.admin.run-config.skills.classification.' + classification | translate }}\n </option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-classification-hint'\">{{ 'nh-assistant.admin.agent-editor.classification-hint' | translate }}</p>\n @for (warning of warnings(); track warning) {\n <p class=\"message warning\" [attr.data-agent-editor-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n @if (fieldError('dataClassification'); as key) {\n <p class=\"hint\" [id]=\"id + '-classification-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n </div>\n\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.state-hint' | translate }}</p>\n\n <fieldset class=\"subsection\" data-agent-tool-selectors [disabled]=\"locked('toolSelectors')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('toolSelectors')\" /></legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.tool-selectors-hint' | translate }}</p>\n\n @if (toolSelectors().length === 0) {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n } @else {\n <ul class=\"chips\">\n @for (selector of toolSelectors(); track selector) {\n <li class=\"chip\">\n <span>{{ selector }}</span>\n <button\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n [attr.title]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n (click)=\"removeSelector(selector)\">\n <nh-assistant-icon name=\"x\" />\n </button>\n </li>\n }\n </ul>\n <p class=\"muted\" role=\"status\">{{ 'nh-assistant.admin.agent-editor.matches' | translate: { count: matchCount() } }}</p>\n }\n\n <div class=\"inline\">\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.add-selector' | translate\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.selector-placeholder' | translate\"\n [attr.aria-invalid]=\"selectorInvalid() ? true : null\"\n [value]=\"newSelector()\"\n (input)=\"newSelector.set(value($event))\"\n (keydown)=\"onSelectorKeydown($event)\" />\n <button class=\"secondary\" type=\"button\" [disabled]=\"newSelector().trim().length === 0 || selectorInvalid()\" (click)=\"addSelector()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agent-editor.add-selector' | translate }}\n </button>\n </div>\n\n <div class=\"field\">\n <label class=\"label\" [for]=\"id + '-catalog-filter'\">{{ 'nh-assistant.admin.agent-editor.catalog' | translate }}</label>\n <input\n type=\"search\"\n [id]=\"id + '-catalog-filter'\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.catalog-filter' | translate\"\n [value]=\"catalogFilter()\"\n (input)=\"catalogFilter.set(value($event))\" />\n <ul class=\"catalog\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.catalog' | translate\">\n @for (tool of filteredTools(); track tool.id) {\n <li>\n <label>\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(tool.id) || isCovered(tool.id)\"\n [disabled]=\"isCovered(tool.id)\"\n (change)=\"toggleTool(tool.id, checked($event))\" />\n <span class=\"tool-id\">{{ tool.id }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.source.' + tool.source | translate }}</span>\n <span class=\"badge\" [class.warning]=\"tool.effect !== 'read-only'\">{{ 'nh-assistant.admin.effect.' + tool.effect | translate }}</span>\n <span class=\"muted\">{{ tool.description }}</span>\n </label>\n </li>\n } @empty {\n <li class=\"muted\">{{ 'nh-assistant.admin.agent-editor.catalog-empty' | translate }}</li>\n }\n </ul>\n </div>\n </fieldset>\n\n <fieldset class=\"subsection\">\n <legend>{{ 'nh-assistant.admin.agent-editor.mcp-servers' | translate }}</legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-hint' | translate }}</p>\n @for (server of servers(); track server.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"mcpServerIds().includes(server.id)\" (change)=\"toggleServer(server.id, checked($event))\" />\n <span>{{ server.displayName }} <span class=\"mono muted\">{{ server.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-empty' | translate }}</p>\n }\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=\"secondary\" type=\"button\" (click)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"saving() || tooLong()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\n\n<nh-assistant-agent-metadata [agent]=\"metadataAgent()\" [entries]=\"metadataEntries()\" (agentVersionChanged)=\"fieldsChanged($event)\" />\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAgentMetadataComponent, selector: "nh-assistant-agent-metadata", inputs: ["agent", "entries"], outputs: ["agentVersionChanged"] }, { kind: "component", type: NhAssistantInstructionsAssetComponent, selector: "nh-assistant-instructions-asset", inputs: ["idPrefix", "available", "source", "reference", "problem", "error"], outputs: ["sourceChange", "referenceChange", "touched"] }, { kind: "component", type: NhAssistantPackageLockComponent, selector: "nh-assistant-package-lock", inputs: ["lock", "agentId", "part", "unlinkable"], outputs: ["unlinked"] }, { kind: "component", type: NhAssistantPackageLockedMarkComponent, selector: "nh-assistant-package-locked-mark", inputs: ["lock"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1666
1676
|
}
|
|
1667
1677
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentEditorComponent, decorators: [{
|
|
1668
1678
|
type: Component,
|
|
@@ -1674,7 +1684,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
1674
1684
|
NhAssistantInstructionsAssetComponent,
|
|
1675
1685
|
NhAssistantPackageLockComponent,
|
|
1676
1686
|
NhAssistantPackageLockedMarkComponent
|
|
1677
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (agent(); as current) {\n {{ 'nh-assistant.admin.agent-editor.edit-title' | translate: { name: current.displayName } }}\n } @else {\n {{ 'nh-assistant.admin.agent-editor.new-title' | translate }}\n }\n </h3>\n @if (agent(); as current) {\n <!-- Fields the agent's package locks show read-only below; unlinking makes them change here. -->\n <nh-assistant-package-lock [lock]=\"lock()\" [agentId]=\"current.id\" part=\"agent\" (unlinked)=\"onUnlinked()\" />\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.agent-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-id'\"\n [value]=\"agentId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"id + '-id-hint'\"\n [attr.aria-invalid]=\"submitted() && idInvalid() ? true : null\"\n (input)=\"agentId.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">\n <span [class.error-text]=\"submitted() && idInvalid()\">\n {{ (submitted() && idInvalid() ? 'nh-assistant.admin.invalid-id' : 'nh-assistant.admin.agent-editor.id-hint') | translate }}\n </span>\n </p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.agent-editor.display-name' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('displayName')\" /></label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [disabled]=\"locked('displayName')\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"submitted() && nameMissing() ? true : null\"\n [attr.aria-describedby]=\"id + '-name-hint'\"\n (input)=\"displayName.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-name-hint'\">\n @if (submitted() && nameMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n }\n </p>\n </div>\n </div>\n\n @if (choosesUse()) {\n <fieldset class=\"subsection\" data-agent-use [disabled]=\"locked('offeredInChat')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('offeredInChat')\" /></legend>\n <div class=\"uses\">\n @for (option of uses; track option) {\n <label class=\"use\" [class.selected]=\"use() === option\">\n <input type=\"radio\" [name]=\"id + '-use'\" [value]=\"option\" [checked]=\"use() === option\" (change)=\"use.set(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.use.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.use.' + option + '-hint' | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (isNew() && use() !== 'chat') {\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.use.next' | translate }}</p>\n }\n @if (isNew()) {\n <label class=\"check described\" data-switch-on-now>\n <input type=\"checkbox\" [checked]=\"switchOnNow()\" (change)=\"switchOnNow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.switch-on-now' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.switch-on-now-hint' | translate }}</span>\n </span>\n </label>\n @if (use() !== 'chat') {\n <!-- An agent that works on its own may first work in shadow, once it has run settings. -->\n <label class=\"check described\" data-starts-in-shadow>\n <input type=\"checkbox\" [checked]=\"startsInShadow()\" (change)=\"startsInShadow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.starts-in-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.starts-in-shadow-hint' | translate }}</span>\n </span>\n </label>\n }\n }\n </fieldset>\n\n @if (catalogUnavailable()) {\n <!-- Without the run catalog the kinds of objects and policies are unknown: what the agent works on stays as it is. -->\n <p class=\"message warning\" role=\"note\" data-catalog-unavailable>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.agent-editor.catalog-unavailable' | translate }}\n </p>\n } @else {\n <fieldset\n class=\"subsection\"\n data-works-on\n [disabled]=\"locked('worksOn')\"\n [attr.aria-describedby]=\"id + '-works-on-hint ' + id + '-works-on-error'\"\n [attr.aria-invalid]=\"(submitted() && worksOnMissing()) || fieldError('worksOn') ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.works-on.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('worksOn')\" /></legend>\n <p class=\"muted\" [id]=\"id + '-works-on-hint'\">{{ 'nh-assistant.admin.agent-editor.works-on.hint' | translate }}</p>\n <div class=\"uses\">\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'all'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"all\" [checked]=\"worksOnScope() === 'all'\" (change)=\"worksOnScope.set('all')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.all' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.all-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'types'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"types\" [checked]=\"worksOnScope() === 'types'\" (change)=\"worksOnScope.set('types')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.types' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.types-hint' | translate }}</span>\n </span>\n </label>\n </div>\n\n @if (worksOnScope() === 'types') {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.works-on.types' | translate\" data-works-on-types>\n @for (type of subjectTypes(); track type.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"worksOnTypes().includes(type.id)\" (change)=\"toggleWorksOnType(type.id, checked($event))\" />\n <span>{{ type.pluralName ?? type.name }} <span class=\"mono muted\">{{ type.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.no-types' | translate }}</p>\n }\n </div>\n @if (fieldError('worksOnSubjectTypes'); as key) {\n <p class=\"hint\"><span class=\"error-text\">{{ key | translate }}</span></p>\n } @else if (tooManyTypes()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.too-many' | translate }}</span></p>\n }\n }\n\n @if (knownTypes().length > 0) {\n <p class=\"hint\" data-known-types>{{ 'nh-assistant.admin.agent-editor.works-on.known' | translate: { types: knownTypes().join(', ') } }}</p>\n }\n\n <label class=\"check described\">\n <input type=\"checkbox\" [checked]=\"worksOnApplication()\" (change)=\"worksOnApplication.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.application' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.application-hint' | translate }}</span>\n </span>\n </label>\n\n @if (divisionsListed()) {\n <label class=\"check described\" data-per-division>\n <input\n type=\"checkbox\"\n [checked]=\"perDivision()\"\n [attr.aria-invalid]=\"fieldError('perDivision') ? true : null\"\n [attr.aria-describedby]=\"fieldError('perDivision') ? id + '-per-division-error' : null\"\n (change)=\"perDivision.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.per-division' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.per-division-hint' | translate }}</span>\n </span>\n </label>\n @if (fieldError('perDivision'); as key) {\n <p class=\"hint\" [id]=\"id + '-per-division-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n }\n\n <p class=\"hint\" [id]=\"id + '-works-on-error'\" aria-live=\"polite\">\n @if (submitted() && worksOnMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.missing' | translate }}</span>\n } @else if (fieldError('worksOn'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy' | translate }}</label>\n <select\n [id]=\"id + '-run-policy'\"\n [attr.aria-describedby]=\"id + '-run-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('runPolicy') ? true : null\"\n (change)=\"runPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"runPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"runPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-run-policy-hint'\">\n @if (fieldError('runPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.run-policy-hint' | translate }}\n }\n </p>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-view-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy' | translate }}</label>\n <select\n [id]=\"id + '-view-policy'\"\n [attr.aria-describedby]=\"id + '-view-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('viewPolicy') ? true : null\"\n (change)=\"viewPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"viewPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"viewPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-view-policy-hint'\">\n @if (fieldError('viewPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.view-policy-hint' | translate }}\n }\n </p>\n </div>\n </div>\n </fieldset>\n }\n }\n\n @if (agentGroups().length > 0 && !catalogUnavailable()) {\n <fieldset\n class=\"subsection\"\n data-agent-groups\n [attr.aria-describedby]=\"id + '-groups-hint ' + id + '-groups-error'\"\n [attr.aria-invalid]=\"groupsError() ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.groups.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-groups-hint'\">{{ 'nh-assistant.admin.agent-editor.groups.hint' | translate }}</p>\n @if (isVariant()) {\n <p class=\"hint\" data-groups-variant>{{ 'nh-assistant.admin.agent-editor.groups.shadow-variant' | translate }}</p>\n } @else {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.groups.title' | translate\">\n @for (group of agentGroups(); track group.id) {\n <label class=\"check described\" [attr.data-agent-group]=\"group.id\">\n <input type=\"checkbox\" [checked]=\"groups().includes(group.id)\" (change)=\"toggleGroup(group.id, checked($event))\" />\n <span>\n <strong>{{ group.name }}</strong>\n @if (group.description; as description) {\n <span class=\"muted\">{{ description }}</span>\n }\n @if (codeGroups().includes(group.id)) {\n <span class=\"muted\" data-group-in-code>{{ 'nh-assistant.admin.agent-editor.groups.in-code' | translate }}</span>\n }\n </span>\n </label>\n }\n </div>\n }\n <p class=\"hint\" [id]=\"id + '-groups-error'\" aria-live=\"polite\">\n @if (groupsError(); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n </fieldset>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.agent-editor.description' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('description')\" /></label>\n <input type=\"text\" [id]=\"id + '-description'\" [disabled]=\"locked('description')\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <!-- The instructions, from text or an asset, lock together. -->\n <fieldset class=\"stack\" data-agent-instructions [disabled]=\"locked('instructions')\">\n @if (choosesUse()) {\n <nh-assistant-instructions-asset\n [idPrefix]=\"id + '-instructions'\"\n [available]=\"assetsAvailable()\"\n [(source)]=\"instructionsSource\"\n [(reference)]=\"instructionsAsset\"\n [problem]=\"assetProblem()\"\n [error]=\"assetError()\" />\n }\n @if (instructionsSource() === 'inline') {\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('instructions')\" /></label>\n <textarea\n rows=\"8\"\n [id]=\"id + '-instructions'\"\n [value]=\"instructions()\"\n [attr.aria-describedby]=\"id + '-instructions-hint'\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"instructions.set(value($event))\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span [class.error-text]=\"tooLong()\">\n {{ (tooLong() ? 'nh-assistant.admin.too-long' : 'nh-assistant.admin.agent-editor.instructions-hint') | translate }}\n </span>\n <span class=\"counter\" [class.error-text]=\"tooLong()\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: max } }}</span>\n </p>\n </div>\n }\n </fieldset>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('autonomy')\" /></label>\n <select [id]=\"id + '-autonomy'\" [disabled]=\"locked('autonomy')\" [attr.aria-describedby]=\"id + '-autonomy-hint'\" (change)=\"autonomy.set($any(value($event)))\">\n @for (level of autonomyLevels; track level) {\n <option [value]=\"level\" [selected]=\"autonomy() === level\">{{ 'nh-assistant.admin.agents.autonomy.' + level | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-autonomy-hint'\">{{ 'nh-assistant.admin.agent-editor.autonomy-hint' | translate }}</p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.agent-editor.required-policy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('requiredPolicy')\" /></label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\n [disabled]=\"locked('requiredPolicy')\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"id + '-policy-hint'\"\n (input)=\"requiredPolicy.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.agent-editor.required-policy-hint' | translate }}</p>\n </div>\n\n @if (choosesProfile()) {\n <div class=\"field\" data-agent-profile>\n <label [for]=\"id + '-profile'\">{{ 'nh-assistant.admin.agent-editor.profile' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('profile')\" /></label>\n <select\n [id]=\"id + '-profile'\"\n [disabled]=\"locked('profile')\"\n [attr.aria-describedby]=\"id + '-profile-hint' + (fieldError('profile') ? ' ' + id + '-profile-error' : '')\"\n [attr.aria-invalid]=\"fieldError('profile') ? true : null\"\n (change)=\"profile.set(value($event))\">\n @if (isNew()) {\n <option value=\"\" [selected]=\"profile() === ''\">{{ 'nh-assistant.admin.agent-editor.profile-default' | translate }}</option>\n }\n @for (name of profileChoices(); track name) {\n <option [value]=\"name\" [selected]=\"profile() === name\">{{ name }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-profile-hint'\">{{ 'nh-assistant.admin.agent-editor.profile-hint' | translate }}</p>\n @if (fieldError('profile'); as key) {\n <p class=\"hint\" [id]=\"id + '-profile-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n\n @if (choosesUse()) {\n <div class=\"field\" data-agent-classification>\n <label [for]=\"id + '-classification'\">{{ 'nh-assistant.admin.agent-editor.classification' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('dataClassification')\" /></label>\n <select\n [id]=\"id + '-classification'\"\n [disabled]=\"locked('dataClassification')\"\n [attr.aria-describedby]=\"id + '-classification-hint' + (fieldError('dataClassification') ? ' ' + id + '-classification-error' : '')\"\n [attr.aria-invalid]=\"fieldError('dataClassification') ? true : null\"\n (change)=\"dataClassification.set($any(value($event)))\">\n @for (classification of classifications; track classification) {\n <option [value]=\"classification\" [selected]=\"dataClassification() === classification\">\n {{ 'nh-assistant.admin.run-config.skills.classification.' + classification | translate }}\n </option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-classification-hint'\">{{ 'nh-assistant.admin.agent-editor.classification-hint' | translate }}</p>\n @for (warning of warnings(); track warning) {\n <p class=\"message warning\" [attr.data-agent-editor-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n @if (fieldError('dataClassification'); as key) {\n <p class=\"hint\" [id]=\"id + '-classification-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n </div>\n\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.state-hint' | translate }}</p>\n\n <fieldset class=\"subsection\" data-agent-tool-selectors [disabled]=\"locked('toolSelectors')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('toolSelectors')\" /></legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.tool-selectors-hint' | translate }}</p>\n\n @if (toolSelectors().length === 0) {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n } @else {\n <ul class=\"chips\">\n @for (selector of toolSelectors(); track selector) {\n <li class=\"chip\">\n <span>{{ selector }}</span>\n <button\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n [attr.title]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n (click)=\"removeSelector(selector)\">\n <nh-assistant-icon name=\"x\" />\n </button>\n </li>\n }\n </ul>\n <p class=\"muted\" role=\"status\">{{ 'nh-assistant.admin.agent-editor.matches' | translate: { count: matchCount() } }}</p>\n }\n\n <div class=\"inline\">\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.add-selector' | translate\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.selector-placeholder' | translate\"\n [attr.aria-invalid]=\"selectorInvalid() ? true : null\"\n [value]=\"newSelector()\"\n (input)=\"newSelector.set(value($event))\"\n (keydown)=\"onSelectorKeydown($event)\" />\n <button class=\"secondary\" type=\"button\" [disabled]=\"newSelector().trim().length === 0 || selectorInvalid()\" (click)=\"addSelector()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agent-editor.add-selector' | translate }}\n </button>\n </div>\n\n <div class=\"field\">\n <label class=\"label\" [for]=\"id + '-catalog-filter'\">{{ 'nh-assistant.admin.agent-editor.catalog' | translate }}</label>\n <input\n type=\"search\"\n [id]=\"id + '-catalog-filter'\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.catalog-filter' | translate\"\n [value]=\"catalogFilter()\"\n (input)=\"catalogFilter.set(value($event))\" />\n <ul class=\"catalog\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.catalog' | translate\">\n @for (tool of filteredTools(); track tool.id) {\n <li>\n <label>\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(tool.id) || isCovered(tool.id)\"\n [disabled]=\"isCovered(tool.id)\"\n (change)=\"toggleTool(tool.id, checked($event))\" />\n <span class=\"tool-id\">{{ tool.id }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.source.' + tool.source | translate }}</span>\n <span class=\"badge\" [class.warning]=\"tool.effect !== 'read-only'\">{{ 'nh-assistant.admin.effect.' + tool.effect | translate }}</span>\n <span class=\"muted\">{{ tool.description }}</span>\n </label>\n </li>\n } @empty {\n <li class=\"muted\">{{ 'nh-assistant.admin.agent-editor.catalog-empty' | translate }}</li>\n }\n </ul>\n </div>\n </fieldset>\n\n <fieldset class=\"subsection\">\n <legend>{{ 'nh-assistant.admin.agent-editor.mcp-servers' | translate }}</legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-hint' | translate }}</p>\n @for (server of servers(); track server.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"mcpServerIds().includes(server.id)\" (change)=\"toggleServer(server.id, checked($event))\" />\n <span>{{ server.displayName }} <span class=\"mono muted\">{{ server.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-empty' | translate }}</p>\n }\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=\"secondary\" type=\"button\" (click)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"saving() || tooLong()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\n\n<nh-assistant-agent-metadata [agent]=\"metadataAgent()\" [entries]=\"metadataEntries()\" (agentVersionChanged)=\"fieldsChanged($event)\" />\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"] }]
|
|
1687
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (agent()) {\n {{ 'nh-assistant.admin.agent-editor.edit-title' | translate: { name: titleName() } }}\n } @else {\n {{ 'nh-assistant.admin.agent-editor.new-title' | translate }}\n }\n </h3>\n @if (agent(); as current) {\n <!-- Fields the agent's package locks show read-only below; unlinking makes them change here. -->\n <nh-assistant-package-lock [lock]=\"lock()\" [agentId]=\"current.id\" part=\"agent\" (unlinked)=\"onUnlinked()\" />\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.agent-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-id'\"\n [value]=\"agentId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"id + '-id-hint'\"\n [attr.aria-invalid]=\"submitted() && idInvalid() ? true : null\"\n (input)=\"agentId.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">\n <span [class.error-text]=\"submitted() && idInvalid()\">\n {{ (submitted() && idInvalid() ? 'nh-assistant.admin.invalid-id' : 'nh-assistant.admin.agent-editor.id-hint') | translate }}\n </span>\n </p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.agent-editor.display-name' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('displayName')\" /></label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [disabled]=\"locked('displayName')\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"submitted() && nameMissing() ? true : null\"\n [attr.aria-describedby]=\"id + '-name-hint'\"\n (input)=\"displayName.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-name-hint'\">\n @if (submitted() && nameMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n }\n </p>\n </div>\n </div>\n\n @if (choosesUse()) {\n <fieldset class=\"subsection\" data-agent-use [disabled]=\"locked('offeredInChat')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('offeredInChat')\" /></legend>\n <div class=\"uses\">\n @for (option of uses; track option) {\n <label class=\"use\" [class.selected]=\"use() === option\">\n <input type=\"radio\" [name]=\"id + '-use'\" [value]=\"option\" [checked]=\"use() === option\" (change)=\"use.set(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.use.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.use.' + option + '-hint' | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (isNew() && use() !== 'chat') {\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.use.next' | translate }}</p>\n }\n @if (isNew()) {\n <label class=\"check described\" data-switch-on-now>\n <input type=\"checkbox\" [checked]=\"switchOnNow()\" (change)=\"switchOnNow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.switch-on-now' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.switch-on-now-hint' | translate }}</span>\n </span>\n </label>\n @if (use() !== 'chat') {\n <!-- An agent that works on its own may first work in shadow, once it has run settings. -->\n <label class=\"check described\" data-starts-in-shadow>\n <input type=\"checkbox\" [checked]=\"startsInShadow()\" (change)=\"startsInShadow.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.starts-in-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.starts-in-shadow-hint' | translate }}</span>\n </span>\n </label>\n }\n }\n </fieldset>\n\n @if (catalogUnavailable()) {\n <!-- Without the run catalog the kinds of objects and policies are unknown: what the agent works on stays as it is. -->\n <p class=\"message warning\" role=\"note\" data-catalog-unavailable>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.agent-editor.catalog-unavailable' | translate }}\n </p>\n } @else {\n <fieldset\n class=\"subsection\"\n data-works-on\n [disabled]=\"locked('worksOn')\"\n [attr.aria-describedby]=\"id + '-works-on-hint ' + id + '-works-on-error'\"\n [attr.aria-invalid]=\"(submitted() && worksOnMissing()) || fieldError('worksOn') ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.works-on.title' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('worksOn')\" /></legend>\n <p class=\"muted\" [id]=\"id + '-works-on-hint'\">{{ 'nh-assistant.admin.agent-editor.works-on.hint' | translate }}</p>\n <div class=\"uses\">\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'all'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"all\" [checked]=\"worksOnScope() === 'all'\" (change)=\"worksOnScope.set('all')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.all' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.all-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"use\" [class.selected]=\"worksOnScope() === 'types'\">\n <input type=\"radio\" [name]=\"id + '-works-on'\" value=\"types\" [checked]=\"worksOnScope() === 'types'\" (change)=\"worksOnScope.set('types')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.types' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.types-hint' | translate }}</span>\n </span>\n </label>\n </div>\n\n @if (worksOnScope() === 'types') {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.works-on.types' | translate\" data-works-on-types>\n @for (type of subjectTypes(); track type.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"worksOnTypes().includes(type.id)\" (change)=\"toggleWorksOnType(type.id, checked($event))\" />\n <span>{{ type.pluralName ?? type.name }} <span class=\"mono muted\">{{ type.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.no-types' | translate }}</p>\n }\n </div>\n @if (fieldError('worksOnSubjectTypes'); as key) {\n <p class=\"hint\"><span class=\"error-text\">{{ key | translate }}</span></p>\n } @else if (tooManyTypes()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.too-many' | translate }}</span></p>\n }\n }\n\n @if (knownTypes().length > 0) {\n <p class=\"hint\" data-known-types>{{ 'nh-assistant.admin.agent-editor.works-on.known' | translate: { types: knownTypes().join(', ') } }}</p>\n }\n\n <label class=\"check described\">\n <input type=\"checkbox\" [checked]=\"worksOnApplication()\" (change)=\"worksOnApplication.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.application' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.application-hint' | translate }}</span>\n </span>\n </label>\n\n @if (divisionsListed()) {\n <label class=\"check described\" data-per-division>\n <input\n type=\"checkbox\"\n [checked]=\"perDivision()\"\n [attr.aria-invalid]=\"fieldError('perDivision') ? true : null\"\n [attr.aria-describedby]=\"fieldError('perDivision') ? id + '-per-division-error' : null\"\n (change)=\"perDivision.set(checked($event))\" />\n <span>\n <strong>{{ 'nh-assistant.admin.agent-editor.works-on.per-division' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.agent-editor.works-on.per-division-hint' | translate }}</span>\n </span>\n </label>\n @if (fieldError('perDivision'); as key) {\n <p class=\"hint\" [id]=\"id + '-per-division-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n }\n\n <p class=\"hint\" [id]=\"id + '-works-on-error'\" aria-live=\"polite\">\n @if (submitted() && worksOnMissing()) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.agent-editor.works-on.missing' | translate }}</span>\n } @else if (fieldError('worksOn'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy' | translate }}</label>\n <select\n [id]=\"id + '-run-policy'\"\n [attr.aria-describedby]=\"id + '-run-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('runPolicy') ? true : null\"\n (change)=\"runPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"runPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.run-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"runPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-run-policy-hint'\">\n @if (fieldError('runPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.run-policy-hint' | translate }}\n }\n </p>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-view-policy'\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy' | translate }}</label>\n <select\n [id]=\"id + '-view-policy'\"\n [attr.aria-describedby]=\"id + '-view-policy-hint'\"\n [attr.aria-invalid]=\"fieldError('viewPolicy') ? true : null\"\n (change)=\"viewPolicy.set(value($event))\">\n <option value=\"\" [selected]=\"viewPolicy() === ''\">{{ 'nh-assistant.admin.agent-editor.works-on.view-policy-default' | translate }}</option>\n @for (policy of agentPolicies(); track policy.name) {\n <option [value]=\"policy.name\" [selected]=\"viewPolicy() === policy.name\">{{ policyKeys(policy.name) | nhAssistantTranslate: policy.description }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-view-policy-hint'\">\n @if (fieldError('viewPolicy'); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.agent-editor.works-on.view-policy-hint' | translate }}\n }\n </p>\n </div>\n </div>\n </fieldset>\n }\n }\n\n @if (agentGroups().length > 0 && !catalogUnavailable()) {\n <fieldset\n class=\"subsection\"\n data-agent-groups\n [attr.aria-describedby]=\"id + '-groups-hint ' + id + '-groups-error'\"\n [attr.aria-invalid]=\"groupsError() ? true : null\">\n <legend>{{ 'nh-assistant.admin.agent-editor.groups.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-groups-hint'\">{{ 'nh-assistant.admin.agent-editor.groups.hint' | translate }}</p>\n @if (isVariant()) {\n <p class=\"hint\" data-groups-variant>{{ 'nh-assistant.admin.agent-editor.groups.shadow-variant' | translate }}</p>\n } @else {\n <div class=\"checks\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.groups.title' | translate\">\n @for (group of agentGroups(); track group.id) {\n <label class=\"check described\" [attr.data-agent-group]=\"group.id\">\n <input type=\"checkbox\" [checked]=\"groups().includes(group.id)\" (change)=\"toggleGroup(group.id, checked($event))\" />\n <span>\n <strong>{{ group.name }}</strong>\n @if (group.description; as description) {\n <span class=\"muted\">{{ description }}</span>\n }\n @if (codeGroups().includes(group.id)) {\n <span class=\"muted\" data-group-in-code>{{ 'nh-assistant.admin.agent-editor.groups.in-code' | translate }}</span>\n }\n </span>\n </label>\n }\n </div>\n }\n <p class=\"hint\" [id]=\"id + '-groups-error'\" aria-live=\"polite\">\n @if (groupsError(); as key) {\n <span class=\"error-text\">{{ key | translate }}</span>\n }\n </p>\n </fieldset>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.agent-editor.description' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('description')\" /></label>\n <input type=\"text\" [id]=\"id + '-description'\" [disabled]=\"locked('description')\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <!-- The instructions, from text or an asset, lock together. -->\n <fieldset class=\"stack\" data-agent-instructions [disabled]=\"locked('instructions')\">\n @if (choosesUse()) {\n <nh-assistant-instructions-asset\n [idPrefix]=\"id + '-instructions'\"\n [available]=\"assetsAvailable()\"\n [(source)]=\"instructionsSource\"\n [(reference)]=\"instructionsAsset\"\n [problem]=\"assetProblem()\"\n [error]=\"assetError()\" />\n }\n @if (instructionsSource() === 'inline') {\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('instructions')\" /></label>\n <textarea\n rows=\"8\"\n [id]=\"id + '-instructions'\"\n [value]=\"instructions()\"\n [attr.aria-describedby]=\"id + '-instructions-hint'\"\n [attr.aria-invalid]=\"tooLong() ? true : null\"\n (input)=\"instructions.set(value($event))\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span [class.error-text]=\"tooLong()\">\n {{ (tooLong() ? 'nh-assistant.admin.too-long' : 'nh-assistant.admin.agent-editor.instructions-hint') | translate }}\n </span>\n <span class=\"counter\" [class.error-text]=\"tooLong()\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: max } }}</span>\n </p>\n </div>\n }\n </fieldset>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('autonomy')\" /></label>\n <select [id]=\"id + '-autonomy'\" [disabled]=\"locked('autonomy')\" [attr.aria-describedby]=\"id + '-autonomy-hint'\" (change)=\"autonomy.set($any(value($event)))\">\n @for (level of autonomyLevels; track level) {\n <option [value]=\"level\" [selected]=\"autonomy() === level\">{{ 'nh-assistant.admin.agents.autonomy.' + level | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-autonomy-hint'\">{{ 'nh-assistant.admin.agent-editor.autonomy-hint' | translate }}</p>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.agent-editor.required-policy' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('requiredPolicy')\" /></label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\n [disabled]=\"locked('requiredPolicy')\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"id + '-policy-hint'\"\n (input)=\"requiredPolicy.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.agent-editor.required-policy-hint' | translate }}</p>\n </div>\n\n @if (choosesProfile()) {\n <div class=\"field\" data-agent-profile>\n <label [for]=\"id + '-profile'\">{{ 'nh-assistant.admin.agent-editor.profile' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('profile')\" /></label>\n <select\n [id]=\"id + '-profile'\"\n [disabled]=\"locked('profile')\"\n [attr.aria-describedby]=\"id + '-profile-hint' + (fieldError('profile') ? ' ' + id + '-profile-error' : '')\"\n [attr.aria-invalid]=\"fieldError('profile') ? true : null\"\n (change)=\"profile.set(value($event))\">\n @if (isNew()) {\n <option value=\"\" [selected]=\"profile() === ''\">{{ 'nh-assistant.admin.agent-editor.profile-default' | translate }}</option>\n }\n @for (name of profileChoices(); track name) {\n <option [value]=\"name\" [selected]=\"profile() === name\">{{ name }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-profile-hint'\">{{ 'nh-assistant.admin.agent-editor.profile-hint' | translate }}</p>\n @if (fieldError('profile'); as key) {\n <p class=\"hint\" [id]=\"id + '-profile-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n\n @if (choosesUse()) {\n <div class=\"field\" data-agent-classification>\n <label [for]=\"id + '-classification'\">{{ 'nh-assistant.admin.agent-editor.classification' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('dataClassification')\" /></label>\n <select\n [id]=\"id + '-classification'\"\n [disabled]=\"locked('dataClassification')\"\n [attr.aria-describedby]=\"id + '-classification-hint' + (fieldError('dataClassification') ? ' ' + id + '-classification-error' : '')\"\n [attr.aria-invalid]=\"fieldError('dataClassification') ? true : null\"\n (change)=\"dataClassification.set($any(value($event)))\">\n @for (classification of classifications; track classification) {\n <option [value]=\"classification\" [selected]=\"dataClassification() === classification\">\n {{ 'nh-assistant.admin.run-config.skills.classification.' + classification | translate }}\n </option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-classification-hint'\">{{ 'nh-assistant.admin.agent-editor.classification-hint' | translate }}</p>\n @for (warning of warnings(); track warning) {\n <p class=\"message warning\" [attr.data-agent-editor-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n @if (fieldError('dataClassification'); as key) {\n <p class=\"hint\" [id]=\"id + '-classification-error'\"><span class=\"error-text\">{{ key | translate }}</span></p>\n }\n </div>\n }\n </div>\n\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.state-hint' | translate }}</p>\n\n <fieldset class=\"subsection\" data-agent-tool-selectors [disabled]=\"locked('toolSelectors')\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}<nh-assistant-package-locked-mark [lock]=\"lockOf('toolSelectors')\" /></legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.tool-selectors-hint' | translate }}</p>\n\n @if (toolSelectors().length === 0) {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n } @else {\n <ul class=\"chips\">\n @for (selector of toolSelectors(); track selector) {\n <li class=\"chip\">\n <span>{{ selector }}</span>\n <button\n type=\"button\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n [attr.title]=\"'nh-assistant.admin.agent-editor.remove-selector' | translate: { selector: selector }\"\n (click)=\"removeSelector(selector)\">\n <nh-assistant-icon name=\"x\" />\n </button>\n </li>\n }\n </ul>\n <p class=\"muted\" role=\"status\">{{ 'nh-assistant.admin.agent-editor.matches' | translate: { count: matchCount() } }}</p>\n }\n\n <div class=\"inline\">\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [attr.aria-label]=\"'nh-assistant.admin.agent-editor.add-selector' | translate\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.selector-placeholder' | translate\"\n [attr.aria-invalid]=\"selectorInvalid() ? true : null\"\n [value]=\"newSelector()\"\n (input)=\"newSelector.set(value($event))\"\n (keydown)=\"onSelectorKeydown($event)\" />\n <button class=\"secondary\" type=\"button\" [disabled]=\"newSelector().trim().length === 0 || selectorInvalid()\" (click)=\"addSelector()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agent-editor.add-selector' | translate }}\n </button>\n </div>\n\n <div class=\"field\">\n <label class=\"label\" [for]=\"id + '-catalog-filter'\">{{ 'nh-assistant.admin.agent-editor.catalog' | translate }}</label>\n <input\n type=\"search\"\n [id]=\"id + '-catalog-filter'\"\n [attr.placeholder]=\"'nh-assistant.admin.agent-editor.catalog-filter' | translate\"\n [value]=\"catalogFilter()\"\n (input)=\"catalogFilter.set(value($event))\" />\n <ul class=\"catalog\" [attr.aria-label]=\"'nh-assistant.admin.agent-editor.catalog' | translate\">\n @for (tool of filteredTools(); track tool.id) {\n <li>\n <label>\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(tool.id) || isCovered(tool.id)\"\n [disabled]=\"isCovered(tool.id)\"\n (change)=\"toggleTool(tool.id, checked($event))\" />\n <span class=\"tool-id\">{{ tool.id }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.source.' + tool.source | translate }}</span>\n <span class=\"badge\" [class.warning]=\"tool.effect !== 'read-only'\">{{ 'nh-assistant.admin.effect.' + tool.effect | translate }}</span>\n <span class=\"muted\">{{ tool.description }}</span>\n </label>\n </li>\n } @empty {\n <li class=\"muted\">{{ 'nh-assistant.admin.agent-editor.catalog-empty' | translate }}</li>\n }\n </ul>\n </div>\n </fieldset>\n\n <fieldset class=\"subsection\">\n <legend>{{ 'nh-assistant.admin.agent-editor.mcp-servers' | translate }}</legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-hint' | translate }}</p>\n @for (server of servers(); track server.id) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"mcpServerIds().includes(server.id)\" (change)=\"toggleServer(server.id, checked($event))\" />\n <span>{{ server.displayName }} <span class=\"mono muted\">{{ server.id }}</span></span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.mcp-servers-empty' | translate }}</p>\n }\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=\"secondary\" type=\"button\" (click)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"saving() || tooLong()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\n\n<nh-assistant-agent-metadata [agent]=\"metadataAgent()\" [entries]=\"metadataEntries()\" (agentVersionChanged)=\"fieldsChanged($event)\" />\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"] }]
|
|
1678
1688
|
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: false }] }], tools: [{ type: i0.Input, args: [{ isSignal: true, alias: "tools", required: false }] }], servers: [{ type: i0.Input, args: [{ isSignal: true, alias: "servers", required: false }] }], catalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalog", required: false }] }], catalogUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalogUnavailable", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], workRequested: [{ type: i0.Output, args: ["workRequested"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
|
|
1679
1689
|
/** Whether two sorted lists of group ids are the same. */
|
|
1680
1690
|
function sameGroups(left, right) {
|
|
@@ -3339,7 +3349,7 @@ class NhAssistantAgentFlowComponent {
|
|
|
3339
3349
|
this.agentName = computed(() => {
|
|
3340
3350
|
this.language();
|
|
3341
3351
|
const agent = this.agent();
|
|
3342
|
-
return this.
|
|
3352
|
+
return agentDisplayName(this.translate, agent);
|
|
3343
3353
|
}, ...(ngDevMode ? [{ debugName: "agentName" }] : []));
|
|
3344
3354
|
this.accountability = computed(() => flowAccountability(this.configuration()), ...(ngDevMode ? [{ debugName: "accountability" }] : []));
|
|
3345
3355
|
/** The way of working of the agent: fixed rules (named for an agent created here) or the model. */
|
|
@@ -4755,7 +4765,7 @@ class NhAssistantAgentRunConfigurationComponent {
|
|
|
4755
4765
|
this.agentName = computed(() => {
|
|
4756
4766
|
this.language();
|
|
4757
4767
|
const agent = this.agent();
|
|
4758
|
-
return this.
|
|
4768
|
+
return agentDisplayName(this.translate, agent);
|
|
4759
4769
|
}, ...(ngDevMode ? [{ debugName: "agentName" }] : []));
|
|
4760
4770
|
/** The skill being changed; `null` with the skill form open adds a new skill. */
|
|
4761
4771
|
this.editingSkill = signal(null, ...(ngDevMode ? [{ debugName: "editingSkill" }] : []));
|
|
@@ -5033,7 +5043,7 @@ class NhAssistantAgentRunConfigurationComponent {
|
|
|
5033
5043
|
/** An agent's name: the translation of an agent in code, the administrator's text, or its id. */
|
|
5034
5044
|
agentNameOf(agentId) {
|
|
5035
5045
|
const agent = this.agents().find(item => item.id === agentId);
|
|
5036
|
-
return agent ? this.
|
|
5046
|
+
return agent ? agentDisplayName(this.translate, agent) : agentId;
|
|
5037
5047
|
}
|
|
5038
5048
|
/** Who may ask a consultation defined as data, in a sentence; `null` for one in code, whose code says it. */
|
|
5039
5049
|
askSentence(row) {
|
|
@@ -5561,15 +5571,21 @@ const maxDescription$1 = 512;
|
|
|
5561
5571
|
* starts from this agent's definition, gets its own id, name, description and instructions, is never
|
|
5562
5572
|
* offered in the chat and always works in shadow. `created` hands the new variant to the page, which
|
|
5563
5573
|
* continues in its run configuration; `openVariant` opens the run configuration of a data variant.
|
|
5574
|
+
* After a confirmation, a data variant is promoted onto this agent (LS31): its definition becomes this
|
|
5575
|
+
* agent's next version, its skills move along when asked, and the variant is removed; `promoted` hands
|
|
5576
|
+
* the outcome to the page, which shows the agent's new version.
|
|
5564
5577
|
*/
|
|
5565
5578
|
class NhAssistantAgentShadowVariantsComponent extends RunConfigForm {
|
|
5566
5579
|
constructor() {
|
|
5567
5580
|
super();
|
|
5568
5581
|
this.admin = inject(NhAssistantAdminApiService);
|
|
5582
|
+
/** The agent the last promotion note belongs to. */
|
|
5583
|
+
this.shownFor = null;
|
|
5569
5584
|
/** The live agent. */
|
|
5570
5585
|
this.agent = input.required(...(ngDevMode ? [{ debugName: "agent" }] : []));
|
|
5571
5586
|
this.created = output();
|
|
5572
5587
|
this.openVariant = output();
|
|
5588
|
+
this.promoted = output();
|
|
5573
5589
|
this.id = `nh-assistant-shadow-variants-${nextId$7++}`;
|
|
5574
5590
|
this.maxId = maxId;
|
|
5575
5591
|
this.maxName = maxName;
|
|
@@ -5593,12 +5609,35 @@ class NhAssistantAgentShadowVariantsComponent extends RunConfigForm {
|
|
|
5593
5609
|
}
|
|
5594
5610
|
return this.dataVariants() >= variants.maxDataVariants ? 'limit' : null;
|
|
5595
5611
|
}, ...(ngDevMode ? [{ debugName: "closed" }] : []));
|
|
5596
|
-
|
|
5597
|
-
|
|
5612
|
+
/** The data variant whose promotion onto this agent is being confirmed; `null` while none is. */
|
|
5613
|
+
this.promoting = signal(null, ...(ngDevMode ? [{ debugName: "promoting" }] : []));
|
|
5614
|
+
this.moveSkills = signal(false, ...(ngDevMode ? [{ debugName: "moveSkills" }] : []));
|
|
5615
|
+
this.promoteBusy = signal(false, ...(ngDevMode ? [{ debugName: "promoteBusy" }] : []));
|
|
5616
|
+
this.promoteError = signal(null, ...(ngDevMode ? [{ debugName: "promoteError" }] : []));
|
|
5617
|
+
this.promoteErrorKeys = computed(() => _nhAssistantErrorKeys(this.promoteError()), ...(ngDevMode ? [{ debugName: "promoteErrorKeys" }] : []));
|
|
5618
|
+
/** The last promotion onto this agent, which a status announces. */
|
|
5619
|
+
this.promotedNote = signal(null, ...(ngDevMode ? [{ debugName: "promotedNote" }] : []));
|
|
5620
|
+
/** This agent's name as the agent list shows it, in the current language. */
|
|
5621
|
+
this.liveName = computed(() => {
|
|
5622
|
+
this.language();
|
|
5623
|
+
return agentDisplayName(this.translate, this.agent());
|
|
5624
|
+
}, ...(ngDevMode ? [{ debugName: "liveName" }] : []));
|
|
5625
|
+
inject(DestroyRef).onDestroy(() => {
|
|
5626
|
+
this.loadSubscription?.unsubscribe();
|
|
5627
|
+
this.promoteSubscription?.unsubscribe();
|
|
5628
|
+
});
|
|
5629
|
+
// The page shows another agent's run configuration in the same place: start over for it. After a
|
|
5630
|
+
// promotion the page shows this agent's new version, so the note of the promotion stays.
|
|
5598
5631
|
effect(() => {
|
|
5599
5632
|
const agentId = this.agent().id;
|
|
5600
5633
|
untracked(() => {
|
|
5601
5634
|
this.creating.set(false);
|
|
5635
|
+
this.promoting.set(null);
|
|
5636
|
+
this.promoteError.set(null);
|
|
5637
|
+
if (this.shownFor !== agentId) {
|
|
5638
|
+
this.promotedNote.set(null);
|
|
5639
|
+
this.shownFor = agentId;
|
|
5640
|
+
}
|
|
5602
5641
|
this.load(agentId);
|
|
5603
5642
|
});
|
|
5604
5643
|
});
|
|
@@ -5674,6 +5713,53 @@ class NhAssistantAgentShadowVariantsComponent extends RunConfigForm {
|
|
|
5674
5713
|
this.load();
|
|
5675
5714
|
});
|
|
5676
5715
|
}
|
|
5716
|
+
/** Asks to confirm the promotion of a data variant onto this agent; its skills stay unless asked. */
|
|
5717
|
+
startPromote(variant) {
|
|
5718
|
+
this.promoting.set(variant.agentId);
|
|
5719
|
+
this.moveSkills.set(false);
|
|
5720
|
+
this.promoteError.set(null);
|
|
5721
|
+
this.promotedNote.set(null);
|
|
5722
|
+
afterNextRender(() => {
|
|
5723
|
+
this.host.nativeElement.querySelector('[data-promote-confirm-button]')?.focus();
|
|
5724
|
+
}, { injector: this.injector });
|
|
5725
|
+
}
|
|
5726
|
+
cancelPromote() {
|
|
5727
|
+
const variantId = this.promoting();
|
|
5728
|
+
this.promoting.set(null);
|
|
5729
|
+
this.promoteError.set(null);
|
|
5730
|
+
afterNextRender(() => {
|
|
5731
|
+
Array.from(this.host.nativeElement.querySelectorAll('[data-promote-variant]'))
|
|
5732
|
+
.find(button => button.dataset['promoteVariant'] === variantId)
|
|
5733
|
+
?.focus();
|
|
5734
|
+
}, { injector: this.injector });
|
|
5735
|
+
}
|
|
5736
|
+
/**
|
|
5737
|
+
* Promotes the variant onto this agent at the versions shown: this agent's, and the variant's when
|
|
5738
|
+
* the list reports it, so a change by someone else in the meantime is refused.
|
|
5739
|
+
*/
|
|
5740
|
+
promote(variant) {
|
|
5741
|
+
const name = this.variantName(variant);
|
|
5742
|
+
this.promoteBusy.set(true);
|
|
5743
|
+
this.promoteError.set(null);
|
|
5744
|
+
this.promoteSubscription?.unsubscribe();
|
|
5745
|
+
this.promoteSubscription = this.admin.promoteShadowVariant(variant.agentId, {
|
|
5746
|
+
expectedVersion: this.agent().version,
|
|
5747
|
+
moveSkills: this.moveSkills(),
|
|
5748
|
+
expectedVariantVersion: variant.version ?? null
|
|
5749
|
+
}).subscribe({
|
|
5750
|
+
next: promotion => {
|
|
5751
|
+
this.promoteBusy.set(false);
|
|
5752
|
+
this.promoting.set(null);
|
|
5753
|
+
this.promotedNote.set({ variant: name, version: promotion.agent.version });
|
|
5754
|
+
this.promoted.emit(promotion);
|
|
5755
|
+
this.load();
|
|
5756
|
+
},
|
|
5757
|
+
error: (error) => {
|
|
5758
|
+
this.promoteBusy.set(false);
|
|
5759
|
+
this.promoteError.set(_toNhAssistantError(error));
|
|
5760
|
+
}
|
|
5761
|
+
});
|
|
5762
|
+
}
|
|
5677
5763
|
/**
|
|
5678
5764
|
* A variant's name as the agent list shows it: a variant in code is an agent in code, which names
|
|
5679
5765
|
* itself with a key of the application.
|
|
@@ -5690,12 +5776,12 @@ class NhAssistantAgentShadowVariantsComponent extends RunConfigForm {
|
|
|
5690
5776
|
return translated && translated !== text ? translated : text;
|
|
5691
5777
|
}
|
|
5692
5778
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAgentShadowVariantsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5693
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAgentShadowVariantsComponent, isStandalone: true, selector: "nh-assistant-agent-shadow-variants", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { created: "created", openVariant: "openVariant" }, usesInheritance: true, ngImport: i0, template: "<!-- The agent's shadow variants: in code read only, created as data within the ceiling in code. -->\n<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\" data-shadow-variants>\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.shadow-variants.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.shadow-variants.description' | translate }}</p>\n </div>\n @if (!loading() && !loadError() && variants()?.allowsDataVariants) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-open-form=\"shadow-variant\"\n [attr.aria-describedby]=\"closed() ? id + '-closed' : null\"\n [disabled]=\"busy() || closed() !== null || creating()\"\n (click)=\"startCreate()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.shadow-variants.add' | translate }}\n </button>\n }\n </header>\n\n @if (loading()) {\n <p class=\"state\" role=\"status\" data-shadow-variants-loading>{{ 'nh-assistant.admin.shadow-variants.loading' | translate }}</p>\n } @else if (loadError(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-shadow-variants-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <p>{{ 'nh-assistant.admin.shadow-variants.load-failed' | translate }} {{ loadErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n </div>\n } @else {\n @if (closed(); as reason) {\n <p class=\"muted\" [id]=\"id + '-closed'\" [attr.data-shadow-variants-closed]=\"reason\">\n {{ 'nh-assistant.admin.shadow-variants.closed.' + reason | translate: { max: variants()?.maxDataVariants } }}\n </p>\n }\n\n @if (creating()) {\n <form class=\"stack card\" data-form=\"shadow-variant\" novalidate (submit)=\"$event.preventDefault(); create()\">\n <h5>{{ 'nh-assistant.admin.shadow-variants.form.title' | translate }}</h5>\n <p class=\"hint\">{{ 'nh-assistant.admin.shadow-variants.form.copies' | translate }}</p>\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.shadow-variants.form.id' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-id [id]=\"id + '-id'\" [maxLength]=\"maxId\" [value]=\"variantId()\"\n [attr.aria-invalid]=\"fieldError('id') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id', id + '-id-error')\"\n (input)=\"variantId.set(value($event)); touch('id')\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">{{ 'nh-assistant.admin.shadow-variants.form.id-hint' | translate }}</p>\n @if (errorKey('id'); as key) {\n <p class=\"field-error\" [id]=\"id + '-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('id')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.shadow-variants.form.name' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-name [id]=\"id + '-name'\" [maxLength]=\"maxName\" [value]=\"displayName()\"\n [attr.aria-invalid]=\"fieldError('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'displayName', id + '-name-error')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\n @if (errorKey('displayName'); as key) {\n <p class=\"field-error\" [id]=\"id + '-name-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('displayName')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.shadow-variants.form.description' | translate }}</label>\n <textarea rows=\"2\" [id]=\"id + '-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'description', id + '-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\"></textarea>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.shadow-variants.form.instructions' | translate }}</label>\n <textarea rows=\"6\" data-variant-instructions [id]=\"id + '-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-instructions-hint', 'instructions', id + '-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.shadow-variants.form.instructions-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"instructions().length > maxInstructions\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: maxInstructions } }}</span>\n </p>\n @if (errorKey('instructions'); as key) {\n <p class=\"field-error\" [id]=\"id + '-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n\n @if (hasErrors()) {\n <div class=\"form-error\" role=\"alert\" data-form-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n @if (serverError(); as failure) {\n @if (failure.code === 'assistant-validation') {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n } @else {\n {{ errorKeys() | nhAssistantTranslate: failure.code }}\n }\n } @else {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n }\n @if (otherFieldErrors().length > 0) {\n <ul>\n @for (field of otherFieldErrors(); track field) {\n <li><span class=\"mono\">{{ field }}</span></li>\n }\n </ul>\n }\n </div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" (click)=\"cancelCreate()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.shadow-variants.form.create') | translate }}</button>\n </div>\n </form>\n }\n\n @if ((variants()?.variants ?? []).length === 0) {\n <p class=\"state\" data-shadow-variants-empty>{{ 'nh-assistant.admin.shadow-variants.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (variant of variants()?.variants ?? []; track variant.agentId) {\n <li class=\"skill\" [attr.data-shadow-variant]=\"variant.agentId\" [attr.data-shadow-variant-source]=\"variant.source\">\n <div class=\"card-header\">\n <strong data-shadow-variant-name>{{ variantName(variant) }}</strong>\n <span class=\"mono muted\">{{ variant.agentId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.shadow-variants.source.' + variant.source | translate }}</span>\n @if (!variant.hasRunSettings) {\n <span class=\"badge\" data-shadow-variant-needs-settings>{{ 'nh-assistant.admin.shadow-variants.needs-settings' | translate }}</span>\n } @else if (variant.inEffect) {\n <span class=\"badge\" data-shadow-variant-in-effect>{{ 'nh-assistant.admin.shadow-variants.in-effect' | translate }}</span>\n } @else {\n <span class=\"badge danger\" data-shadow-variant-out-of-effect>{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n @if (variant.problem; as problem) {\n <p class=\"message warning\" [attr.data-shadow-variant-problem]=\"problem\">\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.shadow-variants.problems.' + problem | translate }}\n </p>\n }\n @if (variant.source === 'data') {\n <div class=\"card-actions\">\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-open-variant]=\"variant.agentId\"\n [attr.aria-label]=\"'nh-assistant.admin.shadow-variants.open-named' | translate: { name: variantName(variant) }\"\n (click)=\"openVariant.emit(variant.agentId)\">\n <nh-assistant-icon name=\"list\" />{{ (variant.hasRunSettings ? 'nh-assistant.admin.shadow-variants.open' : 'nh-assistant.admin.shadow-variants.set-up') | translate }}\n </button>\n </div>\n }\n </li>\n }\n </ul>\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;min-width:0;color:var(--nha-text);font-family:var(--nha-font);font-size:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n", "h5{margin:0;font-size:15px;font-weight:750}.group{display:flex;flex-direction:column;gap:10px;min-width:0;border-top:1px solid var(--nha-border);padding-top:14px}.group>legend{float:left;width:100%;margin-bottom:2px;font-size:14px;font-weight:750}.choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:8px}.choice{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.choice input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.choice>span{display:grid;gap:2px;min-width:0}.choice strong{font-size:13px}.choice.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.choice:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.block{display:block;margin-top:2px}.advanced{border-top:1px solid var(--nha-border);padding-top:12px}.advanced>summary{width:fit-content;border-radius:6px;font-size:14px;font-weight:750;cursor:pointer}.advanced>summary:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.advanced>.stack{margin-top:12px}.examples{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 0;padding:0;list-style:none}.examples button{border:1px solid var(--nha-border);border-radius:999px;padding:3px 10px;color:var(--nha-text);background:transparent;font:inherit;font-size:12px;cursor:pointer}.examples button:hover{background:var(--nha-surface-strong)}.examples button:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.steps{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.steps li{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:4px 10px;color:var(--nha-text-muted);background:var(--nha-surface-strong);font-size:12px;font-weight:700}.steps li[aria-current=step]{color:var(--nha-accent-contrast);background:var(--nha-accent)}.steps li.done{color:var(--nha-success);background:var(--nha-success-soft)}.review{display:grid;grid-template-columns:minmax(0,max-content) minmax(0,1fr);gap:6px 16px;margin:0;font-size:13px}.review dt{color:var(--nha-text-muted)}.review dd{margin:0;overflow-wrap:anywhere}.tool-choice{display:flex;flex-direction:column;gap:2px;min-width:0;overflow-wrap:anywhere}@media(max-width:520px){.review{grid-template-columns:minmax(0,1fr)}.review dd{margin-bottom:6px}}.table-scroll{max-width:100%;overflow-x:auto}.summary{margin:0;font-size:13px;overflow-wrap:anywhere}.checks.routes{grid-template-columns:minmax(0,1fr);gap:10px}.check.blocked{cursor:not-allowed}.check.blocked>span>span:first-child{color:var(--nha-text-muted)}\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 }); }
|
|
5779
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAgentShadowVariantsComponent, isStandalone: true, selector: "nh-assistant-agent-shadow-variants", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { created: "created", openVariant: "openVariant", promoted: "promoted" }, usesInheritance: true, ngImport: i0, template: "<!-- The agent's shadow variants: in code read only, created as data within the ceiling in code. -->\n<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\" data-shadow-variants>\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.shadow-variants.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.shadow-variants.description' | translate }}</p>\n </div>\n @if (!loading() && !loadError() && variants()?.allowsDataVariants) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-open-form=\"shadow-variant\"\n [attr.aria-describedby]=\"closed() ? id + '-closed' : null\"\n [disabled]=\"busy() || closed() !== null || creating()\"\n (click)=\"startCreate()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.shadow-variants.add' | translate }}\n </button>\n }\n </header>\n\n @if (loading()) {\n <p class=\"state\" role=\"status\" data-shadow-variants-loading>{{ 'nh-assistant.admin.shadow-variants.loading' | translate }}</p>\n } @else if (loadError(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-shadow-variants-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <p>{{ 'nh-assistant.admin.shadow-variants.load-failed' | translate }} {{ loadErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n </div>\n } @else {\n @if (closed(); as reason) {\n <p class=\"muted\" [id]=\"id + '-closed'\" [attr.data-shadow-variants-closed]=\"reason\">\n {{ 'nh-assistant.admin.shadow-variants.closed.' + reason | translate: { max: variants()?.maxDataVariants } }}\n </p>\n }\n\n @if (creating()) {\n <form class=\"stack card\" data-form=\"shadow-variant\" novalidate (submit)=\"$event.preventDefault(); create()\">\n <h5>{{ 'nh-assistant.admin.shadow-variants.form.title' | translate }}</h5>\n <p class=\"hint\">{{ 'nh-assistant.admin.shadow-variants.form.copies' | translate }}</p>\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.shadow-variants.form.id' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-id [id]=\"id + '-id'\" [maxLength]=\"maxId\" [value]=\"variantId()\"\n [attr.aria-invalid]=\"fieldError('id') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id', id + '-id-error')\"\n (input)=\"variantId.set(value($event)); touch('id')\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">{{ 'nh-assistant.admin.shadow-variants.form.id-hint' | translate }}</p>\n @if (errorKey('id'); as key) {\n <p class=\"field-error\" [id]=\"id + '-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('id')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.shadow-variants.form.name' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-name [id]=\"id + '-name'\" [maxLength]=\"maxName\" [value]=\"displayName()\"\n [attr.aria-invalid]=\"fieldError('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'displayName', id + '-name-error')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\n @if (errorKey('displayName'); as key) {\n <p class=\"field-error\" [id]=\"id + '-name-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('displayName')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.shadow-variants.form.description' | translate }}</label>\n <textarea rows=\"2\" [id]=\"id + '-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'description', id + '-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\"></textarea>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.shadow-variants.form.instructions' | translate }}</label>\n <textarea rows=\"6\" data-variant-instructions [id]=\"id + '-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-instructions-hint', 'instructions', id + '-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.shadow-variants.form.instructions-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"instructions().length > maxInstructions\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: maxInstructions } }}</span>\n </p>\n @if (errorKey('instructions'); as key) {\n <p class=\"field-error\" [id]=\"id + '-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n\n @if (hasErrors()) {\n <div class=\"form-error\" role=\"alert\" data-form-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n @if (serverError(); as failure) {\n @if (failure.code === 'assistant-validation') {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n } @else {\n {{ errorKeys() | nhAssistantTranslate: failure.code }}\n }\n } @else {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n }\n @if (otherFieldErrors().length > 0) {\n <ul>\n @for (field of otherFieldErrors(); track field) {\n <li><span class=\"mono\">{{ field }}</span></li>\n }\n </ul>\n }\n </div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" (click)=\"cancelCreate()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.shadow-variants.form.create') | translate }}</button>\n </div>\n </form>\n }\n\n @if (promotedNote(); as note) {\n <p class=\"message\" role=\"status\" data-promoted>\n {{ 'nh-assistant.admin.shadow-variants.promoted' | translate: { variant: note.variant, name: liveName(), version: note.version } }}\n </p>\n }\n\n @if ((variants()?.variants ?? []).length === 0) {\n <p class=\"state\" data-shadow-variants-empty>{{ 'nh-assistant.admin.shadow-variants.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (variant of variants()?.variants ?? []; track variant.agentId) {\n <li class=\"skill\" [attr.data-shadow-variant]=\"variant.agentId\" [attr.data-shadow-variant-source]=\"variant.source\">\n <div class=\"card-header\">\n <strong data-shadow-variant-name>{{ variantName(variant) }}</strong>\n <span class=\"mono muted\">{{ variant.agentId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.shadow-variants.source.' + variant.source | translate }}</span>\n @if (!variant.hasRunSettings) {\n <span class=\"badge\" data-shadow-variant-needs-settings>{{ 'nh-assistant.admin.shadow-variants.needs-settings' | translate }}</span>\n } @else if (variant.inEffect) {\n <span class=\"badge\" data-shadow-variant-in-effect>{{ 'nh-assistant.admin.shadow-variants.in-effect' | translate }}</span>\n } @else {\n <span class=\"badge danger\" data-shadow-variant-out-of-effect>{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n @if (variant.problem; as problem) {\n <p class=\"message warning\" [attr.data-shadow-variant-problem]=\"problem\">\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.shadow-variants.problems.' + problem | translate }}\n </p>\n }\n @if (variant.source === 'data') {\n <div class=\"card-actions\">\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-open-variant]=\"variant.agentId\"\n [attr.aria-label]=\"'nh-assistant.admin.shadow-variants.open-named' | translate: { name: variantName(variant) }\"\n (click)=\"openVariant.emit(variant.agentId)\">\n <nh-assistant-icon name=\"list\" />{{ (variant.hasRunSettings ? 'nh-assistant.admin.shadow-variants.open' : 'nh-assistant.admin.shadow-variants.set-up') | translate }}\n </button>\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-promote-variant]=\"variant.agentId\"\n [attr.aria-label]=\"'nh-assistant.admin.shadow-variants.promote-named' | translate: { variant: variantName(variant), name: liveName() }\"\n [attr.aria-expanded]=\"promoting() === variant.agentId\"\n [disabled]=\"promoteBusy() || (promoting() !== null && promoting() !== variant.agentId)\"\n (click)=\"promoting() === variant.agentId ? cancelPromote() : startPromote(variant)\">\n <nh-assistant-icon name=\"check\" />{{ 'nh-assistant.admin.shadow-variants.promote' | translate: { name: liveName() } }}\n </button>\n </div>\n @if (promoting() === variant.agentId) {\n <!-- The promotion changes the live agent: it asks first and says what stays. -->\n <div class=\"stack card\" role=\"group\" [attr.aria-labelledby]=\"id + '-promote-title'\" data-promote-confirm>\n <h5 [id]=\"id + '-promote-title'\">{{ 'nh-assistant.admin.shadow-variants.promote-confirm.title' | translate: { variant: variantName(variant), name: liveName() } }}</h5>\n <p class=\"hint\" data-promote-explain>{{ 'nh-assistant.admin.shadow-variants.promote-confirm.' + (agent().source === 'code' ? 'code' : 'admin') | translate: { name: liveName() } }}</p>\n <p class=\"hint\">{{ 'nh-assistant.admin.shadow-variants.promote-confirm.removed' | translate }}</p>\n <label class=\"check described\">\n <input type=\"checkbox\" data-promote-move-skills [checked]=\"moveSkills()\" [disabled]=\"promoteBusy()\" (change)=\"moveSkills.set(checked($event))\" />\n <span>\n <span>{{ 'nh-assistant.admin.shadow-variants.promote-confirm.move-skills' | translate }}</span>\n <span class=\"muted\">{{ 'nh-assistant.admin.shadow-variants.promote-confirm.move-skills-hint' | translate }}</span>\n </span>\n </label>\n @if (promoteError(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-promote-error>\n <nh-assistant-icon name=\"warning\" />\n <div>{{ promoteErrorKeys() | nhAssistantTranslate: failure.code }}</div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"promoteBusy()\" (click)=\"cancelPromote()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"button\" data-promote-confirm-button [disabled]=\"promoteBusy()\" (click)=\"promote(variant)\">\n {{ (promoteBusy() ? 'nh-assistant.admin.shadow-variants.promote-confirm.promoting' : 'nh-assistant.admin.shadow-variants.promote-confirm.confirm') | translate }}\n </button>\n </div>\n </div>\n }\n }\n </li>\n }\n </ul>\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;min-width:0;color:var(--nha-text);font-family:var(--nha-font);font-size:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n", "h5{margin:0;font-size:15px;font-weight:750}.group{display:flex;flex-direction:column;gap:10px;min-width:0;border-top:1px solid var(--nha-border);padding-top:14px}.group>legend{float:left;width:100%;margin-bottom:2px;font-size:14px;font-weight:750}.choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:8px}.choice{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.choice input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.choice>span{display:grid;gap:2px;min-width:0}.choice strong{font-size:13px}.choice.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.choice:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.block{display:block;margin-top:2px}.advanced{border-top:1px solid var(--nha-border);padding-top:12px}.advanced>summary{width:fit-content;border-radius:6px;font-size:14px;font-weight:750;cursor:pointer}.advanced>summary:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.advanced>.stack{margin-top:12px}.examples{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 0;padding:0;list-style:none}.examples button{border:1px solid var(--nha-border);border-radius:999px;padding:3px 10px;color:var(--nha-text);background:transparent;font:inherit;font-size:12px;cursor:pointer}.examples button:hover{background:var(--nha-surface-strong)}.examples button:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.steps{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.steps li{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:4px 10px;color:var(--nha-text-muted);background:var(--nha-surface-strong);font-size:12px;font-weight:700}.steps li[aria-current=step]{color:var(--nha-accent-contrast);background:var(--nha-accent)}.steps li.done{color:var(--nha-success);background:var(--nha-success-soft)}.review{display:grid;grid-template-columns:minmax(0,max-content) minmax(0,1fr);gap:6px 16px;margin:0;font-size:13px}.review dt{color:var(--nha-text-muted)}.review dd{margin:0;overflow-wrap:anywhere}.tool-choice{display:flex;flex-direction:column;gap:2px;min-width:0;overflow-wrap:anywhere}@media(max-width:520px){.review{grid-template-columns:minmax(0,1fr)}.review dd{margin-bottom:6px}}.table-scroll{max-width:100%;overflow-x:auto}.summary{margin:0;font-size:13px;overflow-wrap:anywhere}.checks.routes{grid-template-columns:minmax(0,1fr);gap:10px}.check.blocked{cursor:not-allowed}.check.blocked>span>span:first-child{color:var(--nha-text-muted)}\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 }); }
|
|
5694
5780
|
}
|
|
5695
5781
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAgentShadowVariantsComponent, decorators: [{
|
|
5696
5782
|
type: Component,
|
|
5697
|
-
args: [{ selector: 'nh-assistant-agent-shadow-variants', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- The agent's shadow variants: in code read only, created as data within the ceiling in code. -->\n<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\" data-shadow-variants>\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.shadow-variants.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.shadow-variants.description' | translate }}</p>\n </div>\n @if (!loading() && !loadError() && variants()?.allowsDataVariants) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-open-form=\"shadow-variant\"\n [attr.aria-describedby]=\"closed() ? id + '-closed' : null\"\n [disabled]=\"busy() || closed() !== null || creating()\"\n (click)=\"startCreate()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.shadow-variants.add' | translate }}\n </button>\n }\n </header>\n\n @if (loading()) {\n <p class=\"state\" role=\"status\" data-shadow-variants-loading>{{ 'nh-assistant.admin.shadow-variants.loading' | translate }}</p>\n } @else if (loadError(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-shadow-variants-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <p>{{ 'nh-assistant.admin.shadow-variants.load-failed' | translate }} {{ loadErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n </div>\n } @else {\n @if (closed(); as reason) {\n <p class=\"muted\" [id]=\"id + '-closed'\" [attr.data-shadow-variants-closed]=\"reason\">\n {{ 'nh-assistant.admin.shadow-variants.closed.' + reason | translate: { max: variants()?.maxDataVariants } }}\n </p>\n }\n\n @if (creating()) {\n <form class=\"stack card\" data-form=\"shadow-variant\" novalidate (submit)=\"$event.preventDefault(); create()\">\n <h5>{{ 'nh-assistant.admin.shadow-variants.form.title' | translate }}</h5>\n <p class=\"hint\">{{ 'nh-assistant.admin.shadow-variants.form.copies' | translate }}</p>\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.shadow-variants.form.id' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-id [id]=\"id + '-id'\" [maxLength]=\"maxId\" [value]=\"variantId()\"\n [attr.aria-invalid]=\"fieldError('id') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id', id + '-id-error')\"\n (input)=\"variantId.set(value($event)); touch('id')\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">{{ 'nh-assistant.admin.shadow-variants.form.id-hint' | translate }}</p>\n @if (errorKey('id'); as key) {\n <p class=\"field-error\" [id]=\"id + '-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('id')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.shadow-variants.form.name' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-name [id]=\"id + '-name'\" [maxLength]=\"maxName\" [value]=\"displayName()\"\n [attr.aria-invalid]=\"fieldError('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'displayName', id + '-name-error')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\n @if (errorKey('displayName'); as key) {\n <p class=\"field-error\" [id]=\"id + '-name-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('displayName')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.shadow-variants.form.description' | translate }}</label>\n <textarea rows=\"2\" [id]=\"id + '-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'description', id + '-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\"></textarea>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.shadow-variants.form.instructions' | translate }}</label>\n <textarea rows=\"6\" data-variant-instructions [id]=\"id + '-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-instructions-hint', 'instructions', id + '-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.shadow-variants.form.instructions-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"instructions().length > maxInstructions\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: maxInstructions } }}</span>\n </p>\n @if (errorKey('instructions'); as key) {\n <p class=\"field-error\" [id]=\"id + '-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n\n @if (hasErrors()) {\n <div class=\"form-error\" role=\"alert\" data-form-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n @if (serverError(); as failure) {\n @if (failure.code === 'assistant-validation') {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n } @else {\n {{ errorKeys() | nhAssistantTranslate: failure.code }}\n }\n } @else {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n }\n @if (otherFieldErrors().length > 0) {\n <ul>\n @for (field of otherFieldErrors(); track field) {\n <li><span class=\"mono\">{{ field }}</span></li>\n }\n </ul>\n }\n </div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" (click)=\"cancelCreate()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.shadow-variants.form.create') | translate }}</button>\n </div>\n </form>\n }\n\n @if ((variants()?.variants ?? []).length === 0) {\n <p class=\"state\" data-shadow-variants-empty>{{ 'nh-assistant.admin.shadow-variants.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (variant of variants()?.variants ?? []; track variant.agentId) {\n <li class=\"skill\" [attr.data-shadow-variant]=\"variant.agentId\" [attr.data-shadow-variant-source]=\"variant.source\">\n <div class=\"card-header\">\n <strong data-shadow-variant-name>{{ variantName(variant) }}</strong>\n <span class=\"mono muted\">{{ variant.agentId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.shadow-variants.source.' + variant.source | translate }}</span>\n @if (!variant.hasRunSettings) {\n <span class=\"badge\" data-shadow-variant-needs-settings>{{ 'nh-assistant.admin.shadow-variants.needs-settings' | translate }}</span>\n } @else if (variant.inEffect) {\n <span class=\"badge\" data-shadow-variant-in-effect>{{ 'nh-assistant.admin.shadow-variants.in-effect' | translate }}</span>\n } @else {\n <span class=\"badge danger\" data-shadow-variant-out-of-effect>{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n @if (variant.problem; as problem) {\n <p class=\"message warning\" [attr.data-shadow-variant-problem]=\"problem\">\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.shadow-variants.problems.' + problem | translate }}\n </p>\n }\n @if (variant.source === 'data') {\n <div class=\"card-actions\">\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-open-variant]=\"variant.agentId\"\n [attr.aria-label]=\"'nh-assistant.admin.shadow-variants.open-named' | translate: { name: variantName(variant) }\"\n (click)=\"openVariant.emit(variant.agentId)\">\n <nh-assistant-icon name=\"list\" />{{ (variant.hasRunSettings ? 'nh-assistant.admin.shadow-variants.open' : 'nh-assistant.admin.shadow-variants.set-up') | translate }}\n </button>\n </div>\n }\n </li>\n }\n </ul>\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;min-width:0;color:var(--nha-text);font-family:var(--nha-font);font-size:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n", "h5{margin:0;font-size:15px;font-weight:750}.group{display:flex;flex-direction:column;gap:10px;min-width:0;border-top:1px solid var(--nha-border);padding-top:14px}.group>legend{float:left;width:100%;margin-bottom:2px;font-size:14px;font-weight:750}.choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:8px}.choice{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.choice input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.choice>span{display:grid;gap:2px;min-width:0}.choice strong{font-size:13px}.choice.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.choice:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.block{display:block;margin-top:2px}.advanced{border-top:1px solid var(--nha-border);padding-top:12px}.advanced>summary{width:fit-content;border-radius:6px;font-size:14px;font-weight:750;cursor:pointer}.advanced>summary:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.advanced>.stack{margin-top:12px}.examples{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 0;padding:0;list-style:none}.examples button{border:1px solid var(--nha-border);border-radius:999px;padding:3px 10px;color:var(--nha-text);background:transparent;font:inherit;font-size:12px;cursor:pointer}.examples button:hover{background:var(--nha-surface-strong)}.examples button:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.steps{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.steps li{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:4px 10px;color:var(--nha-text-muted);background:var(--nha-surface-strong);font-size:12px;font-weight:700}.steps li[aria-current=step]{color:var(--nha-accent-contrast);background:var(--nha-accent)}.steps li.done{color:var(--nha-success);background:var(--nha-success-soft)}.review{display:grid;grid-template-columns:minmax(0,max-content) minmax(0,1fr);gap:6px 16px;margin:0;font-size:13px}.review dt{color:var(--nha-text-muted)}.review dd{margin:0;overflow-wrap:anywhere}.tool-choice{display:flex;flex-direction:column;gap:2px;min-width:0;overflow-wrap:anywhere}@media(max-width:520px){.review{grid-template-columns:minmax(0,1fr)}.review dd{margin-bottom:6px}}.table-scroll{max-width:100%;overflow-x:auto}.summary{margin:0;font-size:13px;overflow-wrap:anywhere}.checks.routes{grid-template-columns:minmax(0,1fr);gap:10px}.check.blocked{cursor:not-allowed}.check.blocked>span>span:first-child{color:var(--nha-text-muted)}\n"] }]
|
|
5698
|
-
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], created: [{ type: i0.Output, args: ["created"] }], openVariant: [{ type: i0.Output, args: ["openVariant"] }] } });
|
|
5783
|
+
args: [{ selector: 'nh-assistant-agent-shadow-variants', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- The agent's shadow variants: in code read only, created as data within the ceiling in code. -->\n<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\" data-shadow-variants>\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.shadow-variants.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.shadow-variants.description' | translate }}</p>\n </div>\n @if (!loading() && !loadError() && variants()?.allowsDataVariants) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-open-form=\"shadow-variant\"\n [attr.aria-describedby]=\"closed() ? id + '-closed' : null\"\n [disabled]=\"busy() || closed() !== null || creating()\"\n (click)=\"startCreate()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.shadow-variants.add' | translate }}\n </button>\n }\n </header>\n\n @if (loading()) {\n <p class=\"state\" role=\"status\" data-shadow-variants-loading>{{ 'nh-assistant.admin.shadow-variants.loading' | translate }}</p>\n } @else if (loadError(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-shadow-variants-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <p>{{ 'nh-assistant.admin.shadow-variants.load-failed' | translate }} {{ loadErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n </div>\n } @else {\n @if (closed(); as reason) {\n <p class=\"muted\" [id]=\"id + '-closed'\" [attr.data-shadow-variants-closed]=\"reason\">\n {{ 'nh-assistant.admin.shadow-variants.closed.' + reason | translate: { max: variants()?.maxDataVariants } }}\n </p>\n }\n\n @if (creating()) {\n <form class=\"stack card\" data-form=\"shadow-variant\" novalidate (submit)=\"$event.preventDefault(); create()\">\n <h5>{{ 'nh-assistant.admin.shadow-variants.form.title' | translate }}</h5>\n <p class=\"hint\">{{ 'nh-assistant.admin.shadow-variants.form.copies' | translate }}</p>\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.shadow-variants.form.id' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-id [id]=\"id + '-id'\" [maxLength]=\"maxId\" [value]=\"variantId()\"\n [attr.aria-invalid]=\"fieldError('id') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id', id + '-id-error')\"\n (input)=\"variantId.set(value($event)); touch('id')\" />\n <p class=\"hint\" [id]=\"id + '-id-hint'\">{{ 'nh-assistant.admin.shadow-variants.form.id-hint' | translate }}</p>\n @if (errorKey('id'); as key) {\n <p class=\"field-error\" [id]=\"id + '-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('id')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.shadow-variants.form.name' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" data-variant-name [id]=\"id + '-name'\" [maxLength]=\"maxName\" [value]=\"displayName()\"\n [attr.aria-invalid]=\"fieldError('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'displayName', id + '-name-error')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\n @if (errorKey('displayName'); as key) {\n <p class=\"field-error\" [id]=\"id + '-name-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('displayName')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.shadow-variants.form.description' | translate }}</label>\n <textarea rows=\"2\" [id]=\"id + '-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(null, 'description', id + '-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\"></textarea>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.shadow-variants.form.instructions' | translate }}</label>\n <textarea rows=\"6\" data-variant-instructions [id]=\"id + '-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-instructions-hint', 'instructions', id + '-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.shadow-variants.form.instructions-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"instructions().length > maxInstructions\">{{ 'nh-assistant.admin.characters' | translate: { count: instructions().length, max: maxInstructions } }}</span>\n </p>\n @if (errorKey('instructions'); as key) {\n <p class=\"field-error\" [id]=\"id + '-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n\n @if (hasErrors()) {\n <div class=\"form-error\" role=\"alert\" data-form-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n @if (serverError(); as failure) {\n @if (failure.code === 'assistant-validation') {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n } @else {\n {{ errorKeys() | nhAssistantTranslate: failure.code }}\n }\n } @else {\n {{ 'nh-assistant.admin.run-config.check-fields' | translate }}\n }\n @if (otherFieldErrors().length > 0) {\n <ul>\n @for (field of otherFieldErrors(); track field) {\n <li><span class=\"mono\">{{ field }}</span></li>\n }\n </ul>\n }\n </div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" (click)=\"cancelCreate()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.shadow-variants.form.create') | translate }}</button>\n </div>\n </form>\n }\n\n @if (promotedNote(); as note) {\n <p class=\"message\" role=\"status\" data-promoted>\n {{ 'nh-assistant.admin.shadow-variants.promoted' | translate: { variant: note.variant, name: liveName(), version: note.version } }}\n </p>\n }\n\n @if ((variants()?.variants ?? []).length === 0) {\n <p class=\"state\" data-shadow-variants-empty>{{ 'nh-assistant.admin.shadow-variants.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (variant of variants()?.variants ?? []; track variant.agentId) {\n <li class=\"skill\" [attr.data-shadow-variant]=\"variant.agentId\" [attr.data-shadow-variant-source]=\"variant.source\">\n <div class=\"card-header\">\n <strong data-shadow-variant-name>{{ variantName(variant) }}</strong>\n <span class=\"mono muted\">{{ variant.agentId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.shadow-variants.source.' + variant.source | translate }}</span>\n @if (!variant.hasRunSettings) {\n <span class=\"badge\" data-shadow-variant-needs-settings>{{ 'nh-assistant.admin.shadow-variants.needs-settings' | translate }}</span>\n } @else if (variant.inEffect) {\n <span class=\"badge\" data-shadow-variant-in-effect>{{ 'nh-assistant.admin.shadow-variants.in-effect' | translate }}</span>\n } @else {\n <span class=\"badge danger\" data-shadow-variant-out-of-effect>{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n @if (variant.problem; as problem) {\n <p class=\"message warning\" [attr.data-shadow-variant-problem]=\"problem\">\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.shadow-variants.problems.' + problem | translate }}\n </p>\n }\n @if (variant.source === 'data') {\n <div class=\"card-actions\">\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-open-variant]=\"variant.agentId\"\n [attr.aria-label]=\"'nh-assistant.admin.shadow-variants.open-named' | translate: { name: variantName(variant) }\"\n (click)=\"openVariant.emit(variant.agentId)\">\n <nh-assistant-icon name=\"list\" />{{ (variant.hasRunSettings ? 'nh-assistant.admin.shadow-variants.open' : 'nh-assistant.admin.shadow-variants.set-up') | translate }}\n </button>\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-promote-variant]=\"variant.agentId\"\n [attr.aria-label]=\"'nh-assistant.admin.shadow-variants.promote-named' | translate: { variant: variantName(variant), name: liveName() }\"\n [attr.aria-expanded]=\"promoting() === variant.agentId\"\n [disabled]=\"promoteBusy() || (promoting() !== null && promoting() !== variant.agentId)\"\n (click)=\"promoting() === variant.agentId ? cancelPromote() : startPromote(variant)\">\n <nh-assistant-icon name=\"check\" />{{ 'nh-assistant.admin.shadow-variants.promote' | translate: { name: liveName() } }}\n </button>\n </div>\n @if (promoting() === variant.agentId) {\n <!-- The promotion changes the live agent: it asks first and says what stays. -->\n <div class=\"stack card\" role=\"group\" [attr.aria-labelledby]=\"id + '-promote-title'\" data-promote-confirm>\n <h5 [id]=\"id + '-promote-title'\">{{ 'nh-assistant.admin.shadow-variants.promote-confirm.title' | translate: { variant: variantName(variant), name: liveName() } }}</h5>\n <p class=\"hint\" data-promote-explain>{{ 'nh-assistant.admin.shadow-variants.promote-confirm.' + (agent().source === 'code' ? 'code' : 'admin') | translate: { name: liveName() } }}</p>\n <p class=\"hint\">{{ 'nh-assistant.admin.shadow-variants.promote-confirm.removed' | translate }}</p>\n <label class=\"check described\">\n <input type=\"checkbox\" data-promote-move-skills [checked]=\"moveSkills()\" [disabled]=\"promoteBusy()\" (change)=\"moveSkills.set(checked($event))\" />\n <span>\n <span>{{ 'nh-assistant.admin.shadow-variants.promote-confirm.move-skills' | translate }}</span>\n <span class=\"muted\">{{ 'nh-assistant.admin.shadow-variants.promote-confirm.move-skills-hint' | translate }}</span>\n </span>\n </label>\n @if (promoteError(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-promote-error>\n <nh-assistant-icon name=\"warning\" />\n <div>{{ promoteErrorKeys() | nhAssistantTranslate: failure.code }}</div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"promoteBusy()\" (click)=\"cancelPromote()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"button\" data-promote-confirm-button [disabled]=\"promoteBusy()\" (click)=\"promote(variant)\">\n {{ (promoteBusy() ? 'nh-assistant.admin.shadow-variants.promote-confirm.promoting' : 'nh-assistant.admin.shadow-variants.promote-confirm.confirm') | translate }}\n </button>\n </div>\n </div>\n }\n }\n </li>\n }\n </ul>\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;min-width:0;color:var(--nha-text);font-family:var(--nha-font);font-size:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n", "h5{margin:0;font-size:15px;font-weight:750}.group{display:flex;flex-direction:column;gap:10px;min-width:0;border-top:1px solid var(--nha-border);padding-top:14px}.group>legend{float:left;width:100%;margin-bottom:2px;font-size:14px;font-weight:750}.choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:8px}.choice{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.choice input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.choice>span{display:grid;gap:2px;min-width:0}.choice strong{font-size:13px}.choice.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.choice:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.block{display:block;margin-top:2px}.advanced{border-top:1px solid var(--nha-border);padding-top:12px}.advanced>summary{width:fit-content;border-radius:6px;font-size:14px;font-weight:750;cursor:pointer}.advanced>summary:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.advanced>.stack{margin-top:12px}.examples{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 0;padding:0;list-style:none}.examples button{border:1px solid var(--nha-border);border-radius:999px;padding:3px 10px;color:var(--nha-text);background:transparent;font:inherit;font-size:12px;cursor:pointer}.examples button:hover{background:var(--nha-surface-strong)}.examples button:focus-visible{outline:2px solid var(--nha-highlight);outline-offset:2px}.steps{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.steps li{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:4px 10px;color:var(--nha-text-muted);background:var(--nha-surface-strong);font-size:12px;font-weight:700}.steps li[aria-current=step]{color:var(--nha-accent-contrast);background:var(--nha-accent)}.steps li.done{color:var(--nha-success);background:var(--nha-success-soft)}.review{display:grid;grid-template-columns:minmax(0,max-content) minmax(0,1fr);gap:6px 16px;margin:0;font-size:13px}.review dt{color:var(--nha-text-muted)}.review dd{margin:0;overflow-wrap:anywhere}.tool-choice{display:flex;flex-direction:column;gap:2px;min-width:0;overflow-wrap:anywhere}@media(max-width:520px){.review{grid-template-columns:minmax(0,1fr)}.review dd{margin-bottom:6px}}.table-scroll{max-width:100%;overflow-x:auto}.summary{margin:0;font-size:13px;overflow-wrap:anywhere}.checks.routes{grid-template-columns:minmax(0,1fr);gap:10px}.check.blocked{cursor:not-allowed}.check.blocked>span>span:first-child{color:var(--nha-text-muted)}\n"] }]
|
|
5784
|
+
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], created: [{ type: i0.Output, args: ["created"] }], openVariant: [{ type: i0.Output, args: ["openVariant"] }], promoted: [{ type: i0.Output, args: ["promoted"] }] } });
|
|
5699
5785
|
|
|
5700
5786
|
/** The longest package id. */
|
|
5701
5787
|
const maxPackageId = 128;
|
|
@@ -5887,12 +5973,7 @@ class NhAssistantAgentPackageExportDialogComponent {
|
|
|
5887
5973
|
}
|
|
5888
5974
|
agentName(agentId) {
|
|
5889
5975
|
const agent = this.agents().find(item => item.id === agentId);
|
|
5890
|
-
|
|
5891
|
-
return agentId;
|
|
5892
|
-
}
|
|
5893
|
-
const keys = codeTextKeys(agent.source, agent.displayName);
|
|
5894
|
-
const translated = keys.length > 0 ? this.translate.instant(keys[0]) : null;
|
|
5895
|
-
return translated && translated !== keys[0] ? translated : agent.displayName;
|
|
5976
|
+
return agent ? agentDisplayName(this.translate, agent) : agentId;
|
|
5896
5977
|
}
|
|
5897
5978
|
/** Exports the chosen agents with the chosen locks and saves the package as a JSON file. */
|
|
5898
5979
|
download() {
|
|
@@ -6236,11 +6317,12 @@ class NhAssistantAgentPackageImportDialogComponent {
|
|
|
6236
6317
|
agentName(agentId) {
|
|
6237
6318
|
const agent = this.agents().find(item => item.id === agentId);
|
|
6238
6319
|
if (agent) {
|
|
6239
|
-
|
|
6240
|
-
const translated = keys.length > 0 ? this.translate.instant(keys[0]) : null;
|
|
6241
|
-
return translated && translated !== keys[0] ? translated : agent.displayName;
|
|
6320
|
+
return agentDisplayName(this.translate, agent);
|
|
6242
6321
|
}
|
|
6243
|
-
|
|
6322
|
+
// An agent the host does not have yet reads as the package names it; one in code by its key.
|
|
6323
|
+
const packaged = this.source().package?.agents?.find(item => item?.id === agentId);
|
|
6324
|
+
const displayName = packaged?.definition?.displayName;
|
|
6325
|
+
return packaged && displayName ? agentDisplayName(this.translate, { source: packaged.source, displayName }) : agentId;
|
|
6244
6326
|
}
|
|
6245
6327
|
/** The translation keys of the codes of one field, the first one known. */
|
|
6246
6328
|
fieldErrorKeys(codes) {
|
|
@@ -6510,9 +6592,7 @@ class NhAssistantAdminAgentsComponent {
|
|
|
6510
6592
|
if (!agent) {
|
|
6511
6593
|
return null;
|
|
6512
6594
|
}
|
|
6513
|
-
|
|
6514
|
-
const translated = keys.length > 0 ? this.translate.instant(keys[0]) : null;
|
|
6515
|
-
return runNowAgentOf(agent, translated && translated !== keys[0] ? translated : agent.displayName);
|
|
6595
|
+
return runNowAgentOf(agent, agentDisplayName(this.translate, agent));
|
|
6516
6596
|
}, ...(ngDevMode ? [{ debugName: "runNowAgent" }] : []));
|
|
6517
6597
|
/** The run configuration opens with the guided setup, for an agent created to work on its own. */
|
|
6518
6598
|
this.setupOnOpen = signal(false, ...(ngDevMode ? [{ debugName: "setupOnOpen" }] : []));
|
|
@@ -6756,6 +6836,19 @@ class NhAssistantAdminAgentsComponent {
|
|
|
6756
6836
|
this.onSaved(variant);
|
|
6757
6837
|
this.openRunConfiguration(variant, true);
|
|
6758
6838
|
}
|
|
6839
|
+
/**
|
|
6840
|
+
* A data shadow variant promoted onto the agent whose run configuration is open: the agent shows its
|
|
6841
|
+
* new version there and in the list, and the variant, which was removed, leaves the list.
|
|
6842
|
+
*/
|
|
6843
|
+
onVariantPromoted(promotion) {
|
|
6844
|
+
this.agents.update(agents => agents
|
|
6845
|
+
.filter(item => item.id !== promotion.variantId)
|
|
6846
|
+
.map(item => item.id === promotion.agent.id ? promotion.agent : item));
|
|
6847
|
+
if (this.configuring()?.id === promotion.agent.id) {
|
|
6848
|
+
this.configuring.set(promotion.agent);
|
|
6849
|
+
}
|
|
6850
|
+
this.refreshChat();
|
|
6851
|
+
}
|
|
6759
6852
|
/** The run configuration of a data shadow variant of the agent whose run configuration is open. */
|
|
6760
6853
|
variantFromRunConfiguration(variantId) {
|
|
6761
6854
|
const variant = this.agents().find(item => item.id === variantId);
|
|
@@ -7113,7 +7206,7 @@ class NhAssistantAdminAgentsComponent {
|
|
|
7113
7206
|
void this.store.reloadStatus();
|
|
7114
7207
|
}
|
|
7115
7208
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7116
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAdminAgentsComponent, isStandalone: true, selector: "nh-assistant-admin-agents", outputs: { openMcpServers: "openMcpServers" }, viewQueries: [{ propertyName: "backButton", first: true, predicate: ["back"], descendants: true, isSignal: true }, { propertyName: "reasonInput", first: true, predicate: ["reasonInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (editing() !== undefined) {\n <nh-assistant-admin-agent-editor\n [agent]=\"editing() ?? null\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [catalog]=\"catalog()\"\n [catalogUnavailable]=\"catalogError() !== null\"\n (saved)=\"onEditorSaved($event)\"\n (workRequested)=\"onWorkRequested($event)\"\n (cancelled)=\"onEditorCancelled()\" />\n} @else if (reporting(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeReport()\">\n {{ 'nh-assistant.admin.feedback.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-feedback-report [agentId]=\"agent.id\" />\n </div>\n} @else if (configuring(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRunConfiguration()\">\n {{ 'nh-assistant.admin.run-config.back' | translate }}\n </button>\n </div>\n <nh-assistant-agent-run-configuration\n [agent]=\"agent\"\n [startSetup]=\"setupOnOpen()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [agents]=\"agents()\"\n (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\"\n (openAgent)=\"askerFromRunConfiguration(agent, $event)\" />\n <nh-assistant-agent-hand-offs [agent]=\"agent\" [agents]=\"agents()\" [subjectTypes]=\"catalog()?.subjectTypes ?? []\" />\n <nh-assistant-agent-shadow-variants\n [agent]=\"agent\"\n (created)=\"onVariantCreated($event)\"\n (openVariant)=\"variantFromRunConfiguration($event)\" />\n </div>\n} @else if (viewingRuns(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRuns()\">\n {{ (returnTo() === agent.id ? 'nh-assistant.admin.runs.back-to-run-config' : 'nh-assistant.admin.runs.back') | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-run-history\n [agentId]=\"agent.id\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n (openConversation)=\"openConversation($event)\" />\n </div>\n} @else if (evaluating(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeEvaluation()\">\n {{ 'nh-assistant.admin.evaluation.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-evaluation [agentId]=\"agent.id\" [variants]=\"variantsOf(agent)\" />\n </div>\n} @else {\n <section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.agents.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.description' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" aria-haspopup=\"dialog\" data-import-package [disabled]=\"loading() || loadFailed()\" (click)=\"importPackage()\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.import' | translate }}\n </button>\n <button class=\"primary\" type=\"button\" [disabled]=\"loading() || loadFailed()\" (click)=\"create()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agents.new' | translate }}\n </button>\n </div>\n </header>\n\n @if (error(); as failure) {\n @if (errorAgentId() === null) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n @if (!loading() && !loadFailed()) {\n @if (catalogError(); as failure) {\n <!-- Without the run catalog nothing that depends on it is offered: run now, what agents work on, groups. -->\n <div class=\"message warning catalog-error\" role=\"alert\" data-catalog-error>\n <nh-assistant-icon name=\"warning\" />\n <span class=\"grow\">\n {{ 'nh-assistant.admin.agents.catalog-failed' | translate }}\n {{ catalogErrorKeys() | nhAssistantTranslate: failure.code }}\n </span>\n <button class=\"secondary\" type=\"button\" data-catalog-retry [disabled]=\"catalogLoading()\" (click)=\"retryCatalog()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n }\n <nh-assistant-account-names-error [names]=\"accountNameLookup\" />\n }\n\n @if (loading()) {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n } @else if (loadFailed()) {\n <div class=\"state\" role=\"alert\">\n <p>{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">{{ 'nh-assistant.admin.retry' | translate }}</button>\n </div>\n } @else if (agents().length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.agents.empty' | translate }}</p>\n } @else {\n <ul class=\"cards\">\n @for (agent of agents(); track agent.id) {\n <li class=\"card\" [class.inactive]=\"agent.runState !== 'active'\" [attr.aria-busy]=\"busyAgentId() === agent.id\">\n <div class=\"card-header\">\n <!-- An agent in code names and describes itself with translation keys. -->\n <strong>{{ (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }}</strong>\n <span class=\"mono muted\">{{ agent.id }}</span>\n <span class=\"badge\">{{ (agent.source === 'code' ? 'nh-assistant.admin.agents.source-code' : 'nh-assistant.admin.agents.source-admin') | translate }}</span>\n @if (agent.isOverridden) {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.agents.overridden' | translate }}</span>\n }\n <span\n class=\"badge\"\n [class.success]=\"agent.runState === 'active'\"\n [class.warning]=\"agent.runState === 'paused'\"\n [class.danger]=\"agent.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + agent.runState | translate }}</span>\n @if (agent.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n @if (agent.offeredInChat === false) {\n <span class=\"badge\" data-hidden-from-chat>{{ 'nh-assistant.admin.agents.chat.hidden' | translate }}</span>\n }\n @if (agent.package; as linked) {\n <span class=\"badge\" data-package-badge><nh-assistant-icon name=\"lock\" />{{ 'nh-assistant.admin.packages.linked-badge' | translate: { package: linked.packageId, version: linked.packageVersion } }}</span>\n }\n </div>\n <!-- The package the agent comes from; unlinking makes every part of it local. -->\n <nh-assistant-package-lock [lock]=\"agentPackageOf(agent)\" [agentId]=\"agent.id\" [part]=\"null\" (unlinked)=\"onPackageUnlinked()\" />\n @if (agent.description) {\n <p class=\"muted\">{{ codeTextKeys(agent.source, agent.description) | nhAssistantTranslate: agent.description }}</p>\n }\n <!-- A warning never refused the save: the agent is in effect but may not work as configured. -->\n @for (warning of agent.warnings ?? []; track warning) {\n <p class=\"message warning\" [attr.data-agent-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n <!-- The asset its instructions come from no longer resolves: the agent starts no model turn. -->\n @if (agent.instructionsProblem) {\n <p class=\"message error\" role=\"status\" data-agent-instructions-problem>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.instruction-assets.agent-problem' | translate }}\n {{ 'nh-assistant.admin.instruction-assets.problems.' + agent.instructionsProblem | translate }}\n </p>\n }\n @if (agent.runState === 'configured-off') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.configured-off-hint' | translate }}</p>\n } @else if (agent.runState !== 'active') {\n <p class=\"muted\">\n @if (agent.stateChangedAt) {\n <span [attr.title]=\"accountTitle(agent.stateChangedBy)\">{{ 'nh-assistant.admin.agents.state.changed' | translate: { user: accountName(agent.stateChangedBy), date: (agent.stateChangedAt | date: 'medium') } }}</span>\n }\n @if (agent.stateReason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: agent.stateReason } }}\n }\n </p>\n @if (agent.runState === 'paused') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: agent.waitingInputs } }}</p>\n }\n <!-- What releasing the kill switch does: an agent that was off goes back off. Older servers do not say. -->\n @if (agent.runState === 'stopped' && agent.offBeforeStop !== undefined) {\n <p class=\"muted\" data-stopped-hint [attr.data-off-before-stop]=\"agent.offBeforeStop\">\n {{ (agent.offBeforeStop ? 'nh-assistant.admin.agents.state.stopped-was-off-hint' : 'nh-assistant.admin.agents.state.stopped-was-on-hint') | translate }}\n </p>\n }\n @if (agent.runState === 'off') {\n <p class=\"muted\" data-off-hint>\n {{ 'nh-assistant.admin.agents.state.off-hint' | translate }}\n @if (!agent.stateChangedAt) {\n {{ 'nh-assistant.admin.agents.state.starts-off' | translate }}\n }\n </p>\n }\n }\n @if (agent.shadow; as shadow) {\n @if (shadow.shadow) {\n <p class=\"muted\">\n {{ (shadow.locked ? 'nh-assistant.admin.agents.shadow.locked' : 'nh-assistant.admin.agents.shadow.hint') | translate }}\n @if (shadow.changedAt && shadow.override !== null) {\n <span [attr.title]=\"accountTitle(shadow.changedBy)\">{{ 'nh-assistant.admin.agents.shadow.changed' | translate: { user: accountName(shadow.changedBy), date: (shadow.changedAt | date: 'medium') } }}</span>\n }\n @if (shadow.reason && shadow.override !== null) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: shadow.reason } }}\n }\n </p>\n }\n }\n @if (agent.serviceAccount; as account) {\n <p class=\"muted\" data-service-account>\n <span [attr.title]=\"accountTitle(account.actorId)\">{{ 'nh-assistant.admin.agents.service-account.label' | translate: { account: accountName(account.actorId) } }}</span>\n @if (account.overridden) {\n <span [attr.title]=\"accountTitle(account.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.configured' | translate: { account: accountName(account.configuredActorId) } }}</span>\n @if (account.reason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: account.reason } }}\n }\n }\n </p>\n }\n @if (worksOn(agent); as works) {\n <!-- What the agent works on; an agent in code shows its code setting. -->\n <p class=\"muted\" data-works-on>\n <span>{{ 'nh-assistant.admin.agents.works-on.label' | translate }}</span>\n <strong>\n @switch (works.only) {\n @case ('all') { {{ 'nh-assistant.admin.agents.works-on.all' | translate }} }\n @case ('types') { {{ works.types.join(', ') }} }\n @default { {{ 'nh-assistant.admin.agents.works-on.application' | translate }} }\n }\n </strong>\n @if (works.application && works.only !== 'application') {\n <span>{{ 'nh-assistant.admin.agents.works-on.and-application' | translate }}</span>\n }\n @if (works.perDivision) {\n <span>{{ 'nh-assistant.admin.agents.works-on.per-division' | translate }}</span>\n }\n @if (works.undeclared) {\n <span>{{ 'nh-assistant.admin.agents.works-on.undeclared' | translate }}</span>\n }\n </p>\n @if (works.all && works.known.length > 0) {\n <p class=\"muted\" data-known-types>{{ 'nh-assistant.admin.agents.works-on.known' | translate: { types: works.known.join(', ') } }}</p>\n }\n @if (works.runPolicy || works.viewPolicy) {\n <!-- Each policy is an item of its own, wrapping on narrow screens. -->\n <div class=\"meta\" data-works-on-policies>\n @if (works.runPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.run-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n @if (works.viewPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.view-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n </div>\n }\n }\n @if (groupNames(agent); as names) {\n <p class=\"muted\" data-agent-groups>{{ 'nh-assistant.admin.agents.groups' | translate: { groups: names } }}</p>\n }\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.autonomy.' + agent.autonomy | translate }}</span>\n <span>{{ (agent.toolSelectors.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: agent.toolSelectors.length } }}</span>\n <span>{{ (agent.mcpServerIds.length === 1 ? 'nh-assistant.admin.agents.server-count-one' : 'nh-assistant.admin.agents.server-count') | translate: { count: agent.mcpServerIds.length } }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: agent.version } }}</span>\n @if (agent.requiredPolicy; as policy) {\n <!-- The application may name its policies; otherwise the policy shows as it is called in code. -->\n <span data-required-policy>\n {{ 'nh-assistant.admin.agents.required-policy' | translate }}\n @if (policyKeys(policy) | nhAssistantTranslate; as text) {\n {{ text }}\n } @else {\n <code class=\"mono\">{{ policy }}</code>\n }\n </span>\n }\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"edit(agent)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n @for (action of stateActions(agent); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action)\">\n {{ stateKey('action', agent.runState, action) | translate }}\n </button>\n }\n @if (agent.runState !== 'configured-off') {\n @for (mode of shadowActions(agent.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n }\n @if (agent.serviceAccount; as account) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"set\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'set')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'set')\">\n {{ 'nh-assistant.admin.agents.service-account.action.set' | translate }}\n </button>\n @if (account.overridden) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"code\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'code')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'code')\">\n {{ 'nh-assistant.admin.agents.service-account.action.code' | translate }}\n </button>\n }\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-run-config-agent]=\"agent.id\" (click)=\"openRunConfiguration(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.run-config' | translate }}\n </button>\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-runs-agent]=\"agent.id\" (click)=\"openRuns(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.runs' | translate }}\n </button>\n }\n @if (canRunNow(agent)) {\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-run-now-agent]=\"agent.id\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"runNow(agent)\">\n <nh-assistant-icon name=\"send\" />{{ 'nh-assistant.admin.agents.run-now' | translate }}\n </button>\n }\n <button class=\"secondary\" type=\"button\" [attr.data-feedback-agent]=\"agent.id\" (click)=\"openReport(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.feedback' | translate }}\n </button>\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-export-package]=\"agent.id\"\n [attr.aria-label]=\"'nh-assistant.admin.packages.export-named' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"exportPackage(agent)\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.export' | translate }}\n </button>\n @if (variantsOf(agent).length > 0) {\n <button class=\"secondary\" type=\"button\" [attr.data-evaluation-agent]=\"agent.id\" (click)=\"openEvaluation(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.evaluation' | translate }}\n </button>\n }\n @if (agent.source === 'code' && agent.isOverridden) {\n @if (isConfirming(agent.id, 'reset')) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.reset-keeps-state' | translate }}</span>\n <button class=\"danger\" type=\"button\" (click)=\"reset(agent)\">{{ 'nh-assistant.admin.agents.confirm-reset' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"secondary\"\n type=\"button\"\n data-reset-agent\n [attr.aria-describedby]=\"resetLocked(agent) ? id + '-' + agent.id + '-reset-locked' : null\"\n [disabled]=\"busyAgentId() !== null || resetLocked(agent)\"\n (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\n @if (resetLocked(agent)) {\n <span class=\"muted\" data-reset-locked [id]=\"id + '-' + agent.id + '-reset-locked'\">{{ 'nh-assistant.admin.packages.reset-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n @if (agent.source === 'admin') {\n @if (isConfirming(agent.id, 'delete')) {\n <button class=\"danger\" type=\"button\" (click)=\"remove(agent)\">{{ 'nh-assistant.admin.confirm-delete' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"danger\"\n type=\"button\"\n data-delete-agent\n [attr.aria-describedby]=\"deleteLocked(agent) ? id + '-' + agent.id + '-delete-locked' : null\"\n [disabled]=\"busyAgentId() !== null || deleteLocked(agent)\"\n (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n @if (deleteLocked(agent)) {\n <span class=\"muted\" data-delete-locked [id]=\"id + '-' + agent.id + '-delete-locked'\">{{ 'nh-assistant.admin.packages.delete-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n </div>\n @if (agent.skills?.length) {\n <ul class=\"skills\" [attr.aria-label]=\"'nh-assistant.admin.agents.skills.title' | translate\">\n @for (skill of agent.skills; track skill.skillId) {\n <li class=\"skill\" [attr.data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span\n class=\"badge\"\n [class.success]=\"skill.runState === 'active'\"\n [class.warning]=\"skill.runState === 'paused'\"\n [class.danger]=\"skill.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + skill.runState | translate }}</span>\n @if (skill.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(agent.id, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.skills.usage' | translate: { calls: skill.toolCallsToday, tokens: skill.tokensToday } }}</span>\n @if (skill.dailyToolCalls !== null) {\n <span>{{ 'nh-assistant.admin.agents.skills.budget' | translate: { calls: skill.dailyToolCalls, tokens: skill.dailyTokens } }}</span>\n }\n @if (skill.runState === 'paused') {\n <span>{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: skill.waitingInputs } }}</span>\n }\n @if (skill.reason) {\n <span>{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: skill.reason } }}</span>\n }\n </div>\n @if (agent.runState !== 'configured-off') {\n <div class=\"card-actions\">\n @for (action of skillActions(skill); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-label]=\"(stateKey('action', skill.runState, action) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action, skill)\">\n {{ stateKey('action', skill.runState, action) | translate }}\n </button>\n }\n @for (mode of shadowActions(skill.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-label]=\"(shadowActionKey(agent, mode) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode, skill)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n </div>\n }\n </li>\n }\n </ul>\n }\n @if (changingState(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" (submit)=\"$event.preventDefault(); applyState(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ skillStateExplainKey(change) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)) } }}</p>\n } @else {\n <p class=\"muted\">{{ stateKey('explain', change.from, change.state) | translate }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" [class.primary]=\"change.state !== 'stopped'\" [class.danger]=\"change.state === 'stopped'\" [disabled]=\"busyAgentId() !== null\">\n {{ stateKey('confirm', change.from, change.state) | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingState.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingShadow(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-shadow-form (submit)=\"$event.preventDefault(); applyShadow(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, true) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)), mode: (ownShadowModeKey(agent, change.skillId) | translate) } }}</p>\n } @else {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, false) | translate: { mode: (ownShadowModeKey(agent) | translate) } }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-shadow-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-shadow-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-shadow-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-shadow-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.shadow.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingShadow.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingAccount(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-account-form (submit)=\"$event.preventDefault(); applyAccount(agent)\">\n <p class=\"muted\" [attr.title]=\"accountTitle(agent.serviceAccount?.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.explain.' + change.mode | translate: { account: accountName(agent.serviceAccount?.configuredActorId) } }}</p>\n @if (change.mode === 'set') {\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account'\">{{ (accountSearch() ? 'nh-assistant.admin.agents.service-account.input-label-search' : 'nh-assistant.admin.agents.service-account.input-label') | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-' + agent.id + '-account'\"\n [value]=\"accountId()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"accountError() !== null\"\n [describedBy]=\"accountError() ? id + '-' + agent.id + '-account-error' : null\"\n (valueChange)=\"onAccountChange($event)\" />\n @if (accountError(); as failure) {\n <p class=\"field-error\" data-account-error [id]=\"id + '-' + agent.id + '-account-error'\">\n <nh-assistant-icon name=\"warning\" />{{ accountErrorKeys() | nhAssistantTranslate: failure.code }}\n </p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-account-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-account-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-account-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.service-account.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingAccount.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (error(); as failure) {\n @if (errorAgentId() === agent.id) {\n <p class=\"form-error\" role=\"alert\" data-agent-error><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n </li>\n }\n </ul>\n }\n @if (exporting(); as agent) {\n <nh-assistant-agent-package-export-dialog [agents]=\"agents()\" [start]=\"agent\" (closed)=\"exporting.set(null)\" />\n }\n @if (importing()) {\n <nh-assistant-agent-package-import-dialog\n [agents]=\"agents()\"\n [accountSearch]=\"accountSearch()\"\n (imported)=\"onPackageImported()\"\n (closed)=\"importing.set(false)\" />\n }\n @if (runNowAgent(); as runAgent) {\n <nh-assistant-run-now-dialog\n [agent]=\"runAgent\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n [divisions]=\"catalog()?.divisions === true\"\n (openConversation)=\"openConversation($event)\"\n (closed)=\"runningNow.set(null)\" />\n }\n </section>\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAdminAgentEditorComponent, selector: "nh-assistant-admin-agent-editor", inputs: ["agent", "tools", "servers", "catalog", "catalogUnavailable"], outputs: ["saved", "workRequested", "cancelled"] }, { kind: "component", type: NhAssistantAgentEvaluationComponent, selector: "nh-assistant-agent-evaluation", inputs: ["agentId", "variants"] }, { kind: "component", type: NhAssistantAgentFeedbackReportComponent, selector: "nh-assistant-agent-feedback-report", inputs: ["agentId", "itemsPerPage"] }, { kind: "component", type: NhAssistantAgentRunHistoryComponent, selector: "nh-assistant-agent-run-history", inputs: ["agentId", "subjectTypes"], outputs: ["openConversation"] }, { kind: "component", type: NhAssistantAgentRunConfigurationComponent, selector: "nh-assistant-agent-run-configuration", inputs: ["agent", "startSetup", "tools", "servers", "agents"], outputs: ["changed", "editAgent", "changeAccount", "openRuns", "openMcpServers", "openAgent"] }, { kind: "component", type: NhAssistantAccountPickerComponent, selector: "nh-assistant-account-picker", inputs: ["inputId", "value", "searchable", "invalid", "describedBy"], outputs: ["valueChange"] }, { kind: "component", type: _NhAssistantRunNowDialogComponent, selector: "nh-assistant-run-now-dialog", inputs: ["agent", "subjectTypes", "divisions", "subject"], outputs: ["started", "openConversation", "closed"] }, { kind: "component", type: NhAssistantAccountNamesErrorComponent, selector: "nh-assistant-account-names-error", inputs: ["names"] }, { kind: "component", type: NhAssistantAgentHandOffsComponent, selector: "nh-assistant-agent-hand-offs", inputs: ["agent", "agents", "subjectTypes"] }, { kind: "component", type: NhAssistantAgentShadowVariantsComponent, selector: "nh-assistant-agent-shadow-variants", inputs: ["agent"], outputs: ["created", "openVariant"] }, { kind: "component", type: NhAssistantAgentPackageExportDialogComponent, selector: "nh-assistant-agent-package-export-dialog", inputs: ["agents", "start"], outputs: ["closed"] }, { kind: "component", type: NhAssistantAgentPackageImportDialogComponent, selector: "nh-assistant-agent-package-import-dialog", inputs: ["agents", "accountSearch"], outputs: ["imported", "closed"] }, { kind: "component", type: NhAssistantPackageLockComponent, selector: "nh-assistant-package-lock", inputs: ["lock", "agentId", "part", "unlinkable"], outputs: ["unlinked"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7209
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAdminAgentsComponent, isStandalone: true, selector: "nh-assistant-admin-agents", outputs: { openMcpServers: "openMcpServers" }, viewQueries: [{ propertyName: "backButton", first: true, predicate: ["back"], descendants: true, isSignal: true }, { propertyName: "reasonInput", first: true, predicate: ["reasonInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (editing() !== undefined) {\n <nh-assistant-admin-agent-editor\n [agent]=\"editing() ?? null\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [catalog]=\"catalog()\"\n [catalogUnavailable]=\"catalogError() !== null\"\n (saved)=\"onEditorSaved($event)\"\n (workRequested)=\"onWorkRequested($event)\"\n (cancelled)=\"onEditorCancelled()\" />\n} @else if (reporting(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeReport()\">\n {{ 'nh-assistant.admin.feedback.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-feedback-report [agentId]=\"agent.id\" />\n </div>\n} @else if (configuring(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRunConfiguration()\">\n {{ 'nh-assistant.admin.run-config.back' | translate }}\n </button>\n </div>\n <nh-assistant-agent-run-configuration\n [agent]=\"agent\"\n [startSetup]=\"setupOnOpen()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [agents]=\"agents()\"\n (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\"\n (openAgent)=\"askerFromRunConfiguration(agent, $event)\" />\n <nh-assistant-agent-hand-offs [agent]=\"agent\" [agents]=\"agents()\" [subjectTypes]=\"catalog()?.subjectTypes ?? []\" />\n <nh-assistant-agent-shadow-variants\n [agent]=\"agent\"\n (created)=\"onVariantCreated($event)\"\n (promoted)=\"onVariantPromoted($event)\"\n (openVariant)=\"variantFromRunConfiguration($event)\" />\n </div>\n} @else if (viewingRuns(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRuns()\">\n {{ (returnTo() === agent.id ? 'nh-assistant.admin.runs.back-to-run-config' : 'nh-assistant.admin.runs.back') | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-run-history\n [agentId]=\"agent.id\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n (openConversation)=\"openConversation($event)\" />\n </div>\n} @else if (evaluating(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeEvaluation()\">\n {{ 'nh-assistant.admin.evaluation.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-evaluation [agentId]=\"agent.id\" [variants]=\"variantsOf(agent)\" />\n </div>\n} @else {\n <section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.agents.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.description' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" aria-haspopup=\"dialog\" data-import-package [disabled]=\"loading() || loadFailed()\" (click)=\"importPackage()\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.import' | translate }}\n </button>\n <button class=\"primary\" type=\"button\" [disabled]=\"loading() || loadFailed()\" (click)=\"create()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agents.new' | translate }}\n </button>\n </div>\n </header>\n\n @if (error(); as failure) {\n @if (errorAgentId() === null) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n @if (!loading() && !loadFailed()) {\n @if (catalogError(); as failure) {\n <!-- Without the run catalog nothing that depends on it is offered: run now, what agents work on, groups. -->\n <div class=\"message warning catalog-error\" role=\"alert\" data-catalog-error>\n <nh-assistant-icon name=\"warning\" />\n <span class=\"grow\">\n {{ 'nh-assistant.admin.agents.catalog-failed' | translate }}\n {{ catalogErrorKeys() | nhAssistantTranslate: failure.code }}\n </span>\n <button class=\"secondary\" type=\"button\" data-catalog-retry [disabled]=\"catalogLoading()\" (click)=\"retryCatalog()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n }\n <nh-assistant-account-names-error [names]=\"accountNameLookup\" />\n }\n\n @if (loading()) {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n } @else if (loadFailed()) {\n <div class=\"state\" role=\"alert\">\n <p>{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">{{ 'nh-assistant.admin.retry' | translate }}</button>\n </div>\n } @else if (agents().length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.agents.empty' | translate }}</p>\n } @else {\n <ul class=\"cards\">\n @for (agent of agents(); track agent.id) {\n <li class=\"card\" [class.inactive]=\"agent.runState !== 'active'\" [attr.aria-busy]=\"busyAgentId() === agent.id\">\n <div class=\"card-header\">\n <!-- An agent in code names and describes itself with translation keys. -->\n <strong>{{ (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }}</strong>\n <span class=\"mono muted\">{{ agent.id }}</span>\n <span class=\"badge\">{{ (agent.source === 'code' ? 'nh-assistant.admin.agents.source-code' : 'nh-assistant.admin.agents.source-admin') | translate }}</span>\n @if (agent.isOverridden) {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.agents.overridden' | translate }}</span>\n }\n <span\n class=\"badge\"\n [class.success]=\"agent.runState === 'active'\"\n [class.warning]=\"agent.runState === 'paused'\"\n [class.danger]=\"agent.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + agent.runState | translate }}</span>\n @if (agent.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n @if (agent.offeredInChat === false) {\n <span class=\"badge\" data-hidden-from-chat>{{ 'nh-assistant.admin.agents.chat.hidden' | translate }}</span>\n }\n @if (agent.package; as linked) {\n <span class=\"badge\" data-package-badge><nh-assistant-icon name=\"lock\" />{{ 'nh-assistant.admin.packages.linked-badge' | translate: { package: linked.packageId, version: linked.packageVersion } }}</span>\n }\n </div>\n <!-- The package the agent comes from; unlinking makes every part of it local. -->\n <nh-assistant-package-lock [lock]=\"agentPackageOf(agent)\" [agentId]=\"agent.id\" [part]=\"null\" (unlinked)=\"onPackageUnlinked()\" />\n @if (agent.description) {\n <p class=\"muted\">{{ codeTextKeys(agent.source, agent.description) | nhAssistantTranslate: agent.description }}</p>\n }\n <!-- A warning never refused the save: the agent is in effect but may not work as configured. -->\n @for (warning of agent.warnings ?? []; track warning) {\n <p class=\"message warning\" [attr.data-agent-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n <!-- The asset its instructions come from no longer resolves: the agent starts no model turn. -->\n @if (agent.instructionsProblem) {\n <p class=\"message error\" role=\"status\" data-agent-instructions-problem>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.instruction-assets.agent-problem' | translate }}\n {{ 'nh-assistant.admin.instruction-assets.problems.' + agent.instructionsProblem | translate }}\n </p>\n }\n @if (agent.runState === 'configured-off') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.configured-off-hint' | translate }}</p>\n } @else if (agent.runState !== 'active') {\n <p class=\"muted\">\n @if (agent.stateChangedAt) {\n <span [attr.title]=\"accountTitle(agent.stateChangedBy)\">{{ 'nh-assistant.admin.agents.state.changed' | translate: { user: accountName(agent.stateChangedBy), date: (agent.stateChangedAt | date: 'medium') } }}</span>\n }\n @if (agent.stateReason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: agent.stateReason } }}\n }\n </p>\n @if (agent.runState === 'paused') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: agent.waitingInputs } }}</p>\n }\n <!-- What releasing the kill switch does: an agent that was off goes back off. Older servers do not say. -->\n @if (agent.runState === 'stopped' && agent.offBeforeStop !== undefined) {\n <p class=\"muted\" data-stopped-hint [attr.data-off-before-stop]=\"agent.offBeforeStop\">\n {{ (agent.offBeforeStop ? 'nh-assistant.admin.agents.state.stopped-was-off-hint' : 'nh-assistant.admin.agents.state.stopped-was-on-hint') | translate }}\n </p>\n }\n @if (agent.runState === 'off') {\n <p class=\"muted\" data-off-hint>\n {{ 'nh-assistant.admin.agents.state.off-hint' | translate }}\n @if (!agent.stateChangedAt) {\n {{ 'nh-assistant.admin.agents.state.starts-off' | translate }}\n }\n </p>\n }\n }\n @if (agent.shadow; as shadow) {\n @if (shadow.shadow) {\n <p class=\"muted\">\n {{ (shadow.locked ? 'nh-assistant.admin.agents.shadow.locked' : 'nh-assistant.admin.agents.shadow.hint') | translate }}\n @if (shadow.changedAt && shadow.override !== null) {\n <span [attr.title]=\"accountTitle(shadow.changedBy)\">{{ 'nh-assistant.admin.agents.shadow.changed' | translate: { user: accountName(shadow.changedBy), date: (shadow.changedAt | date: 'medium') } }}</span>\n }\n @if (shadow.reason && shadow.override !== null) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: shadow.reason } }}\n }\n </p>\n }\n }\n @if (agent.serviceAccount; as account) {\n <p class=\"muted\" data-service-account>\n <span [attr.title]=\"accountTitle(account.actorId)\">{{ 'nh-assistant.admin.agents.service-account.label' | translate: { account: accountName(account.actorId) } }}</span>\n @if (account.overridden) {\n <span [attr.title]=\"accountTitle(account.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.configured' | translate: { account: accountName(account.configuredActorId) } }}</span>\n @if (account.reason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: account.reason } }}\n }\n }\n </p>\n }\n @if (worksOn(agent); as works) {\n <!-- What the agent works on; an agent in code shows its code setting. -->\n <p class=\"muted\" data-works-on>\n <span>{{ 'nh-assistant.admin.agents.works-on.label' | translate }}</span>\n <strong>\n @switch (works.only) {\n @case ('all') { {{ 'nh-assistant.admin.agents.works-on.all' | translate }} }\n @case ('types') { {{ works.types.join(', ') }} }\n @default { {{ 'nh-assistant.admin.agents.works-on.application' | translate }} }\n }\n </strong>\n @if (works.application && works.only !== 'application') {\n <span>{{ 'nh-assistant.admin.agents.works-on.and-application' | translate }}</span>\n }\n @if (works.perDivision) {\n <span>{{ 'nh-assistant.admin.agents.works-on.per-division' | translate }}</span>\n }\n @if (works.undeclared) {\n <span>{{ 'nh-assistant.admin.agents.works-on.undeclared' | translate }}</span>\n }\n </p>\n @if (works.all && works.known.length > 0) {\n <p class=\"muted\" data-known-types>{{ 'nh-assistant.admin.agents.works-on.known' | translate: { types: works.known.join(', ') } }}</p>\n }\n @if (works.runPolicy || works.viewPolicy) {\n <!-- Each policy is an item of its own, wrapping on narrow screens. -->\n <div class=\"meta\" data-works-on-policies>\n @if (works.runPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.run-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n @if (works.viewPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.view-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n </div>\n }\n }\n @if (groupNames(agent); as names) {\n <p class=\"muted\" data-agent-groups>{{ 'nh-assistant.admin.agents.groups' | translate: { groups: names } }}</p>\n }\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.autonomy.' + agent.autonomy | translate }}</span>\n <span>{{ (agent.toolSelectors.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: agent.toolSelectors.length } }}</span>\n <span>{{ (agent.mcpServerIds.length === 1 ? 'nh-assistant.admin.agents.server-count-one' : 'nh-assistant.admin.agents.server-count') | translate: { count: agent.mcpServerIds.length } }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: agent.version } }}</span>\n @if (agent.requiredPolicy; as policy) {\n <!-- The application may name its policies; otherwise the policy shows as it is called in code. -->\n <span data-required-policy>\n {{ 'nh-assistant.admin.agents.required-policy' | translate }}\n @if (policyKeys(policy) | nhAssistantTranslate; as text) {\n {{ text }}\n } @else {\n <code class=\"mono\">{{ policy }}</code>\n }\n </span>\n }\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"edit(agent)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n @for (action of stateActions(agent); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action)\">\n {{ stateKey('action', agent.runState, action) | translate }}\n </button>\n }\n @if (agent.runState !== 'configured-off') {\n @for (mode of shadowActions(agent.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n }\n @if (agent.serviceAccount; as account) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"set\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'set')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'set')\">\n {{ 'nh-assistant.admin.agents.service-account.action.set' | translate }}\n </button>\n @if (account.overridden) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"code\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'code')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'code')\">\n {{ 'nh-assistant.admin.agents.service-account.action.code' | translate }}\n </button>\n }\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-run-config-agent]=\"agent.id\" (click)=\"openRunConfiguration(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.run-config' | translate }}\n </button>\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-runs-agent]=\"agent.id\" (click)=\"openRuns(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.runs' | translate }}\n </button>\n }\n @if (canRunNow(agent)) {\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-run-now-agent]=\"agent.id\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"runNow(agent)\">\n <nh-assistant-icon name=\"send\" />{{ 'nh-assistant.admin.agents.run-now' | translate }}\n </button>\n }\n <button class=\"secondary\" type=\"button\" [attr.data-feedback-agent]=\"agent.id\" (click)=\"openReport(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.feedback' | translate }}\n </button>\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-export-package]=\"agent.id\"\n [attr.aria-label]=\"'nh-assistant.admin.packages.export-named' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"exportPackage(agent)\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.export' | translate }}\n </button>\n @if (variantsOf(agent).length > 0) {\n <button class=\"secondary\" type=\"button\" [attr.data-evaluation-agent]=\"agent.id\" (click)=\"openEvaluation(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.evaluation' | translate }}\n </button>\n }\n @if (agent.source === 'code' && agent.isOverridden) {\n @if (isConfirming(agent.id, 'reset')) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.reset-keeps-state' | translate }}</span>\n <button class=\"danger\" type=\"button\" (click)=\"reset(agent)\">{{ 'nh-assistant.admin.agents.confirm-reset' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"secondary\"\n type=\"button\"\n data-reset-agent\n [attr.aria-describedby]=\"resetLocked(agent) ? id + '-' + agent.id + '-reset-locked' : null\"\n [disabled]=\"busyAgentId() !== null || resetLocked(agent)\"\n (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\n @if (resetLocked(agent)) {\n <span class=\"muted\" data-reset-locked [id]=\"id + '-' + agent.id + '-reset-locked'\">{{ 'nh-assistant.admin.packages.reset-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n @if (agent.source === 'admin') {\n @if (isConfirming(agent.id, 'delete')) {\n <button class=\"danger\" type=\"button\" (click)=\"remove(agent)\">{{ 'nh-assistant.admin.confirm-delete' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"danger\"\n type=\"button\"\n data-delete-agent\n [attr.aria-describedby]=\"deleteLocked(agent) ? id + '-' + agent.id + '-delete-locked' : null\"\n [disabled]=\"busyAgentId() !== null || deleteLocked(agent)\"\n (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n @if (deleteLocked(agent)) {\n <span class=\"muted\" data-delete-locked [id]=\"id + '-' + agent.id + '-delete-locked'\">{{ 'nh-assistant.admin.packages.delete-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n </div>\n @if (agent.skills?.length) {\n <ul class=\"skills\" [attr.aria-label]=\"'nh-assistant.admin.agents.skills.title' | translate\">\n @for (skill of agent.skills; track skill.skillId) {\n <li class=\"skill\" [attr.data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span\n class=\"badge\"\n [class.success]=\"skill.runState === 'active'\"\n [class.warning]=\"skill.runState === 'paused'\"\n [class.danger]=\"skill.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + skill.runState | translate }}</span>\n @if (skill.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(agent.id, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.skills.usage' | translate: { calls: skill.toolCallsToday, tokens: skill.tokensToday } }}</span>\n @if (skill.dailyToolCalls !== null) {\n <span>{{ 'nh-assistant.admin.agents.skills.budget' | translate: { calls: skill.dailyToolCalls, tokens: skill.dailyTokens } }}</span>\n }\n @if (skill.runState === 'paused') {\n <span>{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: skill.waitingInputs } }}</span>\n }\n @if (skill.reason) {\n <span>{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: skill.reason } }}</span>\n }\n </div>\n @if (agent.runState !== 'configured-off') {\n <div class=\"card-actions\">\n @for (action of skillActions(skill); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-label]=\"(stateKey('action', skill.runState, action) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action, skill)\">\n {{ stateKey('action', skill.runState, action) | translate }}\n </button>\n }\n @for (mode of shadowActions(skill.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-label]=\"(shadowActionKey(agent, mode) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode, skill)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n </div>\n }\n </li>\n }\n </ul>\n }\n @if (changingState(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" (submit)=\"$event.preventDefault(); applyState(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ skillStateExplainKey(change) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)) } }}</p>\n } @else {\n <p class=\"muted\">{{ stateKey('explain', change.from, change.state) | translate }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" [class.primary]=\"change.state !== 'stopped'\" [class.danger]=\"change.state === 'stopped'\" [disabled]=\"busyAgentId() !== null\">\n {{ stateKey('confirm', change.from, change.state) | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingState.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingShadow(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-shadow-form (submit)=\"$event.preventDefault(); applyShadow(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, true) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)), mode: (ownShadowModeKey(agent, change.skillId) | translate) } }}</p>\n } @else {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, false) | translate: { mode: (ownShadowModeKey(agent) | translate) } }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-shadow-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-shadow-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-shadow-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-shadow-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.shadow.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingShadow.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingAccount(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-account-form (submit)=\"$event.preventDefault(); applyAccount(agent)\">\n <p class=\"muted\" [attr.title]=\"accountTitle(agent.serviceAccount?.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.explain.' + change.mode | translate: { account: accountName(agent.serviceAccount?.configuredActorId) } }}</p>\n @if (change.mode === 'set') {\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account'\">{{ (accountSearch() ? 'nh-assistant.admin.agents.service-account.input-label-search' : 'nh-assistant.admin.agents.service-account.input-label') | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-' + agent.id + '-account'\"\n [value]=\"accountId()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"accountError() !== null\"\n [describedBy]=\"accountError() ? id + '-' + agent.id + '-account-error' : null\"\n (valueChange)=\"onAccountChange($event)\" />\n @if (accountError(); as failure) {\n <p class=\"field-error\" data-account-error [id]=\"id + '-' + agent.id + '-account-error'\">\n <nh-assistant-icon name=\"warning\" />{{ accountErrorKeys() | nhAssistantTranslate: failure.code }}\n </p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-account-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-account-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-account-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.service-account.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingAccount.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (error(); as failure) {\n @if (errorAgentId() === agent.id) {\n <p class=\"form-error\" role=\"alert\" data-agent-error><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n </li>\n }\n </ul>\n }\n @if (exporting(); as agent) {\n <nh-assistant-agent-package-export-dialog [agents]=\"agents()\" [start]=\"agent\" (closed)=\"exporting.set(null)\" />\n }\n @if (importing()) {\n <nh-assistant-agent-package-import-dialog\n [agents]=\"agents()\"\n [accountSearch]=\"accountSearch()\"\n (imported)=\"onPackageImported()\"\n (closed)=\"importing.set(false)\" />\n }\n @if (runNowAgent(); as runAgent) {\n <nh-assistant-run-now-dialog\n [agent]=\"runAgent\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n [divisions]=\"catalog()?.divisions === true\"\n (openConversation)=\"openConversation($event)\"\n (closed)=\"runningNow.set(null)\" />\n }\n </section>\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAdminAgentEditorComponent, selector: "nh-assistant-admin-agent-editor", inputs: ["agent", "tools", "servers", "catalog", "catalogUnavailable"], outputs: ["saved", "workRequested", "cancelled"] }, { kind: "component", type: NhAssistantAgentEvaluationComponent, selector: "nh-assistant-agent-evaluation", inputs: ["agentId", "variants"] }, { kind: "component", type: NhAssistantAgentFeedbackReportComponent, selector: "nh-assistant-agent-feedback-report", inputs: ["agentId", "itemsPerPage"] }, { kind: "component", type: NhAssistantAgentRunHistoryComponent, selector: "nh-assistant-agent-run-history", inputs: ["agentId", "subjectTypes"], outputs: ["openConversation"] }, { kind: "component", type: NhAssistantAgentRunConfigurationComponent, selector: "nh-assistant-agent-run-configuration", inputs: ["agent", "startSetup", "tools", "servers", "agents"], outputs: ["changed", "editAgent", "changeAccount", "openRuns", "openMcpServers", "openAgent"] }, { kind: "component", type: NhAssistantAccountPickerComponent, selector: "nh-assistant-account-picker", inputs: ["inputId", "value", "searchable", "invalid", "describedBy"], outputs: ["valueChange"] }, { kind: "component", type: _NhAssistantRunNowDialogComponent, selector: "nh-assistant-run-now-dialog", inputs: ["agent", "subjectTypes", "divisions", "subject"], outputs: ["started", "openConversation", "closed"] }, { kind: "component", type: NhAssistantAccountNamesErrorComponent, selector: "nh-assistant-account-names-error", inputs: ["names"] }, { kind: "component", type: NhAssistantAgentHandOffsComponent, selector: "nh-assistant-agent-hand-offs", inputs: ["agent", "agents", "subjectTypes"] }, { kind: "component", type: NhAssistantAgentShadowVariantsComponent, selector: "nh-assistant-agent-shadow-variants", inputs: ["agent"], outputs: ["created", "openVariant", "promoted"] }, { kind: "component", type: NhAssistantAgentPackageExportDialogComponent, selector: "nh-assistant-agent-package-export-dialog", inputs: ["agents", "start"], outputs: ["closed"] }, { kind: "component", type: NhAssistantAgentPackageImportDialogComponent, selector: "nh-assistant-agent-package-import-dialog", inputs: ["agents", "accountSearch"], outputs: ["imported", "closed"] }, { kind: "component", type: NhAssistantPackageLockComponent, selector: "nh-assistant-package-lock", inputs: ["lock", "agentId", "part", "unlinkable"], outputs: ["unlinked"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7117
7210
|
}
|
|
7118
7211
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentsComponent, decorators: [{
|
|
7119
7212
|
type: Component,
|
|
@@ -7135,7 +7228,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
7135
7228
|
NhAssistantAgentPackageExportDialogComponent,
|
|
7136
7229
|
NhAssistantAgentPackageImportDialogComponent,
|
|
7137
7230
|
NhAssistantPackageLockComponent
|
|
7138
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (editing() !== undefined) {\n <nh-assistant-admin-agent-editor\n [agent]=\"editing() ?? null\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [catalog]=\"catalog()\"\n [catalogUnavailable]=\"catalogError() !== null\"\n (saved)=\"onEditorSaved($event)\"\n (workRequested)=\"onWorkRequested($event)\"\n (cancelled)=\"onEditorCancelled()\" />\n} @else if (reporting(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeReport()\">\n {{ 'nh-assistant.admin.feedback.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-feedback-report [agentId]=\"agent.id\" />\n </div>\n} @else if (configuring(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRunConfiguration()\">\n {{ 'nh-assistant.admin.run-config.back' | translate }}\n </button>\n </div>\n <nh-assistant-agent-run-configuration\n [agent]=\"agent\"\n [startSetup]=\"setupOnOpen()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [agents]=\"agents()\"\n (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\"\n (openAgent)=\"askerFromRunConfiguration(agent, $event)\" />\n <nh-assistant-agent-hand-offs [agent]=\"agent\" [agents]=\"agents()\" [subjectTypes]=\"catalog()?.subjectTypes ?? []\" />\n <nh-assistant-agent-shadow-variants\n [agent]=\"agent\"\n (created)=\"onVariantCreated($event)\"\n (openVariant)=\"variantFromRunConfiguration($event)\" />\n </div>\n} @else if (viewingRuns(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRuns()\">\n {{ (returnTo() === agent.id ? 'nh-assistant.admin.runs.back-to-run-config' : 'nh-assistant.admin.runs.back') | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-run-history\n [agentId]=\"agent.id\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n (openConversation)=\"openConversation($event)\" />\n </div>\n} @else if (evaluating(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeEvaluation()\">\n {{ 'nh-assistant.admin.evaluation.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-evaluation [agentId]=\"agent.id\" [variants]=\"variantsOf(agent)\" />\n </div>\n} @else {\n <section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.agents.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.description' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" aria-haspopup=\"dialog\" data-import-package [disabled]=\"loading() || loadFailed()\" (click)=\"importPackage()\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.import' | translate }}\n </button>\n <button class=\"primary\" type=\"button\" [disabled]=\"loading() || loadFailed()\" (click)=\"create()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agents.new' | translate }}\n </button>\n </div>\n </header>\n\n @if (error(); as failure) {\n @if (errorAgentId() === null) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n @if (!loading() && !loadFailed()) {\n @if (catalogError(); as failure) {\n <!-- Without the run catalog nothing that depends on it is offered: run now, what agents work on, groups. -->\n <div class=\"message warning catalog-error\" role=\"alert\" data-catalog-error>\n <nh-assistant-icon name=\"warning\" />\n <span class=\"grow\">\n {{ 'nh-assistant.admin.agents.catalog-failed' | translate }}\n {{ catalogErrorKeys() | nhAssistantTranslate: failure.code }}\n </span>\n <button class=\"secondary\" type=\"button\" data-catalog-retry [disabled]=\"catalogLoading()\" (click)=\"retryCatalog()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n }\n <nh-assistant-account-names-error [names]=\"accountNameLookup\" />\n }\n\n @if (loading()) {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n } @else if (loadFailed()) {\n <div class=\"state\" role=\"alert\">\n <p>{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">{{ 'nh-assistant.admin.retry' | translate }}</button>\n </div>\n } @else if (agents().length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.agents.empty' | translate }}</p>\n } @else {\n <ul class=\"cards\">\n @for (agent of agents(); track agent.id) {\n <li class=\"card\" [class.inactive]=\"agent.runState !== 'active'\" [attr.aria-busy]=\"busyAgentId() === agent.id\">\n <div class=\"card-header\">\n <!-- An agent in code names and describes itself with translation keys. -->\n <strong>{{ (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }}</strong>\n <span class=\"mono muted\">{{ agent.id }}</span>\n <span class=\"badge\">{{ (agent.source === 'code' ? 'nh-assistant.admin.agents.source-code' : 'nh-assistant.admin.agents.source-admin') | translate }}</span>\n @if (agent.isOverridden) {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.agents.overridden' | translate }}</span>\n }\n <span\n class=\"badge\"\n [class.success]=\"agent.runState === 'active'\"\n [class.warning]=\"agent.runState === 'paused'\"\n [class.danger]=\"agent.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + agent.runState | translate }}</span>\n @if (agent.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n @if (agent.offeredInChat === false) {\n <span class=\"badge\" data-hidden-from-chat>{{ 'nh-assistant.admin.agents.chat.hidden' | translate }}</span>\n }\n @if (agent.package; as linked) {\n <span class=\"badge\" data-package-badge><nh-assistant-icon name=\"lock\" />{{ 'nh-assistant.admin.packages.linked-badge' | translate: { package: linked.packageId, version: linked.packageVersion } }}</span>\n }\n </div>\n <!-- The package the agent comes from; unlinking makes every part of it local. -->\n <nh-assistant-package-lock [lock]=\"agentPackageOf(agent)\" [agentId]=\"agent.id\" [part]=\"null\" (unlinked)=\"onPackageUnlinked()\" />\n @if (agent.description) {\n <p class=\"muted\">{{ codeTextKeys(agent.source, agent.description) | nhAssistantTranslate: agent.description }}</p>\n }\n <!-- A warning never refused the save: the agent is in effect but may not work as configured. -->\n @for (warning of agent.warnings ?? []; track warning) {\n <p class=\"message warning\" [attr.data-agent-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n <!-- The asset its instructions come from no longer resolves: the agent starts no model turn. -->\n @if (agent.instructionsProblem) {\n <p class=\"message error\" role=\"status\" data-agent-instructions-problem>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.instruction-assets.agent-problem' | translate }}\n {{ 'nh-assistant.admin.instruction-assets.problems.' + agent.instructionsProblem | translate }}\n </p>\n }\n @if (agent.runState === 'configured-off') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.configured-off-hint' | translate }}</p>\n } @else if (agent.runState !== 'active') {\n <p class=\"muted\">\n @if (agent.stateChangedAt) {\n <span [attr.title]=\"accountTitle(agent.stateChangedBy)\">{{ 'nh-assistant.admin.agents.state.changed' | translate: { user: accountName(agent.stateChangedBy), date: (agent.stateChangedAt | date: 'medium') } }}</span>\n }\n @if (agent.stateReason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: agent.stateReason } }}\n }\n </p>\n @if (agent.runState === 'paused') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: agent.waitingInputs } }}</p>\n }\n <!-- What releasing the kill switch does: an agent that was off goes back off. Older servers do not say. -->\n @if (agent.runState === 'stopped' && agent.offBeforeStop !== undefined) {\n <p class=\"muted\" data-stopped-hint [attr.data-off-before-stop]=\"agent.offBeforeStop\">\n {{ (agent.offBeforeStop ? 'nh-assistant.admin.agents.state.stopped-was-off-hint' : 'nh-assistant.admin.agents.state.stopped-was-on-hint') | translate }}\n </p>\n }\n @if (agent.runState === 'off') {\n <p class=\"muted\" data-off-hint>\n {{ 'nh-assistant.admin.agents.state.off-hint' | translate }}\n @if (!agent.stateChangedAt) {\n {{ 'nh-assistant.admin.agents.state.starts-off' | translate }}\n }\n </p>\n }\n }\n @if (agent.shadow; as shadow) {\n @if (shadow.shadow) {\n <p class=\"muted\">\n {{ (shadow.locked ? 'nh-assistant.admin.agents.shadow.locked' : 'nh-assistant.admin.agents.shadow.hint') | translate }}\n @if (shadow.changedAt && shadow.override !== null) {\n <span [attr.title]=\"accountTitle(shadow.changedBy)\">{{ 'nh-assistant.admin.agents.shadow.changed' | translate: { user: accountName(shadow.changedBy), date: (shadow.changedAt | date: 'medium') } }}</span>\n }\n @if (shadow.reason && shadow.override !== null) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: shadow.reason } }}\n }\n </p>\n }\n }\n @if (agent.serviceAccount; as account) {\n <p class=\"muted\" data-service-account>\n <span [attr.title]=\"accountTitle(account.actorId)\">{{ 'nh-assistant.admin.agents.service-account.label' | translate: { account: accountName(account.actorId) } }}</span>\n @if (account.overridden) {\n <span [attr.title]=\"accountTitle(account.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.configured' | translate: { account: accountName(account.configuredActorId) } }}</span>\n @if (account.reason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: account.reason } }}\n }\n }\n </p>\n }\n @if (worksOn(agent); as works) {\n <!-- What the agent works on; an agent in code shows its code setting. -->\n <p class=\"muted\" data-works-on>\n <span>{{ 'nh-assistant.admin.agents.works-on.label' | translate }}</span>\n <strong>\n @switch (works.only) {\n @case ('all') { {{ 'nh-assistant.admin.agents.works-on.all' | translate }} }\n @case ('types') { {{ works.types.join(', ') }} }\n @default { {{ 'nh-assistant.admin.agents.works-on.application' | translate }} }\n }\n </strong>\n @if (works.application && works.only !== 'application') {\n <span>{{ 'nh-assistant.admin.agents.works-on.and-application' | translate }}</span>\n }\n @if (works.perDivision) {\n <span>{{ 'nh-assistant.admin.agents.works-on.per-division' | translate }}</span>\n }\n @if (works.undeclared) {\n <span>{{ 'nh-assistant.admin.agents.works-on.undeclared' | translate }}</span>\n }\n </p>\n @if (works.all && works.known.length > 0) {\n <p class=\"muted\" data-known-types>{{ 'nh-assistant.admin.agents.works-on.known' | translate: { types: works.known.join(', ') } }}</p>\n }\n @if (works.runPolicy || works.viewPolicy) {\n <!-- Each policy is an item of its own, wrapping on narrow screens. -->\n <div class=\"meta\" data-works-on-policies>\n @if (works.runPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.run-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n @if (works.viewPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.view-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n </div>\n }\n }\n @if (groupNames(agent); as names) {\n <p class=\"muted\" data-agent-groups>{{ 'nh-assistant.admin.agents.groups' | translate: { groups: names } }}</p>\n }\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.autonomy.' + agent.autonomy | translate }}</span>\n <span>{{ (agent.toolSelectors.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: agent.toolSelectors.length } }}</span>\n <span>{{ (agent.mcpServerIds.length === 1 ? 'nh-assistant.admin.agents.server-count-one' : 'nh-assistant.admin.agents.server-count') | translate: { count: agent.mcpServerIds.length } }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: agent.version } }}</span>\n @if (agent.requiredPolicy; as policy) {\n <!-- The application may name its policies; otherwise the policy shows as it is called in code. -->\n <span data-required-policy>\n {{ 'nh-assistant.admin.agents.required-policy' | translate }}\n @if (policyKeys(policy) | nhAssistantTranslate; as text) {\n {{ text }}\n } @else {\n <code class=\"mono\">{{ policy }}</code>\n }\n </span>\n }\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"edit(agent)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n @for (action of stateActions(agent); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action)\">\n {{ stateKey('action', agent.runState, action) | translate }}\n </button>\n }\n @if (agent.runState !== 'configured-off') {\n @for (mode of shadowActions(agent.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n }\n @if (agent.serviceAccount; as account) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"set\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'set')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'set')\">\n {{ 'nh-assistant.admin.agents.service-account.action.set' | translate }}\n </button>\n @if (account.overridden) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"code\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'code')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'code')\">\n {{ 'nh-assistant.admin.agents.service-account.action.code' | translate }}\n </button>\n }\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-run-config-agent]=\"agent.id\" (click)=\"openRunConfiguration(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.run-config' | translate }}\n </button>\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-runs-agent]=\"agent.id\" (click)=\"openRuns(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.runs' | translate }}\n </button>\n }\n @if (canRunNow(agent)) {\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-run-now-agent]=\"agent.id\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"runNow(agent)\">\n <nh-assistant-icon name=\"send\" />{{ 'nh-assistant.admin.agents.run-now' | translate }}\n </button>\n }\n <button class=\"secondary\" type=\"button\" [attr.data-feedback-agent]=\"agent.id\" (click)=\"openReport(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.feedback' | translate }}\n </button>\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-export-package]=\"agent.id\"\n [attr.aria-label]=\"'nh-assistant.admin.packages.export-named' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"exportPackage(agent)\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.export' | translate }}\n </button>\n @if (variantsOf(agent).length > 0) {\n <button class=\"secondary\" type=\"button\" [attr.data-evaluation-agent]=\"agent.id\" (click)=\"openEvaluation(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.evaluation' | translate }}\n </button>\n }\n @if (agent.source === 'code' && agent.isOverridden) {\n @if (isConfirming(agent.id, 'reset')) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.reset-keeps-state' | translate }}</span>\n <button class=\"danger\" type=\"button\" (click)=\"reset(agent)\">{{ 'nh-assistant.admin.agents.confirm-reset' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"secondary\"\n type=\"button\"\n data-reset-agent\n [attr.aria-describedby]=\"resetLocked(agent) ? id + '-' + agent.id + '-reset-locked' : null\"\n [disabled]=\"busyAgentId() !== null || resetLocked(agent)\"\n (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\n @if (resetLocked(agent)) {\n <span class=\"muted\" data-reset-locked [id]=\"id + '-' + agent.id + '-reset-locked'\">{{ 'nh-assistant.admin.packages.reset-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n @if (agent.source === 'admin') {\n @if (isConfirming(agent.id, 'delete')) {\n <button class=\"danger\" type=\"button\" (click)=\"remove(agent)\">{{ 'nh-assistant.admin.confirm-delete' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"danger\"\n type=\"button\"\n data-delete-agent\n [attr.aria-describedby]=\"deleteLocked(agent) ? id + '-' + agent.id + '-delete-locked' : null\"\n [disabled]=\"busyAgentId() !== null || deleteLocked(agent)\"\n (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n @if (deleteLocked(agent)) {\n <span class=\"muted\" data-delete-locked [id]=\"id + '-' + agent.id + '-delete-locked'\">{{ 'nh-assistant.admin.packages.delete-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n </div>\n @if (agent.skills?.length) {\n <ul class=\"skills\" [attr.aria-label]=\"'nh-assistant.admin.agents.skills.title' | translate\">\n @for (skill of agent.skills; track skill.skillId) {\n <li class=\"skill\" [attr.data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span\n class=\"badge\"\n [class.success]=\"skill.runState === 'active'\"\n [class.warning]=\"skill.runState === 'paused'\"\n [class.danger]=\"skill.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + skill.runState | translate }}</span>\n @if (skill.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(agent.id, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.skills.usage' | translate: { calls: skill.toolCallsToday, tokens: skill.tokensToday } }}</span>\n @if (skill.dailyToolCalls !== null) {\n <span>{{ 'nh-assistant.admin.agents.skills.budget' | translate: { calls: skill.dailyToolCalls, tokens: skill.dailyTokens } }}</span>\n }\n @if (skill.runState === 'paused') {\n <span>{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: skill.waitingInputs } }}</span>\n }\n @if (skill.reason) {\n <span>{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: skill.reason } }}</span>\n }\n </div>\n @if (agent.runState !== 'configured-off') {\n <div class=\"card-actions\">\n @for (action of skillActions(skill); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-label]=\"(stateKey('action', skill.runState, action) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action, skill)\">\n {{ stateKey('action', skill.runState, action) | translate }}\n </button>\n }\n @for (mode of shadowActions(skill.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-label]=\"(shadowActionKey(agent, mode) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode, skill)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n </div>\n }\n </li>\n }\n </ul>\n }\n @if (changingState(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" (submit)=\"$event.preventDefault(); applyState(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ skillStateExplainKey(change) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)) } }}</p>\n } @else {\n <p class=\"muted\">{{ stateKey('explain', change.from, change.state) | translate }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" [class.primary]=\"change.state !== 'stopped'\" [class.danger]=\"change.state === 'stopped'\" [disabled]=\"busyAgentId() !== null\">\n {{ stateKey('confirm', change.from, change.state) | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingState.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingShadow(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-shadow-form (submit)=\"$event.preventDefault(); applyShadow(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, true) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)), mode: (ownShadowModeKey(agent, change.skillId) | translate) } }}</p>\n } @else {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, false) | translate: { mode: (ownShadowModeKey(agent) | translate) } }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-shadow-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-shadow-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-shadow-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-shadow-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.shadow.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingShadow.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingAccount(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-account-form (submit)=\"$event.preventDefault(); applyAccount(agent)\">\n <p class=\"muted\" [attr.title]=\"accountTitle(agent.serviceAccount?.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.explain.' + change.mode | translate: { account: accountName(agent.serviceAccount?.configuredActorId) } }}</p>\n @if (change.mode === 'set') {\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account'\">{{ (accountSearch() ? 'nh-assistant.admin.agents.service-account.input-label-search' : 'nh-assistant.admin.agents.service-account.input-label') | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-' + agent.id + '-account'\"\n [value]=\"accountId()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"accountError() !== null\"\n [describedBy]=\"accountError() ? id + '-' + agent.id + '-account-error' : null\"\n (valueChange)=\"onAccountChange($event)\" />\n @if (accountError(); as failure) {\n <p class=\"field-error\" data-account-error [id]=\"id + '-' + agent.id + '-account-error'\">\n <nh-assistant-icon name=\"warning\" />{{ accountErrorKeys() | nhAssistantTranslate: failure.code }}\n </p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-account-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-account-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-account-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.service-account.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingAccount.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (error(); as failure) {\n @if (errorAgentId() === agent.id) {\n <p class=\"form-error\" role=\"alert\" data-agent-error><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n </li>\n }\n </ul>\n }\n @if (exporting(); as agent) {\n <nh-assistant-agent-package-export-dialog [agents]=\"agents()\" [start]=\"agent\" (closed)=\"exporting.set(null)\" />\n }\n @if (importing()) {\n <nh-assistant-agent-package-import-dialog\n [agents]=\"agents()\"\n [accountSearch]=\"accountSearch()\"\n (imported)=\"onPackageImported()\"\n (closed)=\"importing.set(false)\" />\n }\n @if (runNowAgent(); as runAgent) {\n <nh-assistant-run-now-dialog\n [agent]=\"runAgent\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n [divisions]=\"catalog()?.divisions === true\"\n (openConversation)=\"openConversation($event)\"\n (closed)=\"runningNow.set(null)\" />\n }\n </section>\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"] }]
|
|
7231
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (editing() !== undefined) {\n <nh-assistant-admin-agent-editor\n [agent]=\"editing() ?? null\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [catalog]=\"catalog()\"\n [catalogUnavailable]=\"catalogError() !== null\"\n (saved)=\"onEditorSaved($event)\"\n (workRequested)=\"onWorkRequested($event)\"\n (cancelled)=\"onEditorCancelled()\" />\n} @else if (reporting(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeReport()\">\n {{ 'nh-assistant.admin.feedback.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-feedback-report [agentId]=\"agent.id\" />\n </div>\n} @else if (configuring(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRunConfiguration()\">\n {{ 'nh-assistant.admin.run-config.back' | translate }}\n </button>\n </div>\n <nh-assistant-agent-run-configuration\n [agent]=\"agent\"\n [startSetup]=\"setupOnOpen()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [agents]=\"agents()\"\n (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\"\n (openAgent)=\"askerFromRunConfiguration(agent, $event)\" />\n <nh-assistant-agent-hand-offs [agent]=\"agent\" [agents]=\"agents()\" [subjectTypes]=\"catalog()?.subjectTypes ?? []\" />\n <nh-assistant-agent-shadow-variants\n [agent]=\"agent\"\n (created)=\"onVariantCreated($event)\"\n (promoted)=\"onVariantPromoted($event)\"\n (openVariant)=\"variantFromRunConfiguration($event)\" />\n </div>\n} @else if (viewingRuns(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeRuns()\">\n {{ (returnTo() === agent.id ? 'nh-assistant.admin.runs.back-to-run-config' : 'nh-assistant.admin.runs.back') | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-run-history\n [agentId]=\"agent.id\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n (openConversation)=\"openConversation($event)\" />\n </div>\n} @else if (evaluating(); as agent) {\n <div class=\"stack\">\n <div>\n <button #back class=\"secondary\" type=\"button\" (click)=\"closeEvaluation()\">\n {{ 'nh-assistant.admin.evaluation.back' | translate }}\n </button>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.feedback.agent' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName), id: agent.id } }}</p>\n <nh-assistant-agent-evaluation [agentId]=\"agent.id\" [variants]=\"variantsOf(agent)\" />\n </div>\n} @else {\n <section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.agents.title' | translate }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.description' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" aria-haspopup=\"dialog\" data-import-package [disabled]=\"loading() || loadFailed()\" (click)=\"importPackage()\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.import' | translate }}\n </button>\n <button class=\"primary\" type=\"button\" [disabled]=\"loading() || loadFailed()\" (click)=\"create()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.agents.new' | translate }}\n </button>\n </div>\n </header>\n\n @if (error(); as failure) {\n @if (errorAgentId() === null) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n @if (!loading() && !loadFailed()) {\n @if (catalogError(); as failure) {\n <!-- Without the run catalog nothing that depends on it is offered: run now, what agents work on, groups. -->\n <div class=\"message warning catalog-error\" role=\"alert\" data-catalog-error>\n <nh-assistant-icon name=\"warning\" />\n <span class=\"grow\">\n {{ 'nh-assistant.admin.agents.catalog-failed' | translate }}\n {{ catalogErrorKeys() | nhAssistantTranslate: failure.code }}\n </span>\n <button class=\"secondary\" type=\"button\" data-catalog-retry [disabled]=\"catalogLoading()\" (click)=\"retryCatalog()\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.retry' | translate }}\n </button>\n </div>\n }\n <nh-assistant-account-names-error [names]=\"accountNameLookup\" />\n }\n\n @if (loading()) {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n } @else if (loadFailed()) {\n <div class=\"state\" role=\"alert\">\n <p>{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n <button class=\"secondary\" type=\"button\" (click)=\"load()\">{{ 'nh-assistant.admin.retry' | translate }}</button>\n </div>\n } @else if (agents().length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.agents.empty' | translate }}</p>\n } @else {\n <ul class=\"cards\">\n @for (agent of agents(); track agent.id) {\n <li class=\"card\" [class.inactive]=\"agent.runState !== 'active'\" [attr.aria-busy]=\"busyAgentId() === agent.id\">\n <div class=\"card-header\">\n <!-- An agent in code names and describes itself with translation keys. -->\n <strong>{{ (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }}</strong>\n <span class=\"mono muted\">{{ agent.id }}</span>\n <span class=\"badge\">{{ (agent.source === 'code' ? 'nh-assistant.admin.agents.source-code' : 'nh-assistant.admin.agents.source-admin') | translate }}</span>\n @if (agent.isOverridden) {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.agents.overridden' | translate }}</span>\n }\n <span\n class=\"badge\"\n [class.success]=\"agent.runState === 'active'\"\n [class.warning]=\"agent.runState === 'paused'\"\n [class.danger]=\"agent.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + agent.runState | translate }}</span>\n @if (agent.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n @if (agent.offeredInChat === false) {\n <span class=\"badge\" data-hidden-from-chat>{{ 'nh-assistant.admin.agents.chat.hidden' | translate }}</span>\n }\n @if (agent.package; as linked) {\n <span class=\"badge\" data-package-badge><nh-assistant-icon name=\"lock\" />{{ 'nh-assistant.admin.packages.linked-badge' | translate: { package: linked.packageId, version: linked.packageVersion } }}</span>\n }\n </div>\n <!-- The package the agent comes from; unlinking makes every part of it local. -->\n <nh-assistant-package-lock [lock]=\"agentPackageOf(agent)\" [agentId]=\"agent.id\" [part]=\"null\" (unlinked)=\"onPackageUnlinked()\" />\n @if (agent.description) {\n <p class=\"muted\">{{ codeTextKeys(agent.source, agent.description) | nhAssistantTranslate: agent.description }}</p>\n }\n <!-- A warning never refused the save: the agent is in effect but may not work as configured. -->\n @for (warning of agent.warnings ?? []; track warning) {\n <p class=\"message warning\" [attr.data-agent-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('agent', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n <!-- The asset its instructions come from no longer resolves: the agent starts no model turn. -->\n @if (agent.instructionsProblem) {\n <p class=\"message error\" role=\"status\" data-agent-instructions-problem>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.instruction-assets.agent-problem' | translate }}\n {{ 'nh-assistant.admin.instruction-assets.problems.' + agent.instructionsProblem | translate }}\n </p>\n }\n @if (agent.runState === 'configured-off') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.configured-off-hint' | translate }}</p>\n } @else if (agent.runState !== 'active') {\n <p class=\"muted\">\n @if (agent.stateChangedAt) {\n <span [attr.title]=\"accountTitle(agent.stateChangedBy)\">{{ 'nh-assistant.admin.agents.state.changed' | translate: { user: accountName(agent.stateChangedBy), date: (agent.stateChangedAt | date: 'medium') } }}</span>\n }\n @if (agent.stateReason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: agent.stateReason } }}\n }\n </p>\n @if (agent.runState === 'paused') {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: agent.waitingInputs } }}</p>\n }\n <!-- What releasing the kill switch does: an agent that was off goes back off. Older servers do not say. -->\n @if (agent.runState === 'stopped' && agent.offBeforeStop !== undefined) {\n <p class=\"muted\" data-stopped-hint [attr.data-off-before-stop]=\"agent.offBeforeStop\">\n {{ (agent.offBeforeStop ? 'nh-assistant.admin.agents.state.stopped-was-off-hint' : 'nh-assistant.admin.agents.state.stopped-was-on-hint') | translate }}\n </p>\n }\n @if (agent.runState === 'off') {\n <p class=\"muted\" data-off-hint>\n {{ 'nh-assistant.admin.agents.state.off-hint' | translate }}\n @if (!agent.stateChangedAt) {\n {{ 'nh-assistant.admin.agents.state.starts-off' | translate }}\n }\n </p>\n }\n }\n @if (agent.shadow; as shadow) {\n @if (shadow.shadow) {\n <p class=\"muted\">\n {{ (shadow.locked ? 'nh-assistant.admin.agents.shadow.locked' : 'nh-assistant.admin.agents.shadow.hint') | translate }}\n @if (shadow.changedAt && shadow.override !== null) {\n <span [attr.title]=\"accountTitle(shadow.changedBy)\">{{ 'nh-assistant.admin.agents.shadow.changed' | translate: { user: accountName(shadow.changedBy), date: (shadow.changedAt | date: 'medium') } }}</span>\n }\n @if (shadow.reason && shadow.override !== null) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: shadow.reason } }}\n }\n </p>\n }\n }\n @if (agent.serviceAccount; as account) {\n <p class=\"muted\" data-service-account>\n <span [attr.title]=\"accountTitle(account.actorId)\">{{ 'nh-assistant.admin.agents.service-account.label' | translate: { account: accountName(account.actorId) } }}</span>\n @if (account.overridden) {\n <span [attr.title]=\"accountTitle(account.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.configured' | translate: { account: accountName(account.configuredActorId) } }}</span>\n @if (account.reason) {\n {{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: account.reason } }}\n }\n }\n </p>\n }\n @if (worksOn(agent); as works) {\n <!-- What the agent works on; an agent in code shows its code setting. -->\n <p class=\"muted\" data-works-on>\n <span>{{ 'nh-assistant.admin.agents.works-on.label' | translate }}</span>\n <strong>\n @switch (works.only) {\n @case ('all') { {{ 'nh-assistant.admin.agents.works-on.all' | translate }} }\n @case ('types') { {{ works.types.join(', ') }} }\n @default { {{ 'nh-assistant.admin.agents.works-on.application' | translate }} }\n }\n </strong>\n @if (works.application && works.only !== 'application') {\n <span>{{ 'nh-assistant.admin.agents.works-on.and-application' | translate }}</span>\n }\n @if (works.perDivision) {\n <span>{{ 'nh-assistant.admin.agents.works-on.per-division' | translate }}</span>\n }\n @if (works.undeclared) {\n <span>{{ 'nh-assistant.admin.agents.works-on.undeclared' | translate }}</span>\n }\n </p>\n @if (works.all && works.known.length > 0) {\n <p class=\"muted\" data-known-types>{{ 'nh-assistant.admin.agents.works-on.known' | translate: { types: works.known.join(', ') } }}</p>\n }\n @if (works.runPolicy || works.viewPolicy) {\n <!-- Each policy is an item of its own, wrapping on narrow screens. -->\n <div class=\"meta\" data-works-on-policies>\n @if (works.runPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.run-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n @if (works.viewPolicy; as policy) {\n <span>{{ 'nh-assistant.admin.agents.works-on.view-policy' | translate: { policy: (policyKeys(policy) | nhAssistantTranslate: policy) } }}</span>\n }\n </div>\n }\n }\n @if (groupNames(agent); as names) {\n <p class=\"muted\" data-agent-groups>{{ 'nh-assistant.admin.agents.groups' | translate: { groups: names } }}</p>\n }\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.autonomy.' + agent.autonomy | translate }}</span>\n <span>{{ (agent.toolSelectors.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: agent.toolSelectors.length } }}</span>\n <span>{{ (agent.mcpServerIds.length === 1 ? 'nh-assistant.admin.agents.server-count-one' : 'nh-assistant.admin.agents.server-count') | translate: { count: agent.mcpServerIds.length } }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: agent.version } }}</span>\n @if (agent.requiredPolicy; as policy) {\n <!-- The application may name its policies; otherwise the policy shows as it is called in code. -->\n <span data-required-policy>\n {{ 'nh-assistant.admin.agents.required-policy' | translate }}\n @if (policyKeys(policy) | nhAssistantTranslate; as text) {\n {{ text }}\n } @else {\n <code class=\"mono\">{{ policy }}</code>\n }\n </span>\n }\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"edit(agent)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n @for (action of stateActions(agent); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action)\">\n {{ stateKey('action', agent.runState, action) | translate }}\n </button>\n }\n @if (agent.runState !== 'configured-off') {\n @for (mode of shadowActions(agent.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n }\n @if (agent.serviceAccount; as account) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"set\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'set')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'set')\">\n {{ 'nh-assistant.admin.agents.service-account.action.set' | translate }}\n </button>\n @if (account.overridden) {\n <button\n class=\"secondary\"\n type=\"button\"\n data-account-action=\"code\"\n [attr.aria-expanded]=\"isChangingAccount(agent.id, 'code')\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askAccount(agent, 'code')\">\n {{ 'nh-assistant.admin.agents.service-account.action.code' | translate }}\n </button>\n }\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-run-config-agent]=\"agent.id\" (click)=\"openRunConfiguration(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.run-config' | translate }}\n </button>\n }\n @if (hasRunConfiguration(agent)) {\n <button class=\"secondary\" type=\"button\" [attr.data-runs-agent]=\"agent.id\" (click)=\"openRuns(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.runs' | translate }}\n </button>\n }\n @if (canRunNow(agent)) {\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-run-now-agent]=\"agent.id\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"runNow(agent)\">\n <nh-assistant-icon name=\"send\" />{{ 'nh-assistant.admin.agents.run-now' | translate }}\n </button>\n }\n <button class=\"secondary\" type=\"button\" [attr.data-feedback-agent]=\"agent.id\" (click)=\"openReport(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.feedback' | translate }}\n </button>\n <button\n class=\"secondary\"\n type=\"button\"\n aria-haspopup=\"dialog\"\n [attr.data-export-package]=\"agent.id\"\n [attr.aria-label]=\"'nh-assistant.admin.packages.export-named' | translate: { name: (codeTextKeys(agent.source, agent.displayName) | nhAssistantTranslate: agent.displayName) }\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"exportPackage(agent)\">\n <nh-assistant-icon name=\"file\" />{{ 'nh-assistant.admin.packages.export' | translate }}\n </button>\n @if (variantsOf(agent).length > 0) {\n <button class=\"secondary\" type=\"button\" [attr.data-evaluation-agent]=\"agent.id\" (click)=\"openEvaluation(agent)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.agents.evaluation' | translate }}\n </button>\n }\n @if (agent.source === 'code' && agent.isOverridden) {\n @if (isConfirming(agent.id, 'reset')) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.reset-keeps-state' | translate }}</span>\n <button class=\"danger\" type=\"button\" (click)=\"reset(agent)\">{{ 'nh-assistant.admin.agents.confirm-reset' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"secondary\"\n type=\"button\"\n data-reset-agent\n [attr.aria-describedby]=\"resetLocked(agent) ? id + '-' + agent.id + '-reset-locked' : null\"\n [disabled]=\"busyAgentId() !== null || resetLocked(agent)\"\n (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\n @if (resetLocked(agent)) {\n <span class=\"muted\" data-reset-locked [id]=\"id + '-' + agent.id + '-reset-locked'\">{{ 'nh-assistant.admin.packages.reset-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n @if (agent.source === 'admin') {\n @if (isConfirming(agent.id, 'delete')) {\n <button class=\"danger\" type=\"button\" (click)=\"remove(agent)\">{{ 'nh-assistant.admin.confirm-delete' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button\n class=\"danger\"\n type=\"button\"\n data-delete-agent\n [attr.aria-describedby]=\"deleteLocked(agent) ? id + '-' + agent.id + '-delete-locked' : null\"\n [disabled]=\"busyAgentId() !== null || deleteLocked(agent)\"\n (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n @if (deleteLocked(agent)) {\n <span class=\"muted\" data-delete-locked [id]=\"id + '-' + agent.id + '-delete-locked'\">{{ 'nh-assistant.admin.packages.delete-locked' | translate: { package: agent.package?.packageId } }}</span>\n }\n }\n }\n </div>\n @if (agent.skills?.length) {\n <ul class=\"skills\" [attr.aria-label]=\"'nh-assistant.admin.agents.skills.title' | translate\">\n @for (skill of agent.skills; track skill.skillId) {\n <li class=\"skill\" [attr.data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span\n class=\"badge\"\n [class.success]=\"skill.runState === 'active'\"\n [class.warning]=\"skill.runState === 'paused'\"\n [class.danger]=\"skill.runState === 'stopped'\">{{ 'nh-assistant.admin.agents.state.' + skill.runState | translate }}</span>\n @if (skill.shadow?.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n }\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(agent.id, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n <div class=\"meta\">\n <span>{{ 'nh-assistant.admin.agents.skills.usage' | translate: { calls: skill.toolCallsToday, tokens: skill.tokensToday } }}</span>\n @if (skill.dailyToolCalls !== null) {\n <span>{{ 'nh-assistant.admin.agents.skills.budget' | translate: { calls: skill.dailyToolCalls, tokens: skill.dailyTokens } }}</span>\n }\n @if (skill.runState === 'paused') {\n <span>{{ 'nh-assistant.admin.agents.state.waiting' | translate: { count: skill.waitingInputs } }}</span>\n }\n @if (skill.reason) {\n <span>{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: skill.reason } }}</span>\n }\n </div>\n @if (agent.runState !== 'configured-off') {\n <div class=\"card-actions\">\n @for (action of skillActions(skill); track action) {\n <button\n type=\"button\"\n [class.secondary]=\"action !== 'stopped'\"\n [class.danger]=\"action === 'stopped'\"\n [attr.data-state-action]=\"action\"\n [attr.aria-label]=\"(stateKey('action', skill.runState, action) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingState(agent.id, action, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action, skill)\">\n {{ stateKey('action', skill.runState, action) | translate }}\n </button>\n }\n @for (mode of shadowActions(skill.shadow); track mode) {\n <button\n class=\"secondary\"\n type=\"button\"\n [attr.data-shadow-action]=\"mode\"\n [attr.aria-label]=\"(shadowActionKey(agent, mode) | translate) + ' ' + (skillNameKeys(agent.id, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId))\"\n [attr.aria-expanded]=\"isChangingShadow(agent.id, mode, skill.skillId)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askShadow(agent, mode, skill)\">\n {{ shadowActionKey(agent, mode) | translate }}\n </button>\n }\n </div>\n }\n </li>\n }\n </ul>\n }\n @if (changingState(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" (submit)=\"$event.preventDefault(); applyState(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ skillStateExplainKey(change) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)) } }}</p>\n } @else {\n <p class=\"muted\">{{ stateKey('explain', change.from, change.state) | translate }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" [class.primary]=\"change.state !== 'stopped'\" [class.danger]=\"change.state === 'stopped'\" [disabled]=\"busyAgentId() !== null\">\n {{ stateKey('confirm', change.from, change.state) | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingState.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingShadow(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-shadow-form (submit)=\"$event.preventDefault(); applyShadow(agent)\">\n @if (change.skillId) {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, true) | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)), mode: (ownShadowModeKey(agent, change.skillId) | translate) } }}</p>\n } @else {\n <p class=\"muted\">{{ shadowExplainKey(agent, change.mode, false) | translate: { mode: (ownShadowModeKey(agent) | translate) } }}</p>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-shadow-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n #reasonInput\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-shadow-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-shadow-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-shadow-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.shadow.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingShadow.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (changingAccount(); as change) {\n @if (change.agentId === agent.id) {\n <form class=\"stack\" data-account-form (submit)=\"$event.preventDefault(); applyAccount(agent)\">\n <p class=\"muted\" [attr.title]=\"accountTitle(agent.serviceAccount?.configuredActorId)\">{{ 'nh-assistant.admin.agents.service-account.explain.' + change.mode | translate: { account: accountName(agent.serviceAccount?.configuredActorId) } }}</p>\n @if (change.mode === 'set') {\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account'\">{{ (accountSearch() ? 'nh-assistant.admin.agents.service-account.input-label-search' : 'nh-assistant.admin.agents.service-account.input-label') | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-' + agent.id + '-account'\"\n [value]=\"accountId()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"accountError() !== null\"\n [describedBy]=\"accountError() ? id + '-' + agent.id + '-account-error' : null\"\n (valueChange)=\"onAccountChange($event)\" />\n @if (accountError(); as failure) {\n <p class=\"field-error\" data-account-error [id]=\"id + '-' + agent.id + '-account-error'\">\n <nh-assistant-icon name=\"warning\" />{{ accountErrorKeys() | nhAssistantTranslate: failure.code }}\n </p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-' + agent.id + '-account-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"id + '-' + agent.id + '-account-reason'\"\n [attr.aria-describedby]=\"id + '-' + agent.id + '-account-reason-hint'\"\n [maxLength]=\"maxReason\"\n [value]=\"stateReason()\"\n (input)=\"stateReason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-' + agent.id + '-account-reason-hint'\">{{ 'nh-assistant.admin.agents.state.note-hint' | translate }}</p>\n </div>\n <div class=\"card-actions\">\n <button type=\"submit\" class=\"primary\" [disabled]=\"busyAgentId() !== null\">\n {{ 'nh-assistant.admin.agents.service-account.confirm.' + change.mode | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" (click)=\"changingAccount.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n </div>\n </form>\n }\n }\n @if (error(); as failure) {\n @if (errorAgentId() === agent.id) {\n <p class=\"form-error\" role=\"alert\" data-agent-error><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n }\n </li>\n }\n </ul>\n }\n @if (exporting(); as agent) {\n <nh-assistant-agent-package-export-dialog [agents]=\"agents()\" [start]=\"agent\" (closed)=\"exporting.set(null)\" />\n }\n @if (importing()) {\n <nh-assistant-agent-package-import-dialog\n [agents]=\"agents()\"\n [accountSearch]=\"accountSearch()\"\n (imported)=\"onPackageImported()\"\n (closed)=\"importing.set(false)\" />\n }\n @if (runNowAgent(); as runAgent) {\n <nh-assistant-run-now-dialog\n [agent]=\"runAgent\"\n [subjectTypes]=\"catalog()?.subjectTypes ?? []\"\n [divisions]=\"catalog()?.divisions === true\"\n (openConversation)=\"openConversation($event)\"\n (closed)=\"runningNow.set(null)\" />\n }\n </section>\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:14px}: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}.section{display:flex;flex-direction:column;gap:16px;min-width:0}.section-header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.section-header>div{min-width:0;max-width:72ch}h3{margin:0 0 4px;font-size:17px;font-weight:750}h4{margin:0 0 8px;font-size:14px;font-weight:700}.muted{margin:0;color:var(--nha-text-muted);font-size:13px}.state{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin:0;border:1px dashed var(--nha-border);border-radius:var(--nha-radius);padding:20px;color:var(--nha-text-muted);font-size:13px}.state p{margin:0}.stack{display:flex;flex-direction:column;gap:14px;min-width:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px}.meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}textarea.large{min-height:260px}.catalog-error{flex-wrap:wrap}.grow{flex:1;min-width:0}.subsection{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--nha-border);padding-top:14px}.history{display:grid;gap:6px;margin:0;padding:0;list-style:none}.history li{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:12px}.cards{display:grid;gap:10px;margin:0;padding:0;list-style:none}.card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius);padding:14px;background:var(--nha-background)}.card.inactive{opacity:.8}.card-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.card-header strong{font-size:14px;overflow-wrap:anywhere}.card-actions{display:flex;flex-wrap:wrap;gap:8px}.check{display:flex;align-items:flex-start;gap:8px;font-size:13px;cursor:pointer}.check input{width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.check.described>span{display:grid;gap:2px;min-width:0;overflow-wrap:anywhere}.checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:6px 12px;min-width:0;overflow-wrap:anywhere}.chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none}.chip{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--nha-border);border-radius:999px;padding:2px 2px 2px 10px;background:var(--nha-surface);font-family:var(--nha-mono);font-size:12px}.chip 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;width:26px;height:26px;border-radius:999px}.chip button:focus-visible{outline:3px solid color-mix(in srgb,var(--nha-focus) 80%,transparent);outline-offset:2px}.chip button:hover:not(:disabled){color:var(--nha-text);background:var(--nha-surface-strong)}.chip button:disabled{cursor:not-allowed;opacity:.5}.inline{display:flex;flex-wrap:wrap;gap:8px}.inline>input{flex:1 1 180px}.catalog{display:grid;gap:4px;max-height:260px;margin:8px 0 0;overflow-y:auto;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px;list-style:none}.catalog li label{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;border-radius:8px;padding:6px;cursor:pointer}.catalog li label:hover{background:var(--nha-surface)}.catalog .tool-id{font-family:var(--nha-mono);font-size:12px;overflow-wrap:anywhere}.skills{display:grid;gap:8px;margin:0;padding:0;list-style:none}.skill{display:grid;gap:6px;border-left:3px solid var(--nha-border);padding:4px 0 4px 12px}.uses{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}.use{display:flex;align-items:flex-start;gap:10px;min-width:0;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:10px 12px;cursor:pointer;overflow-wrap:anywhere}.use input{flex:none;width:16px;height:16px;margin:2px 0 0;accent-color:var(--nha-highlight)}.use>span{display:grid;gap:2px;min-width:0}.use strong{font-size:13px}.use.selected{border-color:var(--nha-highlight);background:var(--nha-surface)}.use:focus-within{outline:2px solid var(--nha-highlight);outline-offset:2px}.discovery{display:grid;gap:8px;padding:10px 12px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control)}.discovery dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 12px;margin:0}.discovery dt{color:var(--nha-text-muted)}.discovery dd{margin:0;overflow-wrap:anywhere}\n"] }]
|
|
7139
7232
|
}], ctorParameters: () => [], propDecorators: { backButton: [{ type: i0.ViewChild, args: ['back', { isSignal: true }] }], reasonInput: [{ type: i0.ViewChild, args: ['reasonInput', { isSignal: true }] }], openMcpServers: [{ type: i0.Output, args: ["openMcpServers"] }] } });
|
|
7140
7233
|
function withState(agent, state) {
|
|
7141
7234
|
return {
|