@newheap/platform-ai-chat 0.15.0 → 0.16.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.
@@ -214,6 +214,15 @@ function skillNameKeys(agentId, skillId) {
214
214
  function skillDescriptionKeys(agentId, skillId) {
215
215
  return [`nh-assistant.agents.${agentId}.skills.${skillId}.description`];
216
216
  }
217
+ /**
218
+ * The key of a warning about an agent or a skill that is saved and in effect but may not work as
219
+ * configured, such as `classification-not-permitted`; a code the screen does not know shows as sent.
220
+ */
221
+ function warningKeys(kind, code) {
222
+ return kind === 'agent'
223
+ ? [`nh-assistant.admin.agents.warnings.${code}`]
224
+ : [`nh-assistant.admin.run-config.skills.warnings.${code}`];
225
+ }
217
226
  /** The key an application may translate an authorization policy's name with. */
218
227
  function policyKeys(policy) {
219
228
  return policy ? [`nh-assistant.policies.${policy}`] : [];
@@ -411,6 +420,7 @@ class NhAssistantAdminAgentEditorComponent {
411
420
  this.id = `nh-assistant-agent-editor-${nextId$f++}`;
412
421
  this.max = NH_ASSISTANT_MAX_INSTRUCTIONS;
413
422
  this.autonomyLevels = ['observe', 'explain', 'propose', 'simulate', 'execute'];
423
+ this.classifications = ['public', 'internal', 'confidential', 'restricted'];
414
424
  this.agentId = signal('', ...(ngDevMode ? [{ debugName: "agentId" }] : []));
415
425
  this.displayName = signal('', ...(ngDevMode ? [{ debugName: "displayName" }] : []));
416
426
  this.description = signal('', ...(ngDevMode ? [{ debugName: "description" }] : []));
@@ -418,6 +428,12 @@ class NhAssistantAdminAgentEditorComponent {
418
428
  this.autonomy = signal('explain', ...(ngDevMode ? [{ debugName: "autonomy" }] : []));
419
429
  /** How the agent is used: in the chat, on its own, or both. */
420
430
  this.use = signal('chat', ...(ngDevMode ? [{ debugName: "use" }] : []));
431
+ /** A new agent takes its triggers at once; without it, it starts off until someone switches it on. */
432
+ this.switchOnNow = signal(true, ...(ngDevMode ? [{ debugName: "switchOnNow" }] : []));
433
+ /** The model profile of an agent created here; empty uses the application's chat profile. */
434
+ this.profile = signal('', ...(ngDevMode ? [{ debugName: "profile" }] : []));
435
+ /** The classification of the model calls of an agent created here; `internal` when it has none. */
436
+ this.dataClassification = signal('internal', ...(ngDevMode ? [{ debugName: "dataClassification" }] : []));
421
437
  this.requiredPolicy = signal('', ...(ngDevMode ? [{ debugName: "requiredPolicy" }] : []));
422
438
  this.toolSelectors = signal([], ...(ngDevMode ? [{ debugName: "toolSelectors" }] : []));
423
439
  this.mcpServerIds = signal([], ...(ngDevMode ? [{ debugName: "mcpServerIds" }] : []));
@@ -480,10 +496,21 @@ class NhAssistantAdminAgentEditorComponent {
480
496
  }, ...(ngDevMode ? [{ debugName: "knownTypes" }] : []));
481
497
  /** What the agent works on is edited here: an agent created here, while the run catalog is known. */
482
498
  this.editsWorksOn = computed(() => this.choosesUse() && !this.catalogUnavailable(), ...(ngDevMode ? [{ debugName: "editsWorksOn" }] : []));
499
+ /** An agent created here chooses its profile from those the run catalog offers. */
500
+ this.choosesProfile = computed(() => this.choosesUse() && !this.catalogUnavailable(), ...(ngDevMode ? [{ debugName: "choosesProfile" }] : []));
501
+ /** The profiles the run catalog offers, and the agent's own when the catalog no longer lists it. */
502
+ this.profileChoices = computed(() => {
503
+ const listed = this.catalog()?.profiles ?? [];
504
+ const current = this.agent()?.profile;
505
+ return current && !listed.includes(current) ? [...listed, current] : listed;
506
+ }, ...(ngDevMode ? [{ debugName: "profileChoices" }] : []));
483
507
  /** Chosen object types without a type, and not the application either: the agent would work on nothing. */
484
508
  this.worksOnMissing = computed(() => this.editsWorksOn() && this.worksOnScope() === 'types' && this.worksOnTypes().length === 0 && !this.worksOnApplication(), ...(ngDevMode ? [{ debugName: "worksOnMissing" }] : []));
485
509
  this.tooManyTypes = computed(() => this.editsWorksOn() && this.worksOnScope() === 'types' && this.worksOnTypes().length > maxWorksOnTypes, ...(ngDevMode ? [{ debugName: "tooManyTypes" }] : []));
486
510
  this.policyKeys = policyKeys;
511
+ this.warningKeys = warningKeys;
512
+ /** The warnings of the agent as it was saved, until this editor saves it again. */
513
+ this.warnings = computed(() => this.agent()?.warnings ?? [], ...(ngDevMode ? [{ debugName: "warnings" }] : []));
487
514
  this.valid = computed(() => !this.idInvalid() && !this.nameMissing() && !this.tooLong() && !this.worksOnMissing() && !this.tooManyTypes(), ...(ngDevMode ? [{ debugName: "valid" }] : []));
488
515
  this.errorKeys = computed(() => _nhAssistantErrorKeys(this.error()), ...(ngDevMode ? [{ debugName: "errorKeys" }] : []));
489
516
  this.filteredTools = computed(() => {
@@ -564,7 +591,14 @@ class NhAssistantAdminAgentEditorComponent {
564
591
  autonomy: this.autonomy(),
565
592
  ...(this.choosesUse() ? { offeredInChat: this.use() !== 'background' } : {}),
566
593
  // Omitted, what the agent works on stays as it is; a new agent then works on every object type.
567
- ...(this.editsWorksOn() ? this.worksOnInput() : {})
594
+ ...(this.editsWorksOn() ? this.worksOnInput() : {}),
595
+ ...(this.isNew() && !this.switchOnNow() ? { startsOff: true } : {}),
596
+ // Omitted, the profile stays as it is; a new agent then uses the application's chat profile.
597
+ ...(this.choosesProfile() && this.profile() !== '' ? { profile: this.profile() } : {}),
598
+ // Sent only when it changes, so an agent without a classification keeps none.
599
+ ...(this.choosesUse() && this.dataClassification() !== (this.editing()?.dataClassification ?? 'internal')
600
+ ? { dataClassification: this.dataClassification() }
601
+ : {})
568
602
  };
569
603
  const startsWork = this.agent() === null && this.use() !== 'chat';
570
604
  // An existing agent's groups are saved before its definition, a new agent's right after it is
@@ -621,6 +655,9 @@ class NhAssistantAdminAgentEditorComponent {
621
655
  this.instructions.set(agent?.instructions ?? '');
622
656
  this.autonomy.set(agent?.autonomy ?? 'explain');
623
657
  this.use.set(agent?.offeredInChat === false ? 'background' : 'chat');
658
+ this.switchOnNow.set(true);
659
+ this.profile.set(agent?.source === 'admin' ? agent.profile ?? '' : '');
660
+ this.dataClassification.set(agent?.source === 'admin' ? agent.dataClassification ?? 'internal' : 'internal');
624
661
  this.requiredPolicy.set(agent?.requiredPolicy ?? '');
625
662
  this.toolSelectors.set([...(agent?.toolSelectors ?? [])]);
626
663
  this.mcpServerIds.set([...(agent?.mcpServerIds ?? [])]);
@@ -645,11 +682,11 @@ class NhAssistantAdminAgentEditorComponent {
645
682
  return typeof shown === 'string' && shown.length > 0 && shown !== text ? { key: text, shown } : null;
646
683
  }
647
684
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
648
- 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\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 }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\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>\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}</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 </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 [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 }}</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 }}</label>\n <input type=\"text\" [id]=\"id + '-description'\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}</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 <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}</label>\n <select [id]=\"id + '-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 }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\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 </div>\n\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.state-hint' | translate }}</p>\n\n <fieldset class=\"subsection\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}</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", 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: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
685
+ 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\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 }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\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>\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}</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 }\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 [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 }}</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 }}</label>\n <input type=\"text\" [id]=\"id + '-description'\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}</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 <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}</label>\n <select [id]=\"id + '-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 }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\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 }}</label>\n <select\n [id]=\"id + '-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 }}</label>\n <select\n [id]=\"id + '-classification'\"\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\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}</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", 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: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
649
686
  }
650
687
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentEditorComponent, decorators: [{
651
688
  type: Component,
652
- args: [{ selector: 'nh-assistant-admin-agent-editor', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent], 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\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 }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\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>\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}</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 </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 [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 }}</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 }}</label>\n <input type=\"text\" [id]=\"id + '-description'\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}</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 <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}</label>\n <select [id]=\"id + '-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 }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\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 </div>\n\n <p class=\"hint\">{{ 'nh-assistant.admin.agent-editor.state-hint' | translate }}</p>\n\n <fieldset class=\"subsection\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}</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", 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"] }]
689
+ args: [{ selector: 'nh-assistant-admin-agent-editor', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent], 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\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 }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\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>\n <legend>{{ 'nh-assistant.admin.agent-editor.use.title' | translate }}</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 }\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 [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 }}</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 }}</label>\n <input type=\"text\" [id]=\"id + '-description'\" [value]=\"description()\" (input)=\"description.set(value($event))\" />\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.agent-editor.instructions' | translate }}</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 <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-autonomy'\">{{ 'nh-assistant.admin.agent-editor.autonomy' | translate }}</label>\n <select [id]=\"id + '-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 }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n autocomplete=\"off\"\n [id]=\"id + '-policy'\"\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 }}</label>\n <select\n [id]=\"id + '-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 }}</label>\n <select\n [id]=\"id + '-classification'\"\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\">\n <legend>{{ 'nh-assistant.admin.agent-editor.tool-selectors' | translate }}</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", 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"] }]
653
690
  }], 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"] }] } });
654
691
  /** Whether two sorted lists of group ids are the same. */
655
692
  function sameGroups(left, right) {
@@ -1390,6 +1427,8 @@ function withScheduleTargetError(errors, target) {
1390
1427
  ? { ...errors, subjectSet: { code: 'application-not-worked-on' } }
1391
1428
  : errors;
1392
1429
  }
1430
+ /** The data classifications a skill can choose, from the least to the most sensitive. */
1431
+ const dataClassifications = ['public', 'internal', 'confidential', 'restricted'];
1393
1432
  function profileOptions(catalog) {
1394
1433
  return (catalog?.profiles ?? []).map(profile => ({ value: profile, label: profile }));
1395
1434
  }
@@ -1499,6 +1538,83 @@ function describeDuration(minutes, t) {
1499
1538
  }
1500
1539
  return t(minutes === 1 ? `${base}.minute` : `${base}.minutes`, { count: minutes });
1501
1540
  }
1541
+ /** The bytes of one megabyte, as the forms show a file size. */
1542
+ const bytesPerMegabyte = 1024 * 1024;
1543
+ /** The file limit fields in the order the forms show them. */
1544
+ const fileLimitFields = ['maxFileBytes', 'maxFilePages', 'maxFilesPerTurn', 'maxFileTokensPerTurn'];
1545
+ /** A size in megabytes as a form shows it: whole megabytes plainly, others with up to two decimals. */
1546
+ function megabytesText(bytes) {
1547
+ const megabytes = bytes / bytesPerMegabyte;
1548
+ return Number.isInteger(megabytes) ? String(megabytes) : String(Math.round(megabytes * 100) / 100);
1549
+ }
1550
+ /**
1551
+ * The lower file limits of an agent or a skill as a form edits them: the largest file in megabytes,
1552
+ * the others as whole numbers; an empty field keeps the application's limit (for a skill, the
1553
+ * agent's). A size shown with decimals keeps its exact bytes until the administrator changes it.
1554
+ */
1555
+ class FileLimitsDraft {
1556
+ constructor() {
1557
+ this.megabytes = signal('', ...(ngDevMode ? [{ debugName: "megabytes" }] : []));
1558
+ this.pages = signal('', ...(ngDevMode ? [{ debugName: "pages" }] : []));
1559
+ this.files = signal('', ...(ngDevMode ? [{ debugName: "files" }] : []));
1560
+ this.tokens = signal('', ...(ngDevMode ? [{ debugName: "tokens" }] : []));
1561
+ this.loadedBytes = null;
1562
+ this.loadedMegabytes = '';
1563
+ }
1564
+ load(limits) {
1565
+ this.loadedBytes = limits?.maxFileBytes ?? null;
1566
+ this.loadedMegabytes = this.loadedBytes === null ? '' : megabytesText(this.loadedBytes);
1567
+ this.megabytes.set(this.loadedMegabytes);
1568
+ this.pages.set(numberText(limits?.maxFilePages));
1569
+ this.files.set(numberText(limits?.maxFilesPerTurn));
1570
+ this.tokens.set(numberText(limits?.maxFileTokensPerTurn));
1571
+ }
1572
+ /** The text of a field, by its server name. */
1573
+ text(field) {
1574
+ switch (field) {
1575
+ case 'maxFileBytes':
1576
+ return this.megabytes;
1577
+ case 'maxFilePages':
1578
+ return this.pages;
1579
+ case 'maxFilesPerTurn':
1580
+ return this.files;
1581
+ default:
1582
+ return this.tokens;
1583
+ }
1584
+ }
1585
+ /** Checks the fields against the application's limits, as the server does; only next to accepting files. */
1586
+ check(errors, application) {
1587
+ const bytes = this.bytes();
1588
+ if (this.megabytes().trim() !== '' && (bytes === null || bytes < 1 || (application && bytes > application.maxFileBytes))) {
1589
+ errors['maxFileBytes'] = application
1590
+ ? { code: 'megabytes-up-to', params: { max: megabytesText(application.maxFileBytes) } }
1591
+ : { code: 'megabytes-positive' };
1592
+ }
1593
+ checkWhole(errors, 'maxFilePages', this.pages(), 1, application?.maxFilePages);
1594
+ checkWhole(errors, 'maxFilesPerTurn', this.files(), 1, application?.maxFilesPerTurn);
1595
+ checkWhole(errors, 'maxFileTokensPerTurn', this.tokens(), 1, application?.maxFileTokensPerTurn);
1596
+ }
1597
+ /** The limits a save sends: none when the agent or skill accepts no files. */
1598
+ toRequest(acceptsFiles) {
1599
+ return {
1600
+ maxFileBytes: acceptsFiles ? this.bytes() : null,
1601
+ maxFilePages: acceptsFiles ? toNumber(this.pages()) : null,
1602
+ maxFilesPerTurn: acceptsFiles ? toNumber(this.files()) : null,
1603
+ maxFileTokensPerTurn: acceptsFiles ? toNumber(this.tokens()) : null
1604
+ };
1605
+ }
1606
+ bytes() {
1607
+ const text = this.megabytes().trim();
1608
+ if (text === '') {
1609
+ return null;
1610
+ }
1611
+ if (text === this.loadedMegabytes && this.loadedBytes !== null) {
1612
+ return this.loadedBytes;
1613
+ }
1614
+ const megabytes = Number(text.replace(',', '.'));
1615
+ return Number.isFinite(megabytes) ? Math.round(megabytes * bytesPerMegabyte) : null;
1616
+ }
1617
+ }
1502
1618
 
1503
1619
  const agentFlowSteps = ['works-on', 'when', 'skills', 'account', 'approval', 'results'];
1504
1620
  /** The most tools the flow lists before it counts the rest. */
@@ -1684,7 +1800,8 @@ const unavailableServerUses = new Set([
1684
1800
  /**
1685
1801
  * Whether the agent can be run now, by the rule the server applies to runs by hand: it is neither
1686
1802
  * stopped nor disabled in code, an agent created here has run settings, and the run catalog names
1687
- * what it runs on. A paused agent accepts the run, which waits until it is resumed.
1803
+ * what it runs on. A paused agent accepts the run, which waits until it is resumed; an agent that is
1804
+ * off runs it at once, because it only ignores the work it would take on by itself.
1688
1805
  */
1689
1806
  function flowRunNow(agent, configuration, catalog) {
1690
1807
  if (agent.runState === 'configured-off') {
@@ -2501,6 +2618,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
2501
2618
  args: [{ selector: 'nh-assistant-agent-work-setup', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent, _NhAssistantPickerComponent, NhAssistantAccountPickerComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"stack card\" data-work-setup [attr.aria-labelledby]=\"id + '-title'\">\n <header class=\"stack\">\n <h5 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.run-config.setup.title' | translate: { name: agentName() } }}</h5>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.setup.explain' | translate }}</p>\n <ol class=\"steps\" [attr.aria-label]=\"'nh-assistant.admin.run-config.setup.progress' | translate\">\n @for (item of steps; track item; let index = $index) {\n <li [class.done]=\"stepState(item) === 'done'\" [attr.aria-current]=\"stepState(item) === 'current' ? 'step' : null\">\n @if (stepState(item) === 'done') {\n <nh-assistant-icon name=\"check\" />\n }\n {{ index + 1 }}. {{ 'nh-assistant.admin.run-config.setup.step.' + item | translate }}\n </li>\n }\n </ol>\n </header>\n\n @if (done()) {\n <p class=\"message success\" role=\"status\" data-setup-done>{{ 'nh-assistant.admin.run-config.setup.done' | translate }}</p>\n } @else {\n <form class=\"stack\" novalidate (submit)=\"$event.preventDefault(); step() === 'review' ? save() : next()\">\n @switch (step()) {\n @case ('when') {\n <fieldset class=\"group\" data-step=\"when\">\n <legend tabindex=\"-1\">{{ 'nh-assistant.admin.run-config.setup.when.title' | translate }}</legend>\n <div class=\"choices\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.run-config.setup.when.title' | translate\">\n <label class=\"choice\" [class.selected]=\"source() === 'event'\">\n <input type=\"radio\" [name]=\"id + '-source'\" value=\"event\" [checked]=\"source() === 'event'\" (change)=\"setSource('event')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.triggers.source-event' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.source-event-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"choice\" [class.selected]=\"source() === 'schedule'\">\n <input type=\"radio\" [name]=\"id + '-source'\" value=\"schedule\" [checked]=\"source() === 'schedule'\" (change)=\"setSource('schedule')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.triggers.source-schedule' | translate }}</strong>\n <span class=\"muted\">{{ (offersApplication() ? 'nh-assistant.admin.run-config.triggers.source-schedule-application-hint' : 'nh-assistant.admin.run-config.triggers.source-schedule-hint') | translate }}</span>\n </span>\n </label>\n </div>\n @if (source() === 'event') {\n <div class=\"field\">\n <label [for]=\"id + '-event'\">{{ 'nh-assistant.admin.run-config.triggers.event' | translate }}</label>\n <nh-assistant-picker [inputId]=\"id + '-event'\" [options]=\"events()\" [value]=\"event()\"\n [placeholder]=\"'nh-assistant.admin.run-config.choose' | translate\"\n [invalid]=\"fieldError('event') !== null\"\n [describedBy]=\"describedBy(null, 'event', id + '-event-error')\"\n (valueChange)=\"event.set($event); touch('event')\" />\n @if (errorKey('event'); as key) {\n <p class=\"field-error\" [id]=\"id + '-event-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('event')?.params }}</p>\n }\n @if (events().length === 0) {\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.setup.no-events' | translate }}</p>\n }\n </div>\n } @else {\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-cron'\">{{ 'nh-assistant.admin.run-config.triggers.cron' | translate }}</label>\n <input type=\"text\" class=\"mono\" autocomplete=\"off\" maxlength=\"128\" [id]=\"id + '-cron'\" [value]=\"cron()\"\n [attr.aria-invalid]=\"fieldError('cron') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-cron-hint', 'cron', id + '-cron-error')\"\n (input)=\"cron.set(value($event)); touch('cron')\" />\n <p class=\"hint\" [id]=\"id + '-cron-hint'\">{{ 'nh-assistant.admin.run-config.triggers.cron-hint' | translate }}</p>\n <ul class=\"examples\" [attr.aria-label]=\"'nh-assistant.admin.run-config.triggers.examples' | translate\">\n @for (example of examples; track example.cron) {\n <li><button type=\"button\" (click)=\"useExample(example.cron)\">{{ 'nh-assistant.admin.run-config.triggers.example.' + example.key | translate }}</button></li>\n }\n </ul>\n @if (errorKey('cron'); as key) {\n <p class=\"field-error\" [id]=\"id + '-cron-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('cron')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-zone'\">{{ 'nh-assistant.admin.run-config.triggers.time-zone' | translate }}</label>\n <nh-assistant-picker [inputId]=\"id + '-zone'\" [options]=\"timeZones\" [value]=\"timeZone()\" [noneLabel]=\"'UTC'\"\n [invalid]=\"fieldError('timeZone') !== null\"\n [describedBy]=\"describedBy(null, 'timeZone', id + '-zone-error')\"\n (valueChange)=\"timeZone.set($event); touch('timeZone')\" />\n @if (errorKey('timeZone'); as key) {\n <p class=\"field-error\" [id]=\"id + '-zone-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('timeZone')?.params }}</p>\n }\n </div>\n </div>\n @if (offersApplication()) {\n <!-- An agent that works on the whole application chooses what the schedule runs for. -->\n <div class=\"field\" data-schedule-target>\n <span class=\"label\" [id]=\"id + '-target-label'\">{{ 'nh-assistant.admin.run-config.triggers.target.title' | translate }}</span>\n <div\n class=\"choices\"\n role=\"radiogroup\"\n tabindex=\"-1\"\n [attr.aria-labelledby]=\"id + '-target-label'\"\n [attr.aria-invalid]=\"target() === 'application' && fieldError('subjectSet') ? true : null\"\n [attr.aria-describedby]=\"target() === 'application' ? describedBy(null, 'subjectSet', id + '-target-error') : null\">\n <label class=\"choice\" [class.selected]=\"target() === 'application'\">\n <input type=\"radio\" [name]=\"id + '-target'\" value=\"application\" [checked]=\"target() === 'application'\" (change)=\"setTarget('application')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.triggers.target.application' | translate }}</strong>\n <span class=\"muted\" data-target-hint>{{ (perDivision() ? 'nh-assistant.admin.run-config.triggers.target.application-per-division-hint' : 'nh-assistant.admin.run-config.triggers.target.application-hint') | translate }}</span>\n </span>\n </label>\n <label class=\"choice\" [class.selected]=\"target() === 'set'\">\n <input type=\"radio\" [name]=\"id + '-target'\" value=\"set\" [checked]=\"target() === 'set'\" (change)=\"setTarget('set')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.triggers.target.set' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.target.set-hint' | translate }}</span>\n </span>\n </label>\n </div>\n @if (target() === 'application' && errorKey('subjectSet'); as key) {\n <p class=\"field-error\" [id]=\"id + '-target-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate }}</p>\n }\n </div>\n }\n @if (target() === 'set') {\n <div class=\"field\">\n <label [for]=\"id + '-set'\">{{ 'nh-assistant.admin.run-config.triggers.subject-set' | translate }}</label>\n <nh-assistant-picker [inputId]=\"id + '-set'\" [options]=\"subjectSets()\" [value]=\"subjectSet()\"\n [placeholder]=\"'nh-assistant.admin.run-config.choose' | translate\"\n [invalid]=\"fieldError('subjectSet') !== null\"\n [describedBy]=\"describedBy(id + '-set-hint', 'subjectSet', id + '-set-error')\"\n (valueChange)=\"subjectSet.set($event); touch('subjectSet')\" />\n <p class=\"hint\" [id]=\"id + '-set-hint'\">{{ 'nh-assistant.admin.run-config.triggers.subject-set-hint' | translate }}</p>\n @if (errorKey('subjectSet'); as key) {\n <p class=\"field-error\" [id]=\"id + '-set-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('subjectSet')?.params }}</p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-message'\">{{ 'nh-assistant.admin.run-config.triggers.message' | translate }}</label>\n <textarea rows=\"2\" [id]=\"id + '-message'\" [value]=\"message()\"\n [attr.aria-invalid]=\"fieldError('message') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-message-hint', 'message', id + '-message-error')\"\n (input)=\"message.set(value($event)); touch('message')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-message-hint'\">{{ 'nh-assistant.admin.run-config.triggers.message-hint' | translate }}</p>\n @if (errorKey('message'); as key) {\n <p class=\"field-error\" [id]=\"id + '-message-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('message')?.params }}</p>\n }\n </div>\n }\n </fieldset>\n }\n @case ('what') {\n <fieldset class=\"group\" data-step=\"what\">\n <legend tabindex=\"-1\">{{ 'nh-assistant.admin.run-config.setup.what.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.run-config.setup.what.name' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" maxlength=\"64\" [id]=\"id + '-name'\" [value]=\"name()\"\n [attr.aria-invalid]=\"fieldError('name') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-name-hint', 'name', id + '-name-error')\"\n (input)=\"name.set(value($event)); touch('name')\" />\n <p class=\"hint\" [id]=\"id + '-name-hint'\">\n {{ (skillId() ? 'nh-assistant.admin.run-config.setup.what.name-id' : 'nh-assistant.admin.run-config.setup.what.name-hint') | translate: { id: skillId() } }}\n </p>\n @if (errorKey('name'); as key) {\n <p class=\"field-error\" [id]=\"id + '-name-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('name')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-description'\">{{ 'nh-assistant.admin.run-config.skills.description-label' | translate }}</label>\n <input type=\"text\" [id]=\"id + '-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-description-hint', 'description', id + '-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\" />\n <p class=\"hint\" [id]=\"id + '-description-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.description-hint' | translate }}</span>\n <span class=\"counter\">{{ 'nh-assistant.admin.characters' | translate: { count: description().length, max: maxDescription } }}</span>\n </p>\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 + '-rules'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker [inputId]=\"id + '-rules'\" [options]=\"rules()\" [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-rules-hint', 'ruleHandler', id + '-rules-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler'); touch('instructions')\" />\n <p class=\"hint\" [id]=\"id + '-rules-hint'\">\n {{ (ruleHandler() ? 'nh-assistant.admin.run-config.skills.rules-hint' : 'nh-assistant.admin.run-config.skills.model-hint') | translate }}\n </p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-rules-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-instructions'\">{{ 'nh-assistant.admin.run-config.skills.instructions' | translate }}</label>\n <textarea rows=\"4\" [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'\">{{ 'nh-assistant.admin.run-config.skills.instructions-hint' | translate }} {{ 'nh-assistant.admin.run-config.skills.background-hint' | translate }}</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 <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.tools' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.skills.tools-hint' | translate }}</p>\n @for (choice of toolChoices(); track choice.selector) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"tools().includes(choice.selector)\" (change)=\"toggleTool(choice.selector, checked($event))\" />\n <span class=\"tool-choice\">\n <span class=\"mono\">{{ choice.selector }}</span>\n @if (choice.description) {\n <span class=\"muted block\">{{ choice.description }}</span>\n } @else if (choice.matches !== null) {\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.tools-pattern' | translate: { count: choice.matches } }}</span>\n }\n </span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n }\n @if (errorKey('tools'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('tools')?.params }}</p>\n }\n </fieldset>\n </fieldset>\n }\n @case ('who') {\n <fieldset class=\"group\" data-step=\"who\">\n <legend tabindex=\"-1\">{{ 'nh-assistant.admin.run-config.settings.who.title' | translate }}</legend>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.who.explain' | translate }}</p>\n <div class=\"choices\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.run-config.settings.who.title' | translate\">\n @for (option of accountabilities; track option) {\n <label class=\"choice\" [class.selected]=\"accountability() === option\">\n <input type=\"radio\" [name]=\"id + '-accountability'\" [value]=\"option\" [checked]=\"accountability() === option\" (change)=\"setAccountability(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.settings.accountability.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.accountability-explain.' + option | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (accountability() === 'service-account') {\n <div class=\"field\">\n <label [for]=\"id + '-account'\">{{ 'nh-assistant.admin.run-config.settings.service-account' | translate }}</label>\n <nh-assistant-account-picker [inputId]=\"id + '-account'\" [value]=\"serviceAccount()\" [searchable]=\"accountSearch()\"\n [invalid]=\"fieldError('serviceAccountActorId') !== null\"\n [describedBy]=\"describedBy(id + '-account-hint', 'serviceAccountActorId', id + '-account-error')\"\n (valueChange)=\"serviceAccount.set($event); touch('serviceAccountActorId')\" />\n <p class=\"hint\" [id]=\"id + '-account-hint'\">\n {{ (accountSearch() ? 'nh-assistant.admin.run-config.account.search-hint' : 'nh-assistant.admin.run-config.account.id-hint') | translate }}\n </p>\n @if (errorKey('serviceAccountActorId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-account-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('serviceAccountActorId')?.params }}</p>\n }\n </div>\n }\n @if (errorKey('accountability'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('accountability')?.params }}</p>\n }\n </fieldset>\n }\n @case ('limits') {\n <fieldset class=\"group\" data-step=\"limits\">\n <legend tabindex=\"-1\">{{ 'nh-assistant.admin.run-config.setup.limits.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker [inputId]=\"id + '-policy'\" [options]=\"policies()\" [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.approval.default' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(id + '-policy-hint', 'approvalPolicy', id + '-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.run-config.settings.approval.hint' | translate }}</p>\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-run-tokens'\" [value]=\"maxTokensPerRun()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-run-tokens-error')\"\n (input)=\"maxTokensPerRun.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-run-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-daily-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n }\n @case ('review') {\n <fieldset class=\"group\" data-step=\"review\">\n <legend tabindex=\"-1\">{{ 'nh-assistant.admin.run-config.setup.review.title' | translate }}</legend>\n <dl class=\"review\">\n <dt>{{ 'nh-assistant.admin.run-config.setup.step.when' | translate }}</dt>\n <dd>\n @if (source() === 'event') {\n {{ 'nh-assistant.admin.run-config.setup.review.event' | translate: { event: event() } }}\n @if (eventDescription(); as description) { <span class=\"muted block\">{{ description }}</span> }\n } @else if (target() === 'application') {\n <!-- Without a subject set the schedule runs for the whole application, per division for a per-division agent. -->\n <span data-review-target>{{ (perDivision() ? 'nh-assistant.admin.run-config.setup.review.schedule-divisions' : 'nh-assistant.admin.run-config.setup.review.schedule-application') | translate: { cron: cron(), zone: timeZone() || 'UTC' } }}</span>\n } @else {\n {{ 'nh-assistant.admin.run-config.setup.review.schedule' | translate: { cron: cron(), zone: timeZone() || 'UTC', set: subjectSet() } }}\n @if (subjectSetDescription(); as description) { <span class=\"muted block\">{{ description }}</span> }\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.run-config.setup.step.what' | translate }}</dt>\n <dd>\n <strong>{{ name() }}</strong> <span class=\"mono\">({{ skillId() }})</span>\n <span class=\"block\">{{ description() }}</span>\n <span class=\"muted block\">\n {{ ruleHandler() ? ruleHandler() + (ruleDescription() ? ' \u2014 ' + ruleDescription() : '') : ('nh-assistant.admin.run-config.model' | translate) }}\n </span>\n </dd>\n <dt>{{ 'nh-assistant.admin.run-config.setup.step.who' | translate }}</dt>\n <dd>{{ 'nh-assistant.admin.run-config.settings.accountability.' + accountability() | translate }}</dd>\n <dt>{{ 'nh-assistant.admin.run-config.setup.step.limits' | translate }}</dt>\n <dd>\n {{ approvalPolicy() || ('nh-assistant.admin.run-config.settings.approval.default' | translate) }}\n @if (policyDescription(); as description) { <span class=\"muted block\">{{ description }}</span> }\n </dd>\n </dl>\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.setup.review.shadow' | translate }}</p>\n </fieldset>\n }\n }\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 </div>\n </div>\n }\n <div class=\"actions\">\n <button class=\"secondary\" type=\"button\" (click)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n @if (stepIndex() > 0) {\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"back()\">{{ 'nh-assistant.admin.run-config.setup.back' | translate }}</button>\n }\n @if (step() === 'review') {\n <button class=\"secondary\" type=\"button\" data-setup-live [disabled]=\"busy()\" (click)=\"save(true)\">{{ 'nh-assistant.admin.run-config.setup.save-live' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.run-config.setup.save-shadow') | translate }}</button>\n } @else {\n <button class=\"primary\" type=\"submit\">{{ 'nh-assistant.admin.run-config.setup.next' | translate }}</button>\n }\n </div>\n </form>\n }\n</section>\n", styles: [":host{--nha-font: var(--nh-assistant-font, inherit);--nha-background: var(--nh-assistant-background, #ffffff);--nha-surface: var(--nh-assistant-surface, #f5f7fb);--nha-surface-strong: var(--nh-assistant-surface-strong, #eceff6);--nha-text: var(--nh-assistant-text, #080c1d);--nha-text-muted: var(--nh-assistant-text-muted, #5b6482);--nha-border: var(--nh-assistant-border, #dce0ec);--nha-accent: var(--nh-assistant-accent, #022962);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #c84f00);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #247d4e);--nha-success-soft: var(--nh-assistant-success-soft, #e6f5ec);--nha-warning: var(--nh-assistant-warning, #8a5a00);--nha-warning-soft: var(--nh-assistant-warning-soft, #fff3d9);--nha-danger: var(--nh-assistant-danger, #b92e52);--nha-danger-soft: var(--nh-assistant-danger-soft, #ffe9ef);--nha-focus: var(--nh-assistant-focus, #ff6700);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(2 41 98 / .16));--nha-radius: var(--nh-assistant-radius, 16px);--nha-radius-control: var(--nh-assistant-radius-control, 12px);--nha-mono: var(--nh-assistant-font-mono, ui-monospace, \"Cascadia Code\", Consolas, monospace)}@media(prefers-color-scheme:dark){:host{--nha-background: var(--nh-assistant-background, #0b0e22);--nha-surface: var(--nh-assistant-surface, #11152d);--nha-surface-strong: var(--nh-assistant-surface-strong, #181d3b);--nha-text: var(--nh-assistant-text, #ffffff);--nha-text-muted: var(--nh-assistant-text-muted, #b8bed8);--nha-border: var(--nh-assistant-border, #2b3155);--nha-accent: var(--nh-assistant-accent, #0f4087);--nha-accent-contrast: var(--nh-assistant-accent-contrast, #ffffff);--nha-highlight: var(--nh-assistant-highlight, #ff6700);--nha-user-bubble: var(--nh-assistant-user-bubble, #022962);--nha-user-text: var(--nh-assistant-user-text, #ffffff);--nha-success: var(--nh-assistant-success, #67c58f);--nha-success-soft: var(--nh-assistant-success-soft, #102d24);--nha-warning: var(--nh-assistant-warning, #ffbf5b);--nha-warning-soft: var(--nh-assistant-warning-soft, #342818);--nha-danger: var(--nh-assistant-danger, #ff6d8a);--nha-danger-soft: var(--nh-assistant-danger-soft, #351b2a);--nha-shadow: var(--nh-assistant-shadow, 0 16px 36px rgb(0 0 0 / .32))}}:host{display: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}\n"] }]
2502
2619
  }], propDecorators: { agentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "agentId", required: true }] }], agentName: [{ type: i0.Input, args: [{ isSignal: true, alias: "agentName", required: false }] }], catalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalog", required: false }] }], worksOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "worksOn", required: false }] }], toolSelectors: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolSelectors", required: false }] }], toolCatalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCatalog", required: false }] }], takenSkillIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "takenSkillIds", required: false }] }], takenTriggerIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "takenTriggerIds", required: false }] }], completed: [{ type: i0.Output, args: ["completed"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
2503
2620
 
2621
+ const controls = {
2622
+ maxFileBytes: { field: 'maxFileBytes', key: 'file-size', label: 'max-file-megabytes', step: 'any', inputMode: 'decimal' },
2623
+ maxFilePages: { field: 'maxFilePages', key: 'file-pages', label: 'max-file-pages', step: '1', inputMode: 'numeric' },
2624
+ maxFilesPerTurn: { field: 'maxFilesPerTurn', key: 'files-per-turn', label: 'max-files-per-turn', step: '1', inputMode: 'numeric' },
2625
+ maxFileTokensPerTurn: { field: 'maxFileTokensPerTurn', key: 'file-tokens', label: 'max-file-tokens-per-turn', step: '1', inputMode: 'numeric' }
2626
+ };
2627
+ /**
2628
+ * The lower file limits of an agent or a skill that accepts files, next to its "Accepts files"
2629
+ * switch: the largest file in megabytes, the most pages of one file, the most files of one turn and
2630
+ * the most file tokens of one turn. Each field names the application's limit, which it can only
2631
+ * lower; an empty field keeps it. Errors appear at their fields with the form's other errors.
2632
+ */
2633
+ class NhAssistantFileLimitsFieldsComponent {
2634
+ constructor() {
2635
+ /** The form's limits. */
2636
+ this.draft = input.required(...(ngDevMode ? [{ debugName: "draft" }] : []));
2637
+ /** The application's limits from the run catalog; `null` on older servers. */
2638
+ this.application = input(null, ...(ngDevMode ? [{ debugName: "application" }] : []));
2639
+ /** The form's field errors, by server field name. */
2640
+ this.errors = input({}, ...(ngDevMode ? [{ debugName: "errors" }] : []));
2641
+ /** The prefix of the controls' ids. */
2642
+ this.idPrefix = input.required(...(ngDevMode ? [{ debugName: "idPrefix" }] : []));
2643
+ /** The hint under the title: what an empty field keeps. */
2644
+ this.hintKey = input.required(...(ngDevMode ? [{ debugName: "hintKey" }] : []));
2645
+ /** A field the administrator changed, so the form clears its error. */
2646
+ this.touched = output();
2647
+ this.controls = fileLimitFields.map(field => controls[field]);
2648
+ }
2649
+ idOf(control, suffix = '') {
2650
+ return `${this.idPrefix()}-${control.key}${suffix}`;
2651
+ }
2652
+ /** The application's limit as the field shows it: megabytes for the file size. */
2653
+ applicationLimit(control) {
2654
+ const application = this.application();
2655
+ if (!application) {
2656
+ return null;
2657
+ }
2658
+ const value = application[control.field];
2659
+ return control.field === 'maxFileBytes' ? `${megabytesText(value)} MB` : String(value);
2660
+ }
2661
+ /** The upper bound a browser shows for the field. */
2662
+ max(control) {
2663
+ const application = this.application();
2664
+ if (!application) {
2665
+ return null;
2666
+ }
2667
+ return control.field === 'maxFileBytes' ? application.maxFileBytes / (1024 * 1024) : application[control.field];
2668
+ }
2669
+ errorKey(control) {
2670
+ return fieldErrorKey(this.errors()[control.field]);
2671
+ }
2672
+ errorParams(control) {
2673
+ return this.errors()[control.field]?.params;
2674
+ }
2675
+ describedBy(control) {
2676
+ const ids = [`${this.idPrefix()}-file-limits-hint`];
2677
+ if (this.application()) {
2678
+ ids.push(this.idOf(control, '-limit'));
2679
+ }
2680
+ if (this.errors()[control.field]) {
2681
+ ids.push(this.idOf(control, '-error'));
2682
+ }
2683
+ return ids.join(' ');
2684
+ }
2685
+ change(control, event) {
2686
+ this.draft().text(control.field).set(event.target.value);
2687
+ this.touched.emit(control.field);
2688
+ }
2689
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantFileLimitsFieldsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2690
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantFileLimitsFieldsComponent, isStandalone: true, selector: "nh-assistant-file-limits-fields", inputs: { draft: { classPropertyName: "draft", publicName: "draft", isSignal: true, isRequired: true, transformFunction: null }, application: { classPropertyName: "application", publicName: "application", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, idPrefix: { classPropertyName: "idPrefix", publicName: "idPrefix", isSignal: true, isRequired: true, transformFunction: null }, hintKey: { classPropertyName: "hintKey", publicName: "hintKey", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { touched: "touched" }, ngImport: i0, template: "<fieldset class=\"field file-limits\" data-file-limits>\n <legend>{{ 'nh-assistant.admin.run-config.files.limits-title' | translate }}</legend>\n <p class=\"hint\" [id]=\"idPrefix() + '-file-limits-hint'\">{{ hintKey() | translate }}</p>\n <div class=\"grid\">\n @for (control of controls; track control.field) {\n <div class=\"field\" [attr.data-file-limit]=\"control.field\">\n <label [for]=\"idOf(control)\">{{ 'nh-assistant.admin.run-config.files.' + control.label | translate }}</label>\n <input type=\"number\" min=\"0\" [attr.step]=\"control.step\" [attr.max]=\"max(control)\" [attr.inputmode]=\"control.inputMode\"\n [id]=\"idOf(control)\" [value]=\"draft().text(control.field)()\"\n [attr.aria-invalid]=\"errorKey(control) ? true : null\"\n [attr.aria-describedby]=\"describedBy(control)\"\n (input)=\"change(control, $event)\" />\n @if (applicationLimit(control); as limit) {\n <p class=\"hint\" [id]=\"idOf(control, '-limit')\">{{ 'nh-assistant.admin.run-config.files.application-limit' | translate: { value: limit } }}</p>\n }\n @if (errorKey(control); as key) {\n <p class=\"field-error\" [id]=\"idOf(control, '-error')\"><nh-assistant-icon name=\"warning\" />{{ key | translate: errorParams(control) }}</p>\n }\n </div>\n }\n </div>\n</fieldset>\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2691
+ }
2692
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantFileLimitsFieldsComponent, decorators: [{
2693
+ type: Component,
2694
+ args: [{ selector: 'nh-assistant-file-limits-fields', standalone: true, imports: [TranslatePipe, _NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"field file-limits\" data-file-limits>\n <legend>{{ 'nh-assistant.admin.run-config.files.limits-title' | translate }}</legend>\n <p class=\"hint\" [id]=\"idPrefix() + '-file-limits-hint'\">{{ hintKey() | translate }}</p>\n <div class=\"grid\">\n @for (control of controls; track control.field) {\n <div class=\"field\" [attr.data-file-limit]=\"control.field\">\n <label [for]=\"idOf(control)\">{{ 'nh-assistant.admin.run-config.files.' + control.label | translate }}</label>\n <input type=\"number\" min=\"0\" [attr.step]=\"control.step\" [attr.max]=\"max(control)\" [attr.inputmode]=\"control.inputMode\"\n [id]=\"idOf(control)\" [value]=\"draft().text(control.field)()\"\n [attr.aria-invalid]=\"errorKey(control) ? true : null\"\n [attr.aria-describedby]=\"describedBy(control)\"\n (input)=\"change(control, $event)\" />\n @if (applicationLimit(control); as limit) {\n <p class=\"hint\" [id]=\"idOf(control, '-limit')\">{{ 'nh-assistant.admin.run-config.files.application-limit' | translate: { value: limit } }}</p>\n }\n @if (errorKey(control); as key) {\n <p class=\"field-error\" [id]=\"idOf(control, '-error')\"><nh-assistant-icon name=\"warning\" />{{ key | translate: errorParams(control) }}</p>\n }\n </div>\n }\n </div>\n</fieldset>\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}\n"] }]
2695
+ }], propDecorators: { draft: [{ type: i0.Input, args: [{ isSignal: true, alias: "draft", required: true }] }], application: [{ type: i0.Input, args: [{ isSignal: true, alias: "application", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], idPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "idPrefix", required: true }] }], hintKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintKey", required: true }] }], touched: [{ type: i0.Output, args: ["touched"] }] } });
2696
+
2504
2697
  let nextId$8 = 0;
2505
2698
  const defaults = { retries: '3', concurrent: '4', perSubject: '10' };
2506
2699
  /**
@@ -2525,7 +2718,7 @@ class NhAssistantRunSettingsFormComponent extends RunConfigForm {
2525
2718
  this.fields = [
2526
2719
  'accountability', 'serviceAccountActorId', 'ruleHandler', 'approvalPolicy', 'triageProfile', 'retryCount',
2527
2720
  'maxConcurrentRuns', 'maxRunsPerSubjectPerDay', 'maxTokensPerRun', 'dailyToolCalls', 'dailyTokens',
2528
- 'elevatedReads', 'allowGatewayReads', 'reason'
2721
+ 'elevatedReads', 'allowGatewayReads', 'reason', 'maxFileBytes', 'maxFilePages', 'maxFilesPerTurn', 'maxFileTokensPerTurn'
2529
2722
  ];
2530
2723
  this.accountability = signal('service-account', ...(ngDevMode ? [{ debugName: "accountability" }] : []));
2531
2724
  this.serviceAccount = signal('', ...(ngDevMode ? [{ debugName: "serviceAccount" }] : []));
@@ -2540,6 +2733,10 @@ class NhAssistantRunSettingsFormComponent extends RunConfigForm {
2540
2733
  this.dailyTokens = signal('', ...(ngDevMode ? [{ debugName: "dailyTokens" }] : []));
2541
2734
  this.allowGatewayReads = signal(false, ...(ngDevMode ? [{ debugName: "allowGatewayReads" }] : []));
2542
2735
  this.delegateFromInitiator = signal(false, ...(ngDevMode ? [{ debugName: "delegateFromInitiator" }] : []));
2736
+ /** Whether people's messages and the agent's tools may give it files; off for a new agent. */
2737
+ this.acceptsFiles = signal(false, ...(ngDevMode ? [{ debugName: "acceptsFiles" }] : []));
2738
+ /** The agent's lower file limits, next to accepting files; empty keeps the application's. */
2739
+ this.fileLimits = new FileLimitsDraft();
2543
2740
  this.elevatedReads = signal('restricted', ...(ngDevMode ? [{ debugName: "elevatedReads" }] : []));
2544
2741
  this.reason = signal('', ...(ngDevMode ? [{ debugName: "reason" }] : []));
2545
2742
  this.advancedOpen = signal(false, ...(ngDevMode ? [{ debugName: "advancedOpen" }] : []));
@@ -2577,6 +2774,8 @@ class NhAssistantRunSettingsFormComponent extends RunConfigForm {
2577
2774
  this.dailyTokens.set(numberText(settings?.dailyTokens));
2578
2775
  this.allowGatewayReads.set(settings?.allowGatewayReads ?? false);
2579
2776
  this.delegateFromInitiator.set(settings?.delegateFromInitiator ?? false);
2777
+ this.acceptsFiles.set(settings?.acceptsFiles ?? false);
2778
+ this.fileLimits.load(settings);
2580
2779
  this.elevatedReads.set(settings?.elevatedReads ?? 'restricted');
2581
2780
  this.advancedOpen.set(this.advancedInUse());
2582
2781
  }
@@ -2595,6 +2794,9 @@ class NhAssistantRunSettingsFormComponent extends RunConfigForm {
2595
2794
  checkWhole(errors, 'maxRunsPerSubjectPerDay', this.maxRunsPerSubjectPerDay(), ...runConfigLimits.perSubject, true);
2596
2795
  checkWhole(errors, 'maxTokensPerRun', this.maxTokensPerRun(), 1);
2597
2796
  checkBudget(errors, this.dailyToolCalls(), this.dailyTokens());
2797
+ if (this.acceptsFiles()) {
2798
+ this.fileLimits.check(errors, this.catalog()?.fileLimits);
2799
+ }
2598
2800
  const request = {
2599
2801
  accountability: this.accountability(),
2600
2802
  serviceAccountActorId: this.accountability() === 'service-account' ? blank$1(this.serviceAccount()) : null,
@@ -2611,7 +2813,9 @@ class NhAssistantRunSettingsFormComponent extends RunConfigForm {
2611
2813
  triageProfile: blank$1(this.triageProfile()),
2612
2814
  ruleHandler: blank$1(this.ruleHandler()),
2613
2815
  expectedVersion: this.settings()?.version ?? null,
2614
- reason: blank$1(this.reason())
2816
+ reason: blank$1(this.reason()),
2817
+ acceptsFiles: this.acceptsFiles(),
2818
+ ...this.fileLimits.toRequest(this.acceptsFiles())
2615
2819
  };
2616
2820
  this.submit(errors, () => this.admin.saveRunSettings(this.agentId(), request), settings => this.saved.emit(settings));
2617
2821
  }
@@ -2619,11 +2823,18 @@ class NhAssistantRunSettingsFormComponent extends RunConfigForm {
2619
2823
  return withBudgetField(errors, this.dailyToolCalls());
2620
2824
  }
2621
2825
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantRunSettingsFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2622
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantRunSettingsFormComponent, isStandalone: true, selector: "nh-assistant-run-settings-form", inputs: { agentId: { classPropertyName: "agentId", publicName: "agentId", isSignal: true, isRequired: true, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, usesInheritance: true, ngImport: i0, template: "<form class=\"stack card\" data-form=\"settings\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>{{ (settings() ? 'nh-assistant.admin.run-config.settings.edit-title' : 'nh-assistant.admin.run-config.settings.add-title') | translate }}</h5>\n\n <fieldset class=\"group\" [attr.aria-describedby]=\"id + '-who-explain'\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.who.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-who-explain'\">{{ 'nh-assistant.admin.run-config.settings.who.explain' | translate }}</p>\n <div class=\"choices\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.run-config.settings.who.title' | translate\">\n @for (option of accountabilities; track option) {\n <label class=\"choice\" [class.selected]=\"accountability() === option\">\n <input type=\"radio\" [name]=\"id + '-accountability'\" [value]=\"option\" [checked]=\"accountability() === option\" (change)=\"setAccountability(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.settings.accountability.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.accountability-explain.' + option | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (errorKey('accountability'); as key) {\n <p class=\"field-error\" [id]=\"id + '-accountability-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('accountability')?.params }}</p>\n }\n @if (accountability() === 'service-account') {\n <div class=\"field\">\n <label [for]=\"id + '-service-account'\">{{ 'nh-assistant.admin.run-config.settings.service-account' | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-service-account'\"\n [value]=\"serviceAccount()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"fieldError('serviceAccountActorId') !== null\"\n [describedBy]=\"describedBy(id + '-service-account-hint', 'serviceAccountActorId', id + '-service-account-error')\"\n (valueChange)=\"serviceAccount.set($event); touch('serviceAccountActorId')\" />\n <p class=\"hint\" [id]=\"id + '-service-account-hint'\">\n {{ (accountSearch() ? 'nh-assistant.admin.run-config.account.search-hint' : 'nh-assistant.admin.run-config.account.id-hint') | translate }}\n </p>\n @if (errorKey('serviceAccountActorId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-service-account-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('serviceAccountActorId')?.params }}</p>\n }\n </div>\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-rule-handler'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-rule-handler'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-rule-handler-hint', 'ruleHandler', id + '-rule-handler-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-rule-handler-hint'\">{{ 'nh-assistant.admin.run-config.settings.how.hint' | translate }}</p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-rule-handler-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.approval.default' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(id + '-policy-hint', 'approvalPolicy', id + '-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.run-config.settings.approval.hint' | translate }}</p>\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-run-tokens'\" [value]=\"maxTokensPerRun()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-run-tokens-error')\"\n (input)=\"maxTokensPerRun.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-run-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-daily-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n <details class=\"advanced\" data-advanced [open]=\"advancedOpen() || advancedHasErrors()\" (toggle)=\"advancedOpen.set($any($event.target).open)\">\n <summary>{{ 'nh-assistant.admin.run-config.advanced.title' | translate }}</summary>\n <div class=\"stack\">\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.advanced.explain' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-retries'\">{{ 'nh-assistant.admin.run-config.settings.retries' | translate }}</label>\n <input type=\"number\" min=\"0\" max=\"10\" inputmode=\"numeric\" [id]=\"id + '-retries'\" [value]=\"retryCount()\"\n [attr.aria-invalid]=\"fieldError('retryCount') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-retries-hint', 'retryCount', id + '-retries-error')\"\n (input)=\"retryCount.set(value($event)); touch('retryCount')\" />\n <p class=\"hint\" [id]=\"id + '-retries-hint'\">{{ 'nh-assistant.admin.run-config.settings.retries-hint' | translate }}</p>\n @if (errorKey('retryCount'); as key) {\n <p class=\"field-error\" [id]=\"id + '-retries-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('retryCount')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-concurrent'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"100\" inputmode=\"numeric\" [id]=\"id + '-concurrent'\" [value]=\"maxConcurrentRuns()\"\n [attr.aria-invalid]=\"fieldError('maxConcurrentRuns') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-concurrent-hint', 'maxConcurrentRuns', id + '-concurrent-error')\"\n (input)=\"maxConcurrentRuns.set(value($event)); touch('maxConcurrentRuns')\" />\n <p class=\"hint\" [id]=\"id + '-concurrent-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent-hint' | translate }}</p>\n @if (errorKey('maxConcurrentRuns'); as key) {\n <p class=\"field-error\" [id]=\"id + '-concurrent-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxConcurrentRuns')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-per-subject'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"1000\" inputmode=\"numeric\" [id]=\"id + '-per-subject'\" [value]=\"maxRunsPerSubjectPerDay()\"\n [attr.aria-invalid]=\"fieldError('maxRunsPerSubjectPerDay') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-per-subject-hint', 'maxRunsPerSubjectPerDay', id + '-per-subject-error')\"\n (input)=\"maxRunsPerSubjectPerDay.set(value($event)); touch('maxRunsPerSubjectPerDay')\" />\n <p class=\"hint\" [id]=\"id + '-per-subject-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject-hint' | translate }}</p>\n @if (errorKey('maxRunsPerSubjectPerDay'); as key) {\n <p class=\"field-error\" [id]=\"id + '-per-subject-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxRunsPerSubjectPerDay')?.params }}</p>\n }\n </div>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-triage'\">{{ 'nh-assistant.admin.run-config.settings.triage' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-triage'\"\n [options]=\"profiles()\"\n [value]=\"triageProfile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.no-triage' | translate\"\n [invalid]=\"fieldError('triageProfile') !== null\"\n [describedBy]=\"describedBy(id + '-triage-hint', 'triageProfile', id + '-triage-error')\"\n (valueChange)=\"triageProfile.set($event); touch('triageProfile')\" />\n <p class=\"hint\" [id]=\"id + '-triage-hint'\">{{ 'nh-assistant.admin.run-config.settings.triage-hint' | translate }}</p>\n @if (errorKey('triageProfile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-triage-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('triageProfile')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.elevated-reads' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.settings.elevated-reads-hint' | translate }}</p>\n @for (mode of elevatedReadModes; track mode) {\n <label class=\"check\">\n <input type=\"radio\" [name]=\"id + '-elevated'\" [value]=\"mode\" [checked]=\"elevatedReads() === mode\" (change)=\"elevatedReads.set(mode); touch('elevatedReads')\" />\n <span>{{ 'nh-assistant.admin.run-config.settings.elevated.' + mode | translate }}</span>\n </label>\n }\n @if (errorKey('elevatedReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('elevatedReads')?.params }}</p>\n }\n </fieldset>\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"allowGatewayReads()\" [attr.aria-invalid]=\"fieldError('allowGatewayReads') ? true : null\" (change)=\"allowGatewayReads.set(checked($event)); touch('allowGatewayReads')\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.gateway-reads' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.gateway-reads-hint' | translate }}</span>\n </span>\n </label>\n @if (errorKey('allowGatewayReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('allowGatewayReads')?.params }}</p>\n }\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"delegateFromInitiator()\" (change)=\"delegateFromInitiator.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.delegate' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.delegate-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </details>\n\n <div class=\"field\">\n <label [for]=\"id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: _NhAssistantPickerComponent, selector: "nh-assistant-picker", inputs: ["inputId", "options", "value", "selectedLabel", "noneLabel", "placeholder", "search", "minQueryLength", "invalid", "describedBy", "disabled"], outputs: ["valueChange", "optionChange"] }, { kind: "component", type: NhAssistantAccountPickerComponent, selector: "nh-assistant-account-picker", inputs: ["inputId", "value", "searchable", "invalid", "describedBy"], outputs: ["valueChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2826
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantRunSettingsFormComponent, isStandalone: true, selector: "nh-assistant-run-settings-form", inputs: { agentId: { classPropertyName: "agentId", publicName: "agentId", isSignal: true, isRequired: true, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, usesInheritance: true, ngImport: i0, template: "<form class=\"stack card\" data-form=\"settings\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>{{ (settings() ? 'nh-assistant.admin.run-config.settings.edit-title' : 'nh-assistant.admin.run-config.settings.add-title') | translate }}</h5>\n\n <fieldset class=\"group\" [attr.aria-describedby]=\"id + '-who-explain'\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.who.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-who-explain'\">{{ 'nh-assistant.admin.run-config.settings.who.explain' | translate }}</p>\n <div class=\"choices\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.run-config.settings.who.title' | translate\">\n @for (option of accountabilities; track option) {\n <label class=\"choice\" [class.selected]=\"accountability() === option\">\n <input type=\"radio\" [name]=\"id + '-accountability'\" [value]=\"option\" [checked]=\"accountability() === option\" (change)=\"setAccountability(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.settings.accountability.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.accountability-explain.' + option | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (errorKey('accountability'); as key) {\n <p class=\"field-error\" [id]=\"id + '-accountability-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('accountability')?.params }}</p>\n }\n @if (accountability() === 'service-account') {\n <div class=\"field\">\n <label [for]=\"id + '-service-account'\">{{ 'nh-assistant.admin.run-config.settings.service-account' | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-service-account'\"\n [value]=\"serviceAccount()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"fieldError('serviceAccountActorId') !== null\"\n [describedBy]=\"describedBy(id + '-service-account-hint', 'serviceAccountActorId', id + '-service-account-error')\"\n (valueChange)=\"serviceAccount.set($event); touch('serviceAccountActorId')\" />\n <p class=\"hint\" [id]=\"id + '-service-account-hint'\">\n {{ (accountSearch() ? 'nh-assistant.admin.run-config.account.search-hint' : 'nh-assistant.admin.run-config.account.id-hint') | translate }}\n </p>\n @if (errorKey('serviceAccountActorId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-service-account-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('serviceAccountActorId')?.params }}</p>\n }\n </div>\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-rule-handler'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-rule-handler'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-rule-handler-hint', 'ruleHandler', id + '-rule-handler-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-rule-handler-hint'\">{{ 'nh-assistant.admin.run-config.settings.how.hint' | translate }}</p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-rule-handler-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <label class=\"check\" data-accepts-files>\n <input type=\"checkbox\" [checked]=\"acceptsFiles()\" (change)=\"acceptsFiles.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.files.label' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.files.agent-hint' | translate }}</span>\n </span>\n </label>\n @if (acceptsFiles()) {\n <nh-assistant-file-limits-fields\n [draft]=\"fileLimits\"\n [application]=\"catalog()?.fileLimits\"\n [errors]=\"fieldErrors()\"\n [idPrefix]=\"id\"\n hintKey=\"nh-assistant.admin.run-config.files.agent-limits-hint\"\n (touched)=\"touch($event)\" />\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.approval.default' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(id + '-policy-hint', 'approvalPolicy', id + '-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.run-config.settings.approval.hint' | translate }}</p>\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-run-tokens'\" [value]=\"maxTokensPerRun()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-run-tokens-error')\"\n (input)=\"maxTokensPerRun.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-run-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-daily-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n <details class=\"advanced\" data-advanced [open]=\"advancedOpen() || advancedHasErrors()\" (toggle)=\"advancedOpen.set($any($event.target).open)\">\n <summary>{{ 'nh-assistant.admin.run-config.advanced.title' | translate }}</summary>\n <div class=\"stack\">\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.advanced.explain' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-retries'\">{{ 'nh-assistant.admin.run-config.settings.retries' | translate }}</label>\n <input type=\"number\" min=\"0\" max=\"10\" inputmode=\"numeric\" [id]=\"id + '-retries'\" [value]=\"retryCount()\"\n [attr.aria-invalid]=\"fieldError('retryCount') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-retries-hint', 'retryCount', id + '-retries-error')\"\n (input)=\"retryCount.set(value($event)); touch('retryCount')\" />\n <p class=\"hint\" [id]=\"id + '-retries-hint'\">{{ 'nh-assistant.admin.run-config.settings.retries-hint' | translate }}</p>\n @if (errorKey('retryCount'); as key) {\n <p class=\"field-error\" [id]=\"id + '-retries-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('retryCount')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-concurrent'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"100\" inputmode=\"numeric\" [id]=\"id + '-concurrent'\" [value]=\"maxConcurrentRuns()\"\n [attr.aria-invalid]=\"fieldError('maxConcurrentRuns') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-concurrent-hint', 'maxConcurrentRuns', id + '-concurrent-error')\"\n (input)=\"maxConcurrentRuns.set(value($event)); touch('maxConcurrentRuns')\" />\n <p class=\"hint\" [id]=\"id + '-concurrent-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent-hint' | translate }}</p>\n @if (errorKey('maxConcurrentRuns'); as key) {\n <p class=\"field-error\" [id]=\"id + '-concurrent-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxConcurrentRuns')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-per-subject'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"1000\" inputmode=\"numeric\" [id]=\"id + '-per-subject'\" [value]=\"maxRunsPerSubjectPerDay()\"\n [attr.aria-invalid]=\"fieldError('maxRunsPerSubjectPerDay') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-per-subject-hint', 'maxRunsPerSubjectPerDay', id + '-per-subject-error')\"\n (input)=\"maxRunsPerSubjectPerDay.set(value($event)); touch('maxRunsPerSubjectPerDay')\" />\n <p class=\"hint\" [id]=\"id + '-per-subject-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject-hint' | translate }}</p>\n @if (errorKey('maxRunsPerSubjectPerDay'); as key) {\n <p class=\"field-error\" [id]=\"id + '-per-subject-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxRunsPerSubjectPerDay')?.params }}</p>\n }\n </div>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-triage'\">{{ 'nh-assistant.admin.run-config.settings.triage' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-triage'\"\n [options]=\"profiles()\"\n [value]=\"triageProfile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.no-triage' | translate\"\n [invalid]=\"fieldError('triageProfile') !== null\"\n [describedBy]=\"describedBy(id + '-triage-hint', 'triageProfile', id + '-triage-error')\"\n (valueChange)=\"triageProfile.set($event); touch('triageProfile')\" />\n <p class=\"hint\" [id]=\"id + '-triage-hint'\">{{ 'nh-assistant.admin.run-config.settings.triage-hint' | translate }}</p>\n @if (errorKey('triageProfile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-triage-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('triageProfile')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.elevated-reads' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.settings.elevated-reads-hint' | translate }}</p>\n @for (mode of elevatedReadModes; track mode) {\n <label class=\"check\">\n <input type=\"radio\" [name]=\"id + '-elevated'\" [value]=\"mode\" [checked]=\"elevatedReads() === mode\" (change)=\"elevatedReads.set(mode); touch('elevatedReads')\" />\n <span>{{ 'nh-assistant.admin.run-config.settings.elevated.' + mode | translate }}</span>\n </label>\n }\n @if (errorKey('elevatedReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('elevatedReads')?.params }}</p>\n }\n </fieldset>\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"allowGatewayReads()\" [attr.aria-invalid]=\"fieldError('allowGatewayReads') ? true : null\" (change)=\"allowGatewayReads.set(checked($event)); touch('allowGatewayReads')\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.gateway-reads' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.gateway-reads-hint' | translate }}</span>\n </span>\n </label>\n @if (errorKey('allowGatewayReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('allowGatewayReads')?.params }}</p>\n }\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"delegateFromInitiator()\" (change)=\"delegateFromInitiator.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.delegate' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.delegate-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </details>\n\n <div class=\"field\">\n <label [for]=\"id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: _NhAssistantPickerComponent, selector: "nh-assistant-picker", inputs: ["inputId", "options", "value", "selectedLabel", "noneLabel", "placeholder", "search", "minQueryLength", "invalid", "describedBy", "disabled"], outputs: ["valueChange", "optionChange"] }, { kind: "component", type: NhAssistantAccountPickerComponent, selector: "nh-assistant-account-picker", inputs: ["inputId", "value", "searchable", "invalid", "describedBy"], outputs: ["valueChange"] }, { kind: "component", type: NhAssistantFileLimitsFieldsComponent, selector: "nh-assistant-file-limits-fields", inputs: ["draft", "application", "errors", "idPrefix", "hintKey"], outputs: ["touched"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2623
2827
  }
2624
2828
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantRunSettingsFormComponent, decorators: [{
2625
2829
  type: Component,
2626
- args: [{ selector: 'nh-assistant-run-settings-form', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent, _NhAssistantPickerComponent, NhAssistantAccountPickerComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"stack card\" data-form=\"settings\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>{{ (settings() ? 'nh-assistant.admin.run-config.settings.edit-title' : 'nh-assistant.admin.run-config.settings.add-title') | translate }}</h5>\n\n <fieldset class=\"group\" [attr.aria-describedby]=\"id + '-who-explain'\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.who.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-who-explain'\">{{ 'nh-assistant.admin.run-config.settings.who.explain' | translate }}</p>\n <div class=\"choices\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.run-config.settings.who.title' | translate\">\n @for (option of accountabilities; track option) {\n <label class=\"choice\" [class.selected]=\"accountability() === option\">\n <input type=\"radio\" [name]=\"id + '-accountability'\" [value]=\"option\" [checked]=\"accountability() === option\" (change)=\"setAccountability(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.settings.accountability.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.accountability-explain.' + option | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (errorKey('accountability'); as key) {\n <p class=\"field-error\" [id]=\"id + '-accountability-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('accountability')?.params }}</p>\n }\n @if (accountability() === 'service-account') {\n <div class=\"field\">\n <label [for]=\"id + '-service-account'\">{{ 'nh-assistant.admin.run-config.settings.service-account' | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-service-account'\"\n [value]=\"serviceAccount()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"fieldError('serviceAccountActorId') !== null\"\n [describedBy]=\"describedBy(id + '-service-account-hint', 'serviceAccountActorId', id + '-service-account-error')\"\n (valueChange)=\"serviceAccount.set($event); touch('serviceAccountActorId')\" />\n <p class=\"hint\" [id]=\"id + '-service-account-hint'\">\n {{ (accountSearch() ? 'nh-assistant.admin.run-config.account.search-hint' : 'nh-assistant.admin.run-config.account.id-hint') | translate }}\n </p>\n @if (errorKey('serviceAccountActorId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-service-account-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('serviceAccountActorId')?.params }}</p>\n }\n </div>\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-rule-handler'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-rule-handler'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-rule-handler-hint', 'ruleHandler', id + '-rule-handler-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-rule-handler-hint'\">{{ 'nh-assistant.admin.run-config.settings.how.hint' | translate }}</p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-rule-handler-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.approval.default' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(id + '-policy-hint', 'approvalPolicy', id + '-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.run-config.settings.approval.hint' | translate }}</p>\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-run-tokens'\" [value]=\"maxTokensPerRun()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-run-tokens-error')\"\n (input)=\"maxTokensPerRun.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-run-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-daily-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n <details class=\"advanced\" data-advanced [open]=\"advancedOpen() || advancedHasErrors()\" (toggle)=\"advancedOpen.set($any($event.target).open)\">\n <summary>{{ 'nh-assistant.admin.run-config.advanced.title' | translate }}</summary>\n <div class=\"stack\">\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.advanced.explain' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-retries'\">{{ 'nh-assistant.admin.run-config.settings.retries' | translate }}</label>\n <input type=\"number\" min=\"0\" max=\"10\" inputmode=\"numeric\" [id]=\"id + '-retries'\" [value]=\"retryCount()\"\n [attr.aria-invalid]=\"fieldError('retryCount') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-retries-hint', 'retryCount', id + '-retries-error')\"\n (input)=\"retryCount.set(value($event)); touch('retryCount')\" />\n <p class=\"hint\" [id]=\"id + '-retries-hint'\">{{ 'nh-assistant.admin.run-config.settings.retries-hint' | translate }}</p>\n @if (errorKey('retryCount'); as key) {\n <p class=\"field-error\" [id]=\"id + '-retries-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('retryCount')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-concurrent'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"100\" inputmode=\"numeric\" [id]=\"id + '-concurrent'\" [value]=\"maxConcurrentRuns()\"\n [attr.aria-invalid]=\"fieldError('maxConcurrentRuns') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-concurrent-hint', 'maxConcurrentRuns', id + '-concurrent-error')\"\n (input)=\"maxConcurrentRuns.set(value($event)); touch('maxConcurrentRuns')\" />\n <p class=\"hint\" [id]=\"id + '-concurrent-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent-hint' | translate }}</p>\n @if (errorKey('maxConcurrentRuns'); as key) {\n <p class=\"field-error\" [id]=\"id + '-concurrent-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxConcurrentRuns')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-per-subject'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"1000\" inputmode=\"numeric\" [id]=\"id + '-per-subject'\" [value]=\"maxRunsPerSubjectPerDay()\"\n [attr.aria-invalid]=\"fieldError('maxRunsPerSubjectPerDay') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-per-subject-hint', 'maxRunsPerSubjectPerDay', id + '-per-subject-error')\"\n (input)=\"maxRunsPerSubjectPerDay.set(value($event)); touch('maxRunsPerSubjectPerDay')\" />\n <p class=\"hint\" [id]=\"id + '-per-subject-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject-hint' | translate }}</p>\n @if (errorKey('maxRunsPerSubjectPerDay'); as key) {\n <p class=\"field-error\" [id]=\"id + '-per-subject-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxRunsPerSubjectPerDay')?.params }}</p>\n }\n </div>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-triage'\">{{ 'nh-assistant.admin.run-config.settings.triage' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-triage'\"\n [options]=\"profiles()\"\n [value]=\"triageProfile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.no-triage' | translate\"\n [invalid]=\"fieldError('triageProfile') !== null\"\n [describedBy]=\"describedBy(id + '-triage-hint', 'triageProfile', id + '-triage-error')\"\n (valueChange)=\"triageProfile.set($event); touch('triageProfile')\" />\n <p class=\"hint\" [id]=\"id + '-triage-hint'\">{{ 'nh-assistant.admin.run-config.settings.triage-hint' | translate }}</p>\n @if (errorKey('triageProfile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-triage-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('triageProfile')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.elevated-reads' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.settings.elevated-reads-hint' | translate }}</p>\n @for (mode of elevatedReadModes; track mode) {\n <label class=\"check\">\n <input type=\"radio\" [name]=\"id + '-elevated'\" [value]=\"mode\" [checked]=\"elevatedReads() === mode\" (change)=\"elevatedReads.set(mode); touch('elevatedReads')\" />\n <span>{{ 'nh-assistant.admin.run-config.settings.elevated.' + mode | translate }}</span>\n </label>\n }\n @if (errorKey('elevatedReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('elevatedReads')?.params }}</p>\n }\n </fieldset>\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"allowGatewayReads()\" [attr.aria-invalid]=\"fieldError('allowGatewayReads') ? true : null\" (change)=\"allowGatewayReads.set(checked($event)); touch('allowGatewayReads')\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.gateway-reads' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.gateway-reads-hint' | translate }}</span>\n </span>\n </label>\n @if (errorKey('allowGatewayReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('allowGatewayReads')?.params }}</p>\n }\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"delegateFromInitiator()\" (change)=\"delegateFromInitiator.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.delegate' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.delegate-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </details>\n\n <div class=\"field\">\n <label [for]=\"id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"] }]
2830
+ args: [{ selector: 'nh-assistant-run-settings-form', standalone: true, imports: [
2831
+ TranslatePipe,
2832
+ _NhAssistantTranslatePipe,
2833
+ _NhAssistantIconComponent,
2834
+ _NhAssistantPickerComponent,
2835
+ NhAssistantAccountPickerComponent,
2836
+ NhAssistantFileLimitsFieldsComponent
2837
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"stack card\" data-form=\"settings\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>{{ (settings() ? 'nh-assistant.admin.run-config.settings.edit-title' : 'nh-assistant.admin.run-config.settings.add-title') | translate }}</h5>\n\n <fieldset class=\"group\" [attr.aria-describedby]=\"id + '-who-explain'\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.who.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-who-explain'\">{{ 'nh-assistant.admin.run-config.settings.who.explain' | translate }}</p>\n <div class=\"choices\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.run-config.settings.who.title' | translate\">\n @for (option of accountabilities; track option) {\n <label class=\"choice\" [class.selected]=\"accountability() === option\">\n <input type=\"radio\" [name]=\"id + '-accountability'\" [value]=\"option\" [checked]=\"accountability() === option\" (change)=\"setAccountability(option)\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.settings.accountability.' + option | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.accountability-explain.' + option | translate }}</span>\n </span>\n </label>\n }\n </div>\n @if (errorKey('accountability'); as key) {\n <p class=\"field-error\" [id]=\"id + '-accountability-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('accountability')?.params }}</p>\n }\n @if (accountability() === 'service-account') {\n <div class=\"field\">\n <label [for]=\"id + '-service-account'\">{{ 'nh-assistant.admin.run-config.settings.service-account' | translate }}</label>\n <nh-assistant-account-picker\n [inputId]=\"id + '-service-account'\"\n [value]=\"serviceAccount()\"\n [searchable]=\"accountSearch()\"\n [invalid]=\"fieldError('serviceAccountActorId') !== null\"\n [describedBy]=\"describedBy(id + '-service-account-hint', 'serviceAccountActorId', id + '-service-account-error')\"\n (valueChange)=\"serviceAccount.set($event); touch('serviceAccountActorId')\" />\n <p class=\"hint\" [id]=\"id + '-service-account-hint'\">\n {{ (accountSearch() ? 'nh-assistant.admin.run-config.account.search-hint' : 'nh-assistant.admin.run-config.account.id-hint') | translate }}\n </p>\n @if (errorKey('serviceAccountActorId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-service-account-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('serviceAccountActorId')?.params }}</p>\n }\n </div>\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-rule-handler'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-rule-handler'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-rule-handler-hint', 'ruleHandler', id + '-rule-handler-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-rule-handler-hint'\">{{ 'nh-assistant.admin.run-config.settings.how.hint' | translate }}</p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-rule-handler-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <label class=\"check\" data-accepts-files>\n <input type=\"checkbox\" [checked]=\"acceptsFiles()\" (change)=\"acceptsFiles.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.files.label' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.files.agent-hint' | translate }}</span>\n </span>\n </label>\n @if (acceptsFiles()) {\n <nh-assistant-file-limits-fields\n [draft]=\"fileLimits\"\n [application]=\"catalog()?.fileLimits\"\n [errors]=\"fieldErrors()\"\n [idPrefix]=\"id\"\n hintKey=\"nh-assistant.admin.run-config.files.agent-limits-hint\"\n (touched)=\"touch($event)\" />\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.approval.default' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(id + '-policy-hint', 'approvalPolicy', id + '-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.run-config.settings.approval.hint' | translate }}</p>\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-run-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-run-tokens'\" [value]=\"maxTokensPerRun()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-run-tokens-error')\"\n (input)=\"maxTokensPerRun.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-run-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-daily-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n <details class=\"advanced\" data-advanced [open]=\"advancedOpen() || advancedHasErrors()\" (toggle)=\"advancedOpen.set($any($event.target).open)\">\n <summary>{{ 'nh-assistant.admin.run-config.advanced.title' | translate }}</summary>\n <div class=\"stack\">\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.advanced.explain' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-retries'\">{{ 'nh-assistant.admin.run-config.settings.retries' | translate }}</label>\n <input type=\"number\" min=\"0\" max=\"10\" inputmode=\"numeric\" [id]=\"id + '-retries'\" [value]=\"retryCount()\"\n [attr.aria-invalid]=\"fieldError('retryCount') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-retries-hint', 'retryCount', id + '-retries-error')\"\n (input)=\"retryCount.set(value($event)); touch('retryCount')\" />\n <p class=\"hint\" [id]=\"id + '-retries-hint'\">{{ 'nh-assistant.admin.run-config.settings.retries-hint' | translate }}</p>\n @if (errorKey('retryCount'); as key) {\n <p class=\"field-error\" [id]=\"id + '-retries-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('retryCount')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-concurrent'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"100\" inputmode=\"numeric\" [id]=\"id + '-concurrent'\" [value]=\"maxConcurrentRuns()\"\n [attr.aria-invalid]=\"fieldError('maxConcurrentRuns') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-concurrent-hint', 'maxConcurrentRuns', id + '-concurrent-error')\"\n (input)=\"maxConcurrentRuns.set(value($event)); touch('maxConcurrentRuns')\" />\n <p class=\"hint\" [id]=\"id + '-concurrent-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-concurrent-hint' | translate }}</p>\n @if (errorKey('maxConcurrentRuns'); as key) {\n <p class=\"field-error\" [id]=\"id + '-concurrent-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxConcurrentRuns')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-per-subject'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject' | translate }}</label>\n <input type=\"number\" min=\"1\" max=\"1000\" inputmode=\"numeric\" [id]=\"id + '-per-subject'\" [value]=\"maxRunsPerSubjectPerDay()\"\n [attr.aria-invalid]=\"fieldError('maxRunsPerSubjectPerDay') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-per-subject-hint', 'maxRunsPerSubjectPerDay', id + '-per-subject-error')\"\n (input)=\"maxRunsPerSubjectPerDay.set(value($event)); touch('maxRunsPerSubjectPerDay')\" />\n <p class=\"hint\" [id]=\"id + '-per-subject-hint'\">{{ 'nh-assistant.admin.run-config.settings.max-per-subject-hint' | translate }}</p>\n @if (errorKey('maxRunsPerSubjectPerDay'); as key) {\n <p class=\"field-error\" [id]=\"id + '-per-subject-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxRunsPerSubjectPerDay')?.params }}</p>\n }\n </div>\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-triage'\">{{ 'nh-assistant.admin.run-config.settings.triage' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-triage'\"\n [options]=\"profiles()\"\n [value]=\"triageProfile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.settings.no-triage' | translate\"\n [invalid]=\"fieldError('triageProfile') !== null\"\n [describedBy]=\"describedBy(id + '-triage-hint', 'triageProfile', id + '-triage-error')\"\n (valueChange)=\"triageProfile.set($event); touch('triageProfile')\" />\n <p class=\"hint\" [id]=\"id + '-triage-hint'\">{{ 'nh-assistant.admin.run-config.settings.triage-hint' | translate }}</p>\n @if (errorKey('triageProfile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-triage-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('triageProfile')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.elevated-reads' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.settings.elevated-reads-hint' | translate }}</p>\n @for (mode of elevatedReadModes; track mode) {\n <label class=\"check\">\n <input type=\"radio\" [name]=\"id + '-elevated'\" [value]=\"mode\" [checked]=\"elevatedReads() === mode\" (change)=\"elevatedReads.set(mode); touch('elevatedReads')\" />\n <span>{{ 'nh-assistant.admin.run-config.settings.elevated.' + mode | translate }}</span>\n </label>\n }\n @if (errorKey('elevatedReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('elevatedReads')?.params }}</p>\n }\n </fieldset>\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"allowGatewayReads()\" [attr.aria-invalid]=\"fieldError('allowGatewayReads') ? true : null\" (change)=\"allowGatewayReads.set(checked($event)); touch('allowGatewayReads')\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.gateway-reads' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.gateway-reads-hint' | translate }}</span>\n </span>\n </label>\n @if (errorKey('allowGatewayReads'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('allowGatewayReads')?.params }}</p>\n }\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"delegateFromInitiator()\" (change)=\"delegateFromInitiator.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.settings.delegate' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.settings.delegate-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </details>\n\n <div class=\"field\">\n <label [for]=\"id + '-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"] }]
2627
2838
  }], propDecorators: { agentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "agentId", required: true }] }], catalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalog", required: false }] }], settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
2628
2839
 
2629
2840
  let nextId$7 = 0;
@@ -2654,24 +2865,44 @@ class NhAssistantSkillFormComponent extends RunConfigForm {
2654
2865
  this.maxDescription = runConfigLimits.description;
2655
2866
  this.maxInstructions = runConfigLimits.instructions;
2656
2867
  this.fields = [
2657
- 'skillId', 'description', 'instructions', 'tools', 'ruleHandler', 'profile', 'approvalPolicy',
2658
- 'maxTokensPerRun', 'dailyToolCalls', 'dailyTokens', 'apply', 'reason'
2868
+ 'skillId', 'description', 'instructions', 'tools', 'ruleHandler', 'profile', 'dataClassification', 'approvalPolicy',
2869
+ 'maxTokensPerRun', 'dailyToolCalls', 'dailyTokens', 'apply', 'startsOff', 'reason',
2870
+ 'maxFileBytes', 'maxFilePages', 'maxFilesPerTurn', 'maxFileTokensPerTurn'
2659
2871
  ];
2660
2872
  this.skillId = signal('', ...(ngDevMode ? [{ debugName: "skillId" }] : []));
2661
2873
  this.description = signal('', ...(ngDevMode ? [{ debugName: "description" }] : []));
2662
2874
  this.instructions = signal('', ...(ngDevMode ? [{ debugName: "instructions" }] : []));
2663
2875
  this.tools = signal([], ...(ngDevMode ? [{ debugName: "tools" }] : []));
2664
2876
  this.profile = signal('', ...(ngDevMode ? [{ debugName: "profile" }] : []));
2877
+ /** The skill's data classification; empty uses the agent's. */
2878
+ this.dataClassification = signal('', ...(ngDevMode ? [{ debugName: "dataClassification" }] : []));
2879
+ /** Whether a run in the skill reads files when the agent accepts them too; off for a new skill. */
2880
+ this.acceptsFiles = signal(false, ...(ngDevMode ? [{ debugName: "acceptsFiles" }] : []));
2881
+ /** The skill's lower file limits, next to accepting files; empty keeps the agent's. */
2882
+ this.fileLimits = new FileLimitsDraft();
2665
2883
  this.ruleHandler = signal('', ...(ngDevMode ? [{ debugName: "ruleHandler" }] : []));
2666
2884
  this.approvalPolicy = signal('', ...(ngDevMode ? [{ debugName: "approvalPolicy" }] : []));
2667
2885
  this.maxTokens = signal('', ...(ngDevMode ? [{ debugName: "maxTokens" }] : []));
2668
2886
  this.dailyToolCalls = signal('', ...(ngDevMode ? [{ debugName: "dailyToolCalls" }] : []));
2669
2887
  this.dailyTokens = signal('', ...(ngDevMode ? [{ debugName: "dailyTokens" }] : []));
2670
2888
  this.apply = signal('shadow', ...(ngDevMode ? [{ debugName: "apply" }] : []));
2889
+ /** A new skill takes work at once; without it, it starts off until someone switches it on. */
2890
+ this.switchOnNow = signal(true, ...(ngDevMode ? [{ debugName: "switchOnNow" }] : []));
2671
2891
  this.reason = signal('', ...(ngDevMode ? [{ debugName: "reason" }] : []));
2672
2892
  this.editing = computed(() => this.skill() !== null, ...(ngDevMode ? [{ debugName: "editing" }] : []));
2893
+ /** The warnings of the skill as it was saved, until this form saves it again. */
2894
+ this.warnings = computed(() => this.skill()?.warnings ?? [], ...(ngDevMode ? [{ debugName: "warnings" }] : []));
2895
+ this.warningKeys = warningKeys;
2673
2896
  this.rules = computed(() => ruleOptions(this.catalog()), ...(ngDevMode ? [{ debugName: "rules" }] : []));
2674
2897
  this.profiles = computed(() => profileOptions(this.catalog()), ...(ngDevMode ? [{ debugName: "profiles" }] : []));
2898
+ this.classifications = computed(() => {
2899
+ this.language();
2900
+ return dataClassifications.map(value => ({
2901
+ value,
2902
+ label: this.t(`nh-assistant.admin.run-config.skills.classification.${value}`),
2903
+ description: this.t(`nh-assistant.admin.run-config.skills.classification.${value}-hint`)
2904
+ }));
2905
+ }, ...(ngDevMode ? [{ debugName: "classifications" }] : []));
2675
2906
  this.policies = computed(() => {
2676
2907
  this.language();
2677
2908
  return policyOptions(this.catalog(), summary => describePolicy(summary, (key, params) => this.t(key, params)));
@@ -2684,6 +2915,9 @@ class NhAssistantSkillFormComponent extends RunConfigForm {
2684
2915
  this.instructions.set(skill?.instructions ?? '');
2685
2916
  this.tools.set([...(skill?.tools ?? [])]);
2686
2917
  this.profile.set(skill?.profile ?? '');
2918
+ this.dataClassification.set(skill?.dataClassification ?? '');
2919
+ this.acceptsFiles.set(skill?.acceptsFiles ?? false);
2920
+ this.fileLimits.load(skill);
2687
2921
  this.ruleHandler.set(skill?.ruleHandler ?? '');
2688
2922
  this.approvalPolicy.set(skill?.approvalPolicy ?? '');
2689
2923
  this.maxTokens.set(numberText(skill?.maxTokensPerRun));
@@ -2719,11 +2953,17 @@ class NhAssistantSkillFormComponent extends RunConfigForm {
2719
2953
  }
2720
2954
  checkWhole(errors, 'maxTokensPerRun', this.maxTokens(), 1);
2721
2955
  checkBudget(errors, this.dailyToolCalls(), this.dailyTokens());
2956
+ if (this.acceptsFiles()) {
2957
+ this.fileLimits.check(errors, this.catalog()?.fileLimits);
2958
+ }
2722
2959
  const request = {
2723
2960
  description: this.description().trim(),
2724
2961
  instructions: blank$1(this.instructions()),
2725
2962
  tools: this.tools(),
2726
2963
  profile: blank$1(this.profile()),
2964
+ dataClassification: blank$1(this.dataClassification()),
2965
+ acceptsFiles: this.acceptsFiles(),
2966
+ ...this.fileLimits.toRequest(this.acceptsFiles()),
2727
2967
  ruleHandler: blank$1(this.ruleHandler()),
2728
2968
  approvalPolicy: blank$1(this.approvalPolicy()),
2729
2969
  maxTokensPerRun: toNumber(this.maxTokens()),
@@ -2731,7 +2971,8 @@ class NhAssistantSkillFormComponent extends RunConfigForm {
2731
2971
  dailyTokens: toNumber(this.dailyTokens()),
2732
2972
  expectedVersion: editing?.version ?? null,
2733
2973
  reason: blank$1(this.reason()),
2734
- ...(editing ? { apply: this.apply() } : {})
2974
+ ...(editing ? { apply: this.apply() } : {}),
2975
+ ...(!editing && !this.switchOnNow() ? { startsOff: true } : {})
2735
2976
  };
2736
2977
  this.submit(errors, () => this.admin.saveDataSkill(this.agentId(), skillId, request), skill => this.saved.emit({
2737
2978
  skill,
@@ -2743,11 +2984,11 @@ class NhAssistantSkillFormComponent extends RunConfigForm {
2743
2984
  return withBudgetField(errors, this.dailyToolCalls());
2744
2985
  }
2745
2986
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSkillFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2746
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantSkillFormComponent, isStandalone: true, selector: "nh-assistant-skill-form", inputs: { agentId: { classPropertyName: "agentId", publicName: "agentId", isSignal: true, isRequired: true, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, toolSelectors: { classPropertyName: "toolSelectors", publicName: "toolSelectors", isSignal: true, isRequired: false, transformFunction: null }, toolCatalog: { classPropertyName: "toolCatalog", publicName: "toolCatalog", isSignal: true, isRequired: false, transformFunction: null }, skill: { classPropertyName: "skill", publicName: "skill", isSignal: true, isRequired: false, transformFunction: null }, takenIds: { classPropertyName: "takenIds", publicName: "takenIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, usesInheritance: true, ngImport: i0, template: "<form class=\"stack card\" data-form=\"skill\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>\n @if (skill(); as current) {\n {{ 'nh-assistant.admin.run-config.skills.edit-title' | translate: { skill: current.skillId, version: current.version } }}\n } @else {\n {{ 'nh-assistant.admin.run-config.skills.new-title' | translate }}\n }\n </h5>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.what.title' | translate }}</legend>\n @if (!editing()) {\n <div class=\"field\">\n <label [for]=\"id + '-skill-id'\">{{ 'nh-assistant.admin.run-config.skills.id' | translate }}</label>\n <input type=\"text\" class=\"mono\" autocomplete=\"off\" maxlength=\"64\" [id]=\"id + '-skill-id'\" [value]=\"skillId()\"\n [attr.aria-invalid]=\"fieldError('skillId') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-id-hint', 'skillId', id + '-skill-id-error')\"\n (input)=\"skillId.set(value($event)); touch('skillId')\" />\n <p class=\"hint\" [id]=\"id + '-skill-id-hint'\">{{ 'nh-assistant.admin.run-config.skills.id-hint' | translate }}</p>\n @if (errorKey('skillId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('skillId')?.params }}</p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-skill-description'\">{{ 'nh-assistant.admin.run-config.skills.description-label' | translate }}</label>\n <input type=\"text\" [id]=\"id + '-skill-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-description-hint', 'description', id + '-skill-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\" />\n <p class=\"hint\" [id]=\"id + '-skill-description-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.description-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"description().length > maxDescription\">{{ 'nh-assistant.admin.characters' | translate: { count: description().length, max: maxDescription } }}</span>\n </p>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-rules'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-rules'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-skill-rules-hint', 'ruleHandler', id + '-skill-rules-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-skill-rules-hint'\">\n {{ (ruleHandler() ? 'nh-assistant.admin.run-config.skills.rules-hint' : 'nh-assistant.admin.run-config.skills.model-hint') | translate }}\n </p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-rules-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-instructions'\">{{ 'nh-assistant.admin.run-config.skills.instructions' | translate }}</label>\n <textarea rows=\"5\" [id]=\"id + '-skill-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-instructions-hint', 'instructions', id + '-skill-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-skill-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.instructions-hint' | translate }} {{ 'nh-assistant.admin.run-config.skills.background-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 + '-skill-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\" [attr.aria-describedby]=\"id + '-tools-hint'\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.tools' | translate }}</legend>\n <p class=\"hint\" [id]=\"id + '-tools-hint'\">{{ 'nh-assistant.admin.run-config.skills.tools-hint' | translate }}</p>\n @for (choice of toolChoices(); track choice.selector) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"tools().includes(choice.selector)\" [attr.aria-invalid]=\"fieldError('tools') ? true : null\" (change)=\"toggleTool(choice.selector, checked($event))\" />\n <span class=\"tool-choice\">\n <span class=\"mono\">{{ choice.selector }}</span>\n @if (choice.description) {\n <span class=\"muted block\">{{ choice.description }}</span>\n } @else if (choice.matches !== null) {\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.tools-pattern' | translate: { count: choice.matches } }}</span>\n }\n </span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n }\n @if (errorKey('tools'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('tools')?.params }}</p>\n }\n </fieldset>\n <div class=\"field\">\n <label [for]=\"id + '-skill-profile'\">{{ 'nh-assistant.admin.run-config.skills.profile' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-profile'\"\n [options]=\"profiles()\"\n [value]=\"profile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-profile' | translate\"\n [invalid]=\"fieldError('profile') !== null\"\n [describedBy]=\"describedBy(id + '-skill-profile-hint', 'profile', id + '-skill-profile-error')\"\n (valueChange)=\"profile.set($event); touch('profile')\" />\n <p class=\"hint\" [id]=\"id + '-skill-profile-hint'\">{{ 'nh-assistant.admin.run-config.skills.profile-hint' | translate }}</p>\n @if (errorKey('profile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-profile-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('profile')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-policy' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(null, 'approvalPolicy', id + '-skill-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-skill-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-tokens'\" [value]=\"maxTokens()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-skill-tokens-error')\"\n (input)=\"maxTokens.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-skill-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-skill-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n @if (editing()) {\n <fieldset class=\"group\" data-apply>\n <legend>{{ 'nh-assistant.admin.run-config.skills.apply' | translate }}</legend>\n <div class=\"choices\">\n <label class=\"choice\" [class.selected]=\"apply() === 'shadow'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"shadow\" [checked]=\"apply() === 'shadow'\" (change)=\"apply.set('shadow')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-shadow-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"choice\" [class.selected]=\"apply() === 'live'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"live\" [checked]=\"apply() === 'live'\" (change)=\"apply.set('live')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-live' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-live-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </fieldset>\n } @else {\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.skills.starts-in-shadow' | translate }}</p>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-skill-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-skill-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-skill-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-skill-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: _NhAssistantPickerComponent, selector: "nh-assistant-picker", inputs: ["inputId", "options", "value", "selectedLabel", "noneLabel", "placeholder", "search", "minQueryLength", "invalid", "describedBy", "disabled"], outputs: ["valueChange", "optionChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2987
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantSkillFormComponent, isStandalone: true, selector: "nh-assistant-skill-form", inputs: { agentId: { classPropertyName: "agentId", publicName: "agentId", isSignal: true, isRequired: true, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, toolSelectors: { classPropertyName: "toolSelectors", publicName: "toolSelectors", isSignal: true, isRequired: false, transformFunction: null }, toolCatalog: { classPropertyName: "toolCatalog", publicName: "toolCatalog", isSignal: true, isRequired: false, transformFunction: null }, skill: { classPropertyName: "skill", publicName: "skill", isSignal: true, isRequired: false, transformFunction: null }, takenIds: { classPropertyName: "takenIds", publicName: "takenIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, usesInheritance: true, ngImport: i0, template: "<form class=\"stack card\" data-form=\"skill\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>\n @if (skill(); as current) {\n {{ 'nh-assistant.admin.run-config.skills.edit-title' | translate: { skill: current.skillId, version: current.version } }}\n } @else {\n {{ 'nh-assistant.admin.run-config.skills.new-title' | translate }}\n }\n </h5>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.what.title' | translate }}</legend>\n @if (!editing()) {\n <div class=\"field\">\n <label [for]=\"id + '-skill-id'\">{{ 'nh-assistant.admin.run-config.skills.id' | translate }}</label>\n <input type=\"text\" class=\"mono\" autocomplete=\"off\" maxlength=\"64\" [id]=\"id + '-skill-id'\" [value]=\"skillId()\"\n [attr.aria-invalid]=\"fieldError('skillId') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-id-hint', 'skillId', id + '-skill-id-error')\"\n (input)=\"skillId.set(value($event)); touch('skillId')\" />\n <p class=\"hint\" [id]=\"id + '-skill-id-hint'\">{{ 'nh-assistant.admin.run-config.skills.id-hint' | translate }}</p>\n @if (errorKey('skillId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('skillId')?.params }}</p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-skill-description'\">{{ 'nh-assistant.admin.run-config.skills.description-label' | translate }}</label>\n <input type=\"text\" [id]=\"id + '-skill-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-description-hint', 'description', id + '-skill-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\" />\n <p class=\"hint\" [id]=\"id + '-skill-description-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.description-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"description().length > maxDescription\">{{ 'nh-assistant.admin.characters' | translate: { count: description().length, max: maxDescription } }}</span>\n </p>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-rules'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-rules'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-skill-rules-hint', 'ruleHandler', id + '-skill-rules-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-skill-rules-hint'\">\n {{ (ruleHandler() ? 'nh-assistant.admin.run-config.skills.rules-hint' : 'nh-assistant.admin.run-config.skills.model-hint') | translate }}\n </p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-rules-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-instructions'\">{{ 'nh-assistant.admin.run-config.skills.instructions' | translate }}</label>\n <textarea rows=\"5\" [id]=\"id + '-skill-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-instructions-hint', 'instructions', id + '-skill-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-skill-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.instructions-hint' | translate }} {{ 'nh-assistant.admin.run-config.skills.background-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 + '-skill-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\" [attr.aria-describedby]=\"id + '-tools-hint'\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.tools' | translate }}</legend>\n <p class=\"hint\" [id]=\"id + '-tools-hint'\">{{ 'nh-assistant.admin.run-config.skills.tools-hint' | translate }}</p>\n @for (choice of toolChoices(); track choice.selector) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"tools().includes(choice.selector)\" [attr.aria-invalid]=\"fieldError('tools') ? true : null\" (change)=\"toggleTool(choice.selector, checked($event))\" />\n <span class=\"tool-choice\">\n <span class=\"mono\">{{ choice.selector }}</span>\n @if (choice.description) {\n <span class=\"muted block\">{{ choice.description }}</span>\n } @else if (choice.matches !== null) {\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.tools-pattern' | translate: { count: choice.matches } }}</span>\n }\n </span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n }\n @if (errorKey('tools'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('tools')?.params }}</p>\n }\n </fieldset>\n <div class=\"field\">\n <label [for]=\"id + '-skill-profile'\">{{ 'nh-assistant.admin.run-config.skills.profile' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-profile'\"\n [options]=\"profiles()\"\n [value]=\"profile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-profile' | translate\"\n [invalid]=\"fieldError('profile') !== null\"\n [describedBy]=\"describedBy(id + '-skill-profile-hint', 'profile', id + '-skill-profile-error')\"\n (valueChange)=\"profile.set($event); touch('profile')\" />\n <p class=\"hint\" [id]=\"id + '-skill-profile-hint'\">{{ 'nh-assistant.admin.run-config.skills.profile-hint' | translate }}</p>\n @if (errorKey('profile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-profile-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('profile')?.params }}</p>\n }\n </div>\n <div class=\"field\" data-classification>\n <label [for]=\"id + '-skill-classification'\">{{ 'nh-assistant.admin.run-config.skills.classification.label' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-classification'\"\n [options]=\"classifications()\"\n [value]=\"dataClassification()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.classification.agent' | translate\"\n [invalid]=\"fieldError('dataClassification') !== null\"\n [describedBy]=\"describedBy(id + '-skill-classification-hint', 'dataClassification', id + '-skill-classification-error')\"\n (valueChange)=\"dataClassification.set($event); touch('dataClassification')\" />\n <p class=\"hint\" [id]=\"id + '-skill-classification-hint'\">{{ 'nh-assistant.admin.run-config.skills.classification.hint' | translate }}</p>\n @for (warning of warnings(); track warning) {\n <p class=\"message warning\" [attr.data-skill-form-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('skill', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n @if (errorKey('dataClassification'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-classification-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dataClassification')?.params }}</p>\n }\n </div>\n <label class=\"check\" data-accepts-files>\n <input type=\"checkbox\" [checked]=\"acceptsFiles()\" (change)=\"acceptsFiles.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.files.label' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.files.skill-hint' | translate }}</span>\n </span>\n </label>\n @if (acceptsFiles()) {\n <nh-assistant-file-limits-fields\n [draft]=\"fileLimits\"\n [application]=\"catalog()?.fileLimits\"\n [errors]=\"fieldErrors()\"\n [idPrefix]=\"id\"\n hintKey=\"nh-assistant.admin.run-config.files.skill-limits-hint\"\n (touched)=\"touch($event)\" />\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-policy' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(null, 'approvalPolicy', id + '-skill-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-skill-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-tokens'\" [value]=\"maxTokens()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-skill-tokens-error')\"\n (input)=\"maxTokens.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-skill-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-skill-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n @if (editing()) {\n <fieldset class=\"group\" data-apply>\n <legend>{{ 'nh-assistant.admin.run-config.skills.apply' | translate }}</legend>\n <div class=\"choices\">\n <label class=\"choice\" [class.selected]=\"apply() === 'shadow'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"shadow\" [checked]=\"apply() === 'shadow'\" (change)=\"apply.set('shadow')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-shadow-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"choice\" [class.selected]=\"apply() === 'live'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"live\" [checked]=\"apply() === 'live'\" (change)=\"apply.set('live')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-live' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-live-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </fieldset>\n } @else {\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.skills.starts-in-shadow' | translate }}</p>\n <label class=\"check\" data-switch-on-now>\n <input type=\"checkbox\" [checked]=\"switchOnNow()\" (change)=\"switchOnNow.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.skills.switch-on-now' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.switch-on-now-hint' | translate }}</span>\n </span>\n </label>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-skill-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-skill-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-skill-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-skill-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: _NhAssistantPickerComponent, selector: "nh-assistant-picker", inputs: ["inputId", "options", "value", "selectedLabel", "noneLabel", "placeholder", "search", "minQueryLength", "invalid", "describedBy", "disabled"], outputs: ["valueChange", "optionChange"] }, { kind: "component", type: NhAssistantFileLimitsFieldsComponent, selector: "nh-assistant-file-limits-fields", inputs: ["draft", "application", "errors", "idPrefix", "hintKey"], outputs: ["touched"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2747
2988
  }
2748
2989
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantSkillFormComponent, decorators: [{
2749
2990
  type: Component,
2750
- args: [{ selector: 'nh-assistant-skill-form', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent, _NhAssistantPickerComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"stack card\" data-form=\"skill\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>\n @if (skill(); as current) {\n {{ 'nh-assistant.admin.run-config.skills.edit-title' | translate: { skill: current.skillId, version: current.version } }}\n } @else {\n {{ 'nh-assistant.admin.run-config.skills.new-title' | translate }}\n }\n </h5>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.what.title' | translate }}</legend>\n @if (!editing()) {\n <div class=\"field\">\n <label [for]=\"id + '-skill-id'\">{{ 'nh-assistant.admin.run-config.skills.id' | translate }}</label>\n <input type=\"text\" class=\"mono\" autocomplete=\"off\" maxlength=\"64\" [id]=\"id + '-skill-id'\" [value]=\"skillId()\"\n [attr.aria-invalid]=\"fieldError('skillId') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-id-hint', 'skillId', id + '-skill-id-error')\"\n (input)=\"skillId.set(value($event)); touch('skillId')\" />\n <p class=\"hint\" [id]=\"id + '-skill-id-hint'\">{{ 'nh-assistant.admin.run-config.skills.id-hint' | translate }}</p>\n @if (errorKey('skillId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('skillId')?.params }}</p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-skill-description'\">{{ 'nh-assistant.admin.run-config.skills.description-label' | translate }}</label>\n <input type=\"text\" [id]=\"id + '-skill-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-description-hint', 'description', id + '-skill-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\" />\n <p class=\"hint\" [id]=\"id + '-skill-description-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.description-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"description().length > maxDescription\">{{ 'nh-assistant.admin.characters' | translate: { count: description().length, max: maxDescription } }}</span>\n </p>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-rules'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-rules'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-skill-rules-hint', 'ruleHandler', id + '-skill-rules-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-skill-rules-hint'\">\n {{ (ruleHandler() ? 'nh-assistant.admin.run-config.skills.rules-hint' : 'nh-assistant.admin.run-config.skills.model-hint') | translate }}\n </p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-rules-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-instructions'\">{{ 'nh-assistant.admin.run-config.skills.instructions' | translate }}</label>\n <textarea rows=\"5\" [id]=\"id + '-skill-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-instructions-hint', 'instructions', id + '-skill-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-skill-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.instructions-hint' | translate }} {{ 'nh-assistant.admin.run-config.skills.background-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 + '-skill-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\" [attr.aria-describedby]=\"id + '-tools-hint'\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.tools' | translate }}</legend>\n <p class=\"hint\" [id]=\"id + '-tools-hint'\">{{ 'nh-assistant.admin.run-config.skills.tools-hint' | translate }}</p>\n @for (choice of toolChoices(); track choice.selector) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"tools().includes(choice.selector)\" [attr.aria-invalid]=\"fieldError('tools') ? true : null\" (change)=\"toggleTool(choice.selector, checked($event))\" />\n <span class=\"tool-choice\">\n <span class=\"mono\">{{ choice.selector }}</span>\n @if (choice.description) {\n <span class=\"muted block\">{{ choice.description }}</span>\n } @else if (choice.matches !== null) {\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.tools-pattern' | translate: { count: choice.matches } }}</span>\n }\n </span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n }\n @if (errorKey('tools'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('tools')?.params }}</p>\n }\n </fieldset>\n <div class=\"field\">\n <label [for]=\"id + '-skill-profile'\">{{ 'nh-assistant.admin.run-config.skills.profile' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-profile'\"\n [options]=\"profiles()\"\n [value]=\"profile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-profile' | translate\"\n [invalid]=\"fieldError('profile') !== null\"\n [describedBy]=\"describedBy(id + '-skill-profile-hint', 'profile', id + '-skill-profile-error')\"\n (valueChange)=\"profile.set($event); touch('profile')\" />\n <p class=\"hint\" [id]=\"id + '-skill-profile-hint'\">{{ 'nh-assistant.admin.run-config.skills.profile-hint' | translate }}</p>\n @if (errorKey('profile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-profile-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('profile')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-policy' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(null, 'approvalPolicy', id + '-skill-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-skill-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-tokens'\" [value]=\"maxTokens()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-skill-tokens-error')\"\n (input)=\"maxTokens.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-skill-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-skill-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n @if (editing()) {\n <fieldset class=\"group\" data-apply>\n <legend>{{ 'nh-assistant.admin.run-config.skills.apply' | translate }}</legend>\n <div class=\"choices\">\n <label class=\"choice\" [class.selected]=\"apply() === 'shadow'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"shadow\" [checked]=\"apply() === 'shadow'\" (change)=\"apply.set('shadow')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-shadow-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"choice\" [class.selected]=\"apply() === 'live'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"live\" [checked]=\"apply() === 'live'\" (change)=\"apply.set('live')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-live' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-live-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </fieldset>\n } @else {\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.skills.starts-in-shadow' | translate }}</p>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-skill-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-skill-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-skill-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-skill-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"] }]
2991
+ args: [{ selector: 'nh-assistant-skill-form', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent, _NhAssistantPickerComponent, NhAssistantFileLimitsFieldsComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"stack card\" data-form=\"skill\" novalidate (submit)=\"$event.preventDefault(); save()\">\n <h5>\n @if (skill(); as current) {\n {{ 'nh-assistant.admin.run-config.skills.edit-title' | translate: { skill: current.skillId, version: current.version } }}\n } @else {\n {{ 'nh-assistant.admin.run-config.skills.new-title' | translate }}\n }\n </h5>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.what.title' | translate }}</legend>\n @if (!editing()) {\n <div class=\"field\">\n <label [for]=\"id + '-skill-id'\">{{ 'nh-assistant.admin.run-config.skills.id' | translate }}</label>\n <input type=\"text\" class=\"mono\" autocomplete=\"off\" maxlength=\"64\" [id]=\"id + '-skill-id'\" [value]=\"skillId()\"\n [attr.aria-invalid]=\"fieldError('skillId') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-id-hint', 'skillId', id + '-skill-id-error')\"\n (input)=\"skillId.set(value($event)); touch('skillId')\" />\n <p class=\"hint\" [id]=\"id + '-skill-id-hint'\">{{ 'nh-assistant.admin.run-config.skills.id-hint' | translate }}</p>\n @if (errorKey('skillId'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-id-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('skillId')?.params }}</p>\n }\n </div>\n }\n <div class=\"field\">\n <label [for]=\"id + '-skill-description'\">{{ 'nh-assistant.admin.run-config.skills.description-label' | translate }}</label>\n <input type=\"text\" [id]=\"id + '-skill-description'\" [value]=\"description()\"\n [attr.aria-invalid]=\"fieldError('description') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-description-hint', 'description', id + '-skill-description-error')\"\n (input)=\"description.set(value($event)); touch('description')\" />\n <p class=\"hint\" [id]=\"id + '-skill-description-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.description-hint' | translate }}</span>\n <span class=\"counter\" [class.error-text]=\"description().length > maxDescription\">{{ 'nh-assistant.admin.characters' | translate: { count: description().length, max: maxDescription } }}</span>\n </p>\n @if (errorKey('description'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-description-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('description')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.how.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-rules'\">{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-rules'\"\n [options]=\"rules()\"\n [value]=\"ruleHandler()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.model' | translate\"\n [invalid]=\"fieldError('ruleHandler') !== null\"\n [describedBy]=\"describedBy(id + '-skill-rules-hint', 'ruleHandler', id + '-skill-rules-error')\"\n (valueChange)=\"ruleHandler.set($event); touch('ruleHandler')\" />\n <p class=\"hint\" [id]=\"id + '-skill-rules-hint'\">\n {{ (ruleHandler() ? 'nh-assistant.admin.run-config.skills.rules-hint' : 'nh-assistant.admin.run-config.skills.model-hint') | translate }}\n </p>\n @if (errorKey('ruleHandler'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-rules-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('ruleHandler')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-instructions'\">{{ 'nh-assistant.admin.run-config.skills.instructions' | translate }}</label>\n <textarea rows=\"5\" [id]=\"id + '-skill-instructions'\" [value]=\"instructions()\"\n [attr.aria-invalid]=\"fieldError('instructions') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-skill-instructions-hint', 'instructions', id + '-skill-instructions-error')\"\n (input)=\"instructions.set(value($event)); touch('instructions')\"></textarea>\n <p class=\"hint\" [id]=\"id + '-skill-instructions-hint'\">\n <span>{{ 'nh-assistant.admin.run-config.skills.instructions-hint' | translate }} {{ 'nh-assistant.admin.run-config.skills.background-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 + '-skill-instructions-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('instructions')?.params }}</p>\n }\n </div>\n <fieldset class=\"field\" [attr.aria-describedby]=\"id + '-tools-hint'\">\n <legend>{{ 'nh-assistant.admin.run-config.skills.tools' | translate }}</legend>\n <p class=\"hint\" [id]=\"id + '-tools-hint'\">{{ 'nh-assistant.admin.run-config.skills.tools-hint' | translate }}</p>\n @for (choice of toolChoices(); track choice.selector) {\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"tools().includes(choice.selector)\" [attr.aria-invalid]=\"fieldError('tools') ? true : null\" (change)=\"toggleTool(choice.selector, checked($event))\" />\n <span class=\"tool-choice\">\n <span class=\"mono\">{{ choice.selector }}</span>\n @if (choice.description) {\n <span class=\"muted block\">{{ choice.description }}</span>\n } @else if (choice.matches !== null) {\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.tools-pattern' | translate: { count: choice.matches } }}</span>\n }\n </span>\n </label>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.agent-editor.no-selectors' | translate }}</p>\n }\n @if (errorKey('tools'); as key) {\n <p class=\"field-error\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('tools')?.params }}</p>\n }\n </fieldset>\n <div class=\"field\">\n <label [for]=\"id + '-skill-profile'\">{{ 'nh-assistant.admin.run-config.skills.profile' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-profile'\"\n [options]=\"profiles()\"\n [value]=\"profile()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-profile' | translate\"\n [invalid]=\"fieldError('profile') !== null\"\n [describedBy]=\"describedBy(id + '-skill-profile-hint', 'profile', id + '-skill-profile-error')\"\n (valueChange)=\"profile.set($event); touch('profile')\" />\n <p class=\"hint\" [id]=\"id + '-skill-profile-hint'\">{{ 'nh-assistant.admin.run-config.skills.profile-hint' | translate }}</p>\n @if (errorKey('profile'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-profile-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('profile')?.params }}</p>\n }\n </div>\n <div class=\"field\" data-classification>\n <label [for]=\"id + '-skill-classification'\">{{ 'nh-assistant.admin.run-config.skills.classification.label' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-classification'\"\n [options]=\"classifications()\"\n [value]=\"dataClassification()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.classification.agent' | translate\"\n [invalid]=\"fieldError('dataClassification') !== null\"\n [describedBy]=\"describedBy(id + '-skill-classification-hint', 'dataClassification', id + '-skill-classification-error')\"\n (valueChange)=\"dataClassification.set($event); touch('dataClassification')\" />\n <p class=\"hint\" [id]=\"id + '-skill-classification-hint'\">{{ 'nh-assistant.admin.run-config.skills.classification.hint' | translate }}</p>\n @for (warning of warnings(); track warning) {\n <p class=\"message warning\" [attr.data-skill-form-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('skill', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n @if (errorKey('dataClassification'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-classification-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dataClassification')?.params }}</p>\n }\n </div>\n <label class=\"check\" data-accepts-files>\n <input type=\"checkbox\" [checked]=\"acceptsFiles()\" (change)=\"acceptsFiles.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.files.label' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.files.skill-hint' | translate }}</span>\n </span>\n </label>\n @if (acceptsFiles()) {\n <nh-assistant-file-limits-fields\n [draft]=\"fileLimits\"\n [application]=\"catalog()?.fileLimits\"\n [errors]=\"fieldErrors()\"\n [idPrefix]=\"id\"\n hintKey=\"nh-assistant.admin.run-config.files.skill-limits-hint\"\n (touched)=\"touch($event)\" />\n }\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.settings.approval.title' | translate }}</legend>\n <div class=\"field\">\n <label [for]=\"id + '-skill-policy'\">{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</label>\n <nh-assistant-picker\n [inputId]=\"id + '-skill-policy'\"\n [options]=\"policies()\"\n [value]=\"approvalPolicy()\"\n [noneLabel]=\"'nh-assistant.admin.run-config.skills.agent-policy' | translate\"\n [invalid]=\"fieldError('approvalPolicy') !== null\"\n [describedBy]=\"describedBy(null, 'approvalPolicy', id + '-skill-policy-error')\"\n (valueChange)=\"approvalPolicy.set($event); touch('approvalPolicy')\" />\n @if (errorKey('approvalPolicy'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-policy-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('approvalPolicy')?.params }}</p>\n }\n </div>\n </fieldset>\n\n <fieldset class=\"group\">\n <legend>{{ 'nh-assistant.admin.run-config.limits.title' | translate }}</legend>\n <p class=\"muted\" [id]=\"id + '-limits-hint'\">{{ 'nh-assistant.admin.run-config.budget-hint' | translate }}</p>\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-skill-tokens'\">{{ 'nh-assistant.admin.run-config.max-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-tokens'\" [value]=\"maxTokens()\"\n [attr.aria-invalid]=\"fieldError('maxTokensPerRun') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'maxTokensPerRun', id + '-skill-tokens-error')\"\n (input)=\"maxTokens.set(value($event)); touch('maxTokensPerRun')\" />\n @if (errorKey('maxTokensPerRun'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('maxTokensPerRun')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-calls'\">{{ 'nh-assistant.admin.run-config.daily-tool-calls' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-calls'\" [value]=\"dailyToolCalls()\"\n [attr.aria-invalid]=\"fieldError('dailyToolCalls') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyToolCalls', id + '-skill-calls-error')\"\n (input)=\"dailyToolCalls.set(value($event)); touch('dailyToolCalls'); touch('dailyTokens')\" />\n @if (errorKey('dailyToolCalls'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-calls-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyToolCalls')?.params }}</p>\n }\n </div>\n <div class=\"field\">\n <label [for]=\"id + '-skill-daily-tokens'\">{{ 'nh-assistant.admin.run-config.daily-tokens' | translate }}</label>\n <input type=\"number\" min=\"1\" inputmode=\"numeric\" [id]=\"id + '-skill-daily-tokens'\" [value]=\"dailyTokens()\"\n [attr.aria-invalid]=\"fieldError('dailyTokens') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-limits-hint', 'dailyTokens', id + '-skill-daily-tokens-error')\"\n (input)=\"dailyTokens.set(value($event)); touch('dailyTokens'); touch('dailyToolCalls')\" />\n @if (errorKey('dailyTokens'); as key) {\n <p class=\"field-error\" [id]=\"id + '-skill-daily-tokens-error'\"><nh-assistant-icon name=\"warning\" />{{ key | translate: fieldError('dailyTokens')?.params }}</p>\n }\n </div>\n </div>\n </fieldset>\n\n @if (editing()) {\n <fieldset class=\"group\" data-apply>\n <legend>{{ 'nh-assistant.admin.run-config.skills.apply' | translate }}</legend>\n <div class=\"choices\">\n <label class=\"choice\" [class.selected]=\"apply() === 'shadow'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"shadow\" [checked]=\"apply() === 'shadow'\" (change)=\"apply.set('shadow')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-shadow' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-shadow-hint' | translate }}</span>\n </span>\n </label>\n <label class=\"choice\" [class.selected]=\"apply() === 'live'\">\n <input type=\"radio\" [name]=\"id + '-apply'\" value=\"live\" [checked]=\"apply() === 'live'\" (change)=\"apply.set('live')\" />\n <span>\n <strong>{{ 'nh-assistant.admin.run-config.skills.apply-live' | translate }}</strong>\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.apply-live-hint' | translate }}</span>\n </span>\n </label>\n </div>\n </fieldset>\n } @else {\n <p class=\"hint\">{{ 'nh-assistant.admin.run-config.skills.starts-in-shadow' | translate }}</p>\n <label class=\"check\" data-switch-on-now>\n <input type=\"checkbox\" [checked]=\"switchOnNow()\" (change)=\"switchOnNow.set(checked($event))\" />\n <span>\n {{ 'nh-assistant.admin.run-config.skills.switch-on-now' | translate }}\n <span class=\"muted block\">{{ 'nh-assistant.admin.run-config.skills.switch-on-now-hint' | translate }}</span>\n </span>\n </label>\n }\n\n <div class=\"field\">\n <label [for]=\"id + '-skill-reason'\">{{ 'nh-assistant.admin.agents.state.note-label' | translate }}</label>\n <input type=\"text\" autocomplete=\"off\" [id]=\"id + '-skill-reason'\" [maxLength]=\"maxReason\" [value]=\"reason()\" [attr.aria-describedby]=\"id + '-skill-reason-hint'\" (input)=\"reason.set(value($event))\" />\n <p class=\"hint\" [id]=\"id + '-skill-reason-hint'\">{{ 'nh-assistant.admin.run-config.note-hint' | translate }}</p>\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)=\"cancelled.emit()\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n <button class=\"primary\" type=\"submit\" [disabled]=\"busy()\">{{ (busy() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}</button>\n </div>\n</form>\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}\n"] }]
2751
2992
  }], propDecorators: { agentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "agentId", required: true }] }], catalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalog", required: false }] }], toolSelectors: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolSelectors", required: false }] }], toolCatalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCatalog", required: false }] }], skill: [{ type: i0.Input, args: [{ isSignal: true, alias: "skill", required: false }] }], takenIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "takenIds", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
2752
2993
 
2753
2994
  let nextId$6 = 0;
@@ -2958,6 +3199,7 @@ class NhAssistantAgentRunConfigurationComponent {
2958
3199
  this.id = `nh-assistant-run-configuration-${nextId$5++}`;
2959
3200
  this.maxReason = runConfigLimits.reason;
2960
3201
  this.skillNameKeys = skillNameKeys;
3202
+ this.warningKeys = warningKeys;
2961
3203
  this.skillDescriptionKeys = skillDescriptionKeys;
2962
3204
  this.readableId = readableId;
2963
3205
  this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
@@ -2968,6 +3210,8 @@ class NhAssistantAgentRunConfigurationComponent {
2968
3210
  this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
2969
3211
  this.errorKeys = computed(() => _nhAssistantErrorKeys(this.error()), ...(ngDevMode ? [{ debugName: "errorKeys" }] : []));
2970
3212
  this.saved = signal(null, ...(ngDevMode ? [{ debugName: "saved" }] : []));
3213
+ /** The warnings of the skill that was just saved, shown with the saved message. */
3214
+ this.savedWarnings = signal([], ...(ngDevMode ? [{ debugName: "savedWarnings" }] : []));
2971
3215
  this.form = signal(null, ...(ngDevMode ? [{ debugName: "form" }] : []));
2972
3216
  this.confirming = signal(null, ...(ngDevMode ? [{ debugName: "confirming" }] : []));
2973
3217
  this.reason = signal('', ...(ngDevMode ? [{ debugName: "reason" }] : []));
@@ -3156,7 +3400,7 @@ class NhAssistantAgentRunConfigurationComponent {
3156
3400
  onSkillSaved(result) {
3157
3401
  this.finish(result.candidate
3158
3402
  ? 'nh-assistant.admin.run-config.skills.saved-candidate'
3159
- : result.added ? 'nh-assistant.admin.run-config.skills.added' : 'nh-assistant.admin.run-config.skills.saved');
3403
+ : result.added ? 'nh-assistant.admin.run-config.skills.added' : 'nh-assistant.admin.run-config.skills.saved', result.skill.warnings ?? []);
3160
3404
  }
3161
3405
  onTriggerSaved(added) {
3162
3406
  this.finish(added ? 'nh-assistant.admin.run-config.triggers.added' : 'nh-assistant.admin.run-config.triggers.saved');
@@ -3264,10 +3508,11 @@ class NhAssistantAgentRunConfigurationComponent {
3264
3508
  openForm();
3265
3509
  this.returnFocus = opener instanceof HTMLElement ? opener : null;
3266
3510
  }
3267
- finish(savedKey) {
3511
+ finish(savedKey, warnings = []) {
3268
3512
  this.returnFocus = null;
3269
3513
  this.form.set(null);
3270
3514
  this.saved.set(savedKey);
3515
+ this.savedWarnings.set(warnings);
3271
3516
  this.changed.emit();
3272
3517
  this.load();
3273
3518
  afterNextRender(() => this.host.nativeElement.querySelector('[data-saved]')?.focus(), { injector: this.injector });
@@ -3310,7 +3555,7 @@ class NhAssistantAgentRunConfigurationComponent {
3310
3555
  });
3311
3556
  }
3312
3557
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAgentRunConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3313
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAgentRunConfigurationComponent, isStandalone: true, selector: "nh-assistant-agent-run-configuration", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, startSetup: { classPropertyName: "startSetup", publicName: "startSetup", 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 } }, outputs: { changed: "changed", editAgent: "editAgent", changeAccount: "changeAccount", openRuns: "openRuns", openMcpServers: "openMcpServers" }, ngImport: i0, template: "<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading() || busy()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.run-config.title' | translate: { name: agentName() } }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.description' | translate }}</p>\n </div>\n </header>\n\n @if (saved(); as key) {\n <p class=\"message success\" role=\"status\" tabindex=\"-1\" data-saved>{{ key | translate }}</p>\n }\n\n @if (loading() && !configuration()) {\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 (configuration(); as config) {\n <nh-assistant-account-names-error [names]=\"accountNames\" />\n @if (problems().length > 0) {\n <!-- Each problem shows at the step of the flow it concerns, with the form that fixes it. -->\n <p class=\"message warning\" role=\"status\" data-problems>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.run-config.flow.problems' | translate }}\n </p>\n }\n\n <!-- The agent at a glance; the forms below change what each step shows. -->\n <nh-assistant-agent-flow\n [agent]=\"agent()\"\n [configuration]=\"config\"\n [catalog]=\"catalog()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [accountName]=\"accountName()\"\n [busy]=\"busy()\"\n (entry)=\"onFlowEntry($event)\" />\n\n @if (config.source === 'admin') {\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-settings-title'\" data-run-settings>\n <header class=\"section-header\">\n <h4 [id]=\"id + '-settings-title'\">{{ 'nh-assistant.admin.run-config.settings.title' | translate }}</h4>\n </header>\n @if (form() === 'setup') {\n <nh-assistant-agent-work-setup\n [agentId]=\"config.agentId\"\n [agentName]=\"agentName()\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [takenSkillIds]=\"skillIds()\"\n [takenTriggerIds]=\"triggerIds()\"\n (completed)=\"onSetupCompleted($event.live)\"\n (cancelled)=\"cancel()\" />\n } @else if (form() === 'settings') {\n <nh-assistant-run-settings-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [settings]=\"config.runSettings\"\n (saved)=\"onSettingsSaved()\"\n (cancelled)=\"cancel()\" />\n } @else if (config.runSettings; as settings) {\n <dl class=\"review\" data-settings-summary>\n <dt>{{ 'nh-assistant.admin.run-config.settings.who.short' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.run-config.settings.accountability.' + settings.accountability | translate }}\n @if (settings.serviceAccountActorId; as accountId) {\n <span class=\"block\" data-account-name>\n <nh-assistant-account-label [actorId]=\"accountId\" [name]=\"accountName()\" />\n </span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</dt>\n <dd>{{ settings.ruleHandler ?? ('nh-assistant.admin.run-config.model' | translate) }}</dd>\n <dt>{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</dt>\n <dd>\n {{ settings.approvalPolicy ?? ('nh-assistant.admin.run-config.settings.approval.default' | translate) }}\n @if (settingsPolicy(); as sentence) {\n <span class=\"muted block\">{{ sentence }}</span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.agents.version-label' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.agents.version' | translate: { version: settings.version } }}\n @if (!settings.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </dd>\n </dl>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.rights' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.run-config.settings.edit' | translate }}\n </button>\n @if (isConfirming('remove-settings', config.agentId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSettings()\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-settings', config.agentId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.run-config.settings.remove' | translate }}\n </button>\n }\n </div>\n @if (failed('settings')) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n } @else {\n <div class=\"state\" data-setup-offer>\n <p>{{ 'nh-assistant.admin.run-config.settings.empty' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"primary\" type=\"button\" data-open-form=\"setup\" [disabled]=\"busy()\" (click)=\"openSetup()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.setup.start' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n {{ 'nh-assistant.admin.run-config.settings.add' | translate }}\n </button>\n </div>\n </div>\n }\n </section>\n }\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-skills-title'\" data-skills>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-skills-title'\">{{ 'nh-assistant.admin.agents.skills.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"skill\" [disabled]=\"busy() || !canAddRunData() || form() === 'skill'\" (click)=\"addSkill()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.skills.add' | translate }}\n </button>\n </header>\n @if (!canAddRunData()) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.needs-settings' | translate }}</p>\n }\n\n @if (form() === 'skill') {\n <nh-assistant-skill-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [skill]=\"editingSkill()\"\n [takenIds]=\"skillIds()\"\n (saved)=\"onSkillSaved($event)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeSkills.length === 0 && config.dataSkills.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.skills.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (skill of config.codeSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-code-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(config.agentId, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n </li>\n }\n @for (skill of config.dataSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: skill.version } }}</span>\n @if (!skill.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n @if (skill.candidate) {\n <span class=\"badge warning\" data-candidate-badge>{{ 'nh-assistant.admin.run-config.candidate.badge' | translate: { version: skill.candidate.version } }}</span>\n }\n </div>\n <p class=\"muted\">{{ skill.description }}</p>\n <div class=\"meta\">\n <span>{{ skill.ruleHandler ? ('nh-assistant.admin.run-config.rule-handler-value' | translate: { name: skill.ruleHandler }) : ('nh-assistant.admin.run-config.model' | translate) }}</span>\n @if (skill.profile) {\n <span>{{ 'nh-assistant.admin.run-config.profile-value' | translate: { name: skill.profile } }}</span>\n }\n <span>{{ (skill.tools.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: skill.tools.length } }}</span>\n <span [attr.title]=\"accountTitle(skill.changedBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(skill.changedBy), date: (skill.changedAt | date: 'medium') } }}</span>\n </div>\n @if (skill.candidate; as candidate) {\n <div class=\"subsection\" data-candidate>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.explain' | translate: { version: candidate.version, description: candidate.description } }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"comparison()?.skillId === skill.skillId\" (click)=\"toggleComparison(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.candidate.compare' | translate }}\n </button>\n @if (isConfirming('promote', skill.skillId)) {\n <button class=\"primary\" type=\"button\" [disabled]=\"busy()\" (click)=\"promote(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-promote' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else if (isConfirming('discard', skill.skillId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"discard(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-discard' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('promote', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.promote' | translate }}</button>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('discard', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.discard' | translate }}</button>\n }\n </div>\n @if (comparison(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.result; as result) {\n <div class=\"table-scroll\">\n <table class=\"summary-table\" data-comparison>\n <caption class=\"visually-hidden\">{{ 'nh-assistant.admin.run-config.candidate.comparison' | translate: { skill: (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) } }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{{ 'nh-assistant.admin.evaluation.columns.measure' | translate }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.live-column' | translate: { version: result.live.version } }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.candidate-column' | translate: { version: result.candidate.version } }}</th>\n </tr>\n </thead>\n <tbody>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.runs' | translate }}</th><td>{{ result.live.runs | number }}</td><td>{{ result.candidate.runs | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.completed' | translate }}</th><td>{{ result.live.completed | number }}</td><td>{{ result.candidate.completed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.failed' | translate }}</th><td>{{ result.live.failed | number }}</td><td>{{ result.candidate.failed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.proposals' | translate }}</th><td>{{ result.live.proposals | number }}</td><td>{{ result.candidate.proposals | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.tokens' | translate }}</th><td>{{ result.live.tokens | number }}</td><td>{{ result.candidate.tokens | number }}</td></tr>\n </tbody>\n </table>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.paired' | translate: { count: result.pairedEvents, date: (result.from | date: 'medium') } }}</p>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </div>\n }\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editSkill(skill)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"versions()?.skillId === skill.skillId\" (click)=\"toggleVersions(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.skills.versions' | translate }}\n </button>\n @if (isConfirming('remove-skill', skill.skillId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSkill(skill)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-skill', skill.skillId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('skill:' + skill.skillId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n @if (versions(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.items; as items) {\n <ul class=\"history\" data-versions>\n @for (version of items; track version.version) {\n <li>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: version.version } }}</span>\n <span class=\"badge\" [class.success]=\"version.status === 'live'\" [class.warning]=\"version.status === 'candidate'\">{{ 'nh-assistant.admin.run-config.status.' + version.status | translate }}</span>\n <span>{{ version.description }}</span>\n <span class=\"muted\" [attr.title]=\"accountTitle(version.createdBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(version.createdBy), date: (version.createdAt | date: 'medium') } }}</span>\n @if (version.reason) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: version.reason } }}</span>\n }\n </li>\n }\n </ul>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </li>\n }\n </ul>\n }\n </section>\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-triggers-title'\" data-triggers>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-triggers-title'\">{{ 'nh-assistant.admin.run-config.triggers.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"trigger\" [disabled]=\"busy() || !canAddRunData() || form() === 'trigger'\" (click)=\"addTrigger()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.triggers.add' | translate }}\n </button>\n </header>\n\n @if (form() === 'trigger') {\n <nh-assistant-trigger-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [skills]=\"skillOptions()\"\n [trigger]=\"editingTrigger()\"\n [takenIds]=\"triggerIds()\"\n (saved)=\"onTriggerSaved($event.added)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeTriggers.length === 0 && config.dataTriggers.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.triggers.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (trigger of config.codeTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-code-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n </div>\n @if (trigger.skillId) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.skill-value' | translate: { skill: skillName(trigger.skillId) } }}</p>\n }\n </li>\n }\n @for (trigger of config.dataTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-data-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n @if (trigger.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n } @else {\n <span class=\"badge success\">{{ 'nh-assistant.admin.run-config.triggers.live-badge' | translate }}</span>\n }\n @if (!trigger.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n <div class=\"meta\">\n @if (trigger.source === 'event') {\n <span class=\"mono\">{{ trigger.event }}</span>\n } @else {\n <span class=\"mono\">{{ trigger.cron }} {{ trigger.timeZone ?? 'UTC' }}</span>\n @if (trigger.subjectSet) {\n <span class=\"mono\">{{ trigger.subjectSet }}</span>\n } @else {\n <!-- A schedule without a subject set runs for the whole application, per division for a per-division agent. -->\n <span data-trigger-target>{{ (agent().perDivision ? 'nh-assistant.admin.run-config.triggers.target.every-division' : 'nh-assistant.admin.run-config.triggers.target.application') | translate }}</span>\n }\n }\n <span>{{ (trigger.skillId ? 'nh-assistant.admin.run-config.triggers.skill-value' : 'nh-assistant.admin.run-config.triggers.agent-routes') | translate: { skill: skillName(trigger.skillId) } }}</span>\n <span>{{ 'nh-assistant.admin.run-config.triggers.conflicts.' + trigger.conflict | translate }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: trigger.version } }}</span>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editTrigger(trigger)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.data-trigger-shadow]=\"trigger.shadow ? 'live' : 'shadow'\" [disabled]=\"busy()\" (click)=\"setTriggerShadow(trigger, !trigger.shadow)\">\n {{ (trigger.shadow ? 'nh-assistant.admin.agents.shadow.action.live' : 'nh-assistant.admin.agents.shadow.action.shadow') | translate }}\n </button>\n @if (isConfirming('remove-trigger', trigger.triggerId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeTrigger(trigger)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-trigger', trigger.triggerId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('trigger:' + trigger.triggerId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n </li>\n }\n </ul>\n }\n </section>\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", ".header-actions{display:flex;flex-wrap:wrap;gap:8px}.export-hint{margin-top:4px;font-size:12px}.filters{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));align-items:start;gap:12px}.subsection h4,.list-header h4{margin:0}.list-header{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px}.table-container{container-type:inline-size;min-width:0}.summary-table{width:100%;border-collapse:collapse;font-size:13px}.summary-table th,.summary-table td{border-bottom:1px solid var(--nha-border);padding:8px 10px;text-align:left;vertical-align:top}.summary-table thead th{color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.summary-table tbody th{font-weight:600}.summary-table .number{text-align:right;font-variant-numeric:tabular-nums}.summary-table .mono{overflow-wrap:anywhere}@container (max-width: 820px){.summary-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.summary-table,.summary-table tbody,.summary-table tr{display:block}.summary-table tr{margin-bottom:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 12px;background:var(--nha-background)}.summary-table tbody th,.summary-table td{display:grid;grid-template-columns:minmax(110px,40%) minmax(0,1fr);gap:8px;border:0;padding:4px 0;text-align:left}.summary-table tbody th:before,.summary-table td:before{content:attr(data-label);color:var(--nha-text-muted);font-size:12px;font-weight:700}}.badges{display:flex;flex-wrap:wrap;gap:4px;margin:0;padding:0;list-style:none}.badge .count{font-variant-numeric:tabular-nums;opacity:.85}.feedback-text{margin:0;border-left:3px solid var(--nha-border);padding:2px 0 2px 10px;font-size:13px;white-space:pre-wrap;overflow-wrap:anywhere}.proposal{margin:0;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}.proposal-label{margin-right:4px;color:var(--nha-text);font-weight:700}.pager{display:flex;flex-wrap:wrap;align-items:center;gap:8px}\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAgentFlowComponent, selector: "nh-assistant-agent-flow", inputs: ["agent", "configuration", "catalog", "tools", "servers", "accountName", "busy"], outputs: ["entry"] }, { kind: "component", type: NhAssistantAgentWorkSetupComponent, selector: "nh-assistant-agent-work-setup", inputs: ["agentId", "agentName", "catalog", "worksOn", "toolSelectors", "toolCatalog", "takenSkillIds", "takenTriggerIds"], outputs: ["completed", "cancelled"] }, { kind: "component", type: NhAssistantRunSettingsFormComponent, selector: "nh-assistant-run-settings-form", inputs: ["agentId", "catalog", "settings"], outputs: ["saved", "cancelled"] }, { kind: "component", type: NhAssistantSkillFormComponent, selector: "nh-assistant-skill-form", inputs: ["agentId", "catalog", "toolSelectors", "toolCatalog", "skill", "takenIds"], outputs: ["saved", "cancelled"] }, { kind: "component", type: NhAssistantTriggerFormComponent, selector: "nh-assistant-trigger-form", inputs: ["agentId", "catalog", "worksOn", "skills", "trigger", "takenIds"], outputs: ["saved", "cancelled"] }, { kind: "component", type: NhAssistantAccountNamesErrorComponent, selector: "nh-assistant-account-names-error", inputs: ["names"] }, { kind: "component", type: NhAssistantAccountLabelComponent, selector: "nh-assistant-account-label", inputs: ["actorId", "name"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3558
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAgentRunConfigurationComponent, isStandalone: true, selector: "nh-assistant-agent-run-configuration", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, startSetup: { classPropertyName: "startSetup", publicName: "startSetup", 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 } }, outputs: { changed: "changed", editAgent: "editAgent", changeAccount: "changeAccount", openRuns: "openRuns", openMcpServers: "openMcpServers" }, ngImport: i0, template: "<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading() || busy()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.run-config.title' | translate: { name: agentName() } }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.description' | translate }}</p>\n </div>\n </header>\n\n @if (saved(); as key) {\n <p class=\"message success\" role=\"status\" tabindex=\"-1\" data-saved>{{ key | translate }}</p>\n <!-- The save succeeded; a warning says what may still keep the skill from working. -->\n @for (warning of savedWarnings(); track warning) {\n <p class=\"message warning\" role=\"status\" [attr.data-saved-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('skill', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n }\n\n @if (loading() && !configuration()) {\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 (configuration(); as config) {\n <nh-assistant-account-names-error [names]=\"accountNames\" />\n @if (problems().length > 0) {\n <!-- Each problem shows at the step of the flow it concerns, with the form that fixes it. -->\n <p class=\"message warning\" role=\"status\" data-problems>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.run-config.flow.problems' | translate }}\n </p>\n }\n\n <!-- The agent at a glance; the forms below change what each step shows. -->\n <nh-assistant-agent-flow\n [agent]=\"agent()\"\n [configuration]=\"config\"\n [catalog]=\"catalog()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [accountName]=\"accountName()\"\n [busy]=\"busy()\"\n (entry)=\"onFlowEntry($event)\" />\n\n @if (config.source === 'admin') {\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-settings-title'\" data-run-settings>\n <header class=\"section-header\">\n <h4 [id]=\"id + '-settings-title'\">{{ 'nh-assistant.admin.run-config.settings.title' | translate }}</h4>\n </header>\n @if (form() === 'setup') {\n <nh-assistant-agent-work-setup\n [agentId]=\"config.agentId\"\n [agentName]=\"agentName()\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [takenSkillIds]=\"skillIds()\"\n [takenTriggerIds]=\"triggerIds()\"\n (completed)=\"onSetupCompleted($event.live)\"\n (cancelled)=\"cancel()\" />\n } @else if (form() === 'settings') {\n <nh-assistant-run-settings-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [settings]=\"config.runSettings\"\n (saved)=\"onSettingsSaved()\"\n (cancelled)=\"cancel()\" />\n } @else if (config.runSettings; as settings) {\n <dl class=\"review\" data-settings-summary>\n <dt>{{ 'nh-assistant.admin.run-config.settings.who.short' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.run-config.settings.accountability.' + settings.accountability | translate }}\n @if (settings.serviceAccountActorId; as accountId) {\n <span class=\"block\" data-account-name>\n <nh-assistant-account-label [actorId]=\"accountId\" [name]=\"accountName()\" />\n </span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</dt>\n <dd>{{ settings.ruleHandler ?? ('nh-assistant.admin.run-config.model' | translate) }}</dd>\n <dt>{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</dt>\n <dd>\n {{ settings.approvalPolicy ?? ('nh-assistant.admin.run-config.settings.approval.default' | translate) }}\n @if (settingsPolicy(); as sentence) {\n <span class=\"muted block\">{{ sentence }}</span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.agents.version-label' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.agents.version' | translate: { version: settings.version } }}\n @if (!settings.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </dd>\n </dl>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.rights' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.run-config.settings.edit' | translate }}\n </button>\n @if (isConfirming('remove-settings', config.agentId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSettings()\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-settings', config.agentId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.run-config.settings.remove' | translate }}\n </button>\n }\n </div>\n @if (failed('settings')) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n } @else {\n <div class=\"state\" data-setup-offer>\n <p>{{ 'nh-assistant.admin.run-config.settings.empty' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"primary\" type=\"button\" data-open-form=\"setup\" [disabled]=\"busy()\" (click)=\"openSetup()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.setup.start' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n {{ 'nh-assistant.admin.run-config.settings.add' | translate }}\n </button>\n </div>\n </div>\n }\n </section>\n }\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-skills-title'\" data-skills>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-skills-title'\">{{ 'nh-assistant.admin.agents.skills.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"skill\" [disabled]=\"busy() || !canAddRunData() || form() === 'skill'\" (click)=\"addSkill()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.skills.add' | translate }}\n </button>\n </header>\n @if (!canAddRunData()) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.needs-settings' | translate }}</p>\n }\n\n @if (form() === 'skill') {\n <nh-assistant-skill-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [skill]=\"editingSkill()\"\n [takenIds]=\"skillIds()\"\n (saved)=\"onSkillSaved($event)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeSkills.length === 0 && config.dataSkills.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.skills.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (skill of config.codeSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-code-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(config.agentId, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n </li>\n }\n @for (skill of config.dataSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: skill.version } }}</span>\n @if (!skill.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n @if (skill.candidate) {\n <span class=\"badge warning\" data-candidate-badge>{{ 'nh-assistant.admin.run-config.candidate.badge' | translate: { version: skill.candidate.version } }}</span>\n }\n </div>\n <p class=\"muted\">{{ skill.description }}</p>\n @for (warning of skill.warnings ?? []; track warning) {\n <p class=\"message warning\" [attr.data-skill-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('skill', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n <div class=\"meta\">\n <span>{{ skill.ruleHandler ? ('nh-assistant.admin.run-config.rule-handler-value' | translate: { name: skill.ruleHandler }) : ('nh-assistant.admin.run-config.model' | translate) }}</span>\n @if (skill.profile) {\n <span>{{ 'nh-assistant.admin.run-config.profile-value' | translate: { name: skill.profile } }}</span>\n }\n <span>{{ (skill.tools.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: skill.tools.length } }}</span>\n <span [attr.title]=\"accountTitle(skill.changedBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(skill.changedBy), date: (skill.changedAt | date: 'medium') } }}</span>\n </div>\n @if (skill.candidate; as candidate) {\n <div class=\"subsection\" data-candidate>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.explain' | translate: { version: candidate.version, description: candidate.description } }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"comparison()?.skillId === skill.skillId\" (click)=\"toggleComparison(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.candidate.compare' | translate }}\n </button>\n @if (isConfirming('promote', skill.skillId)) {\n <button class=\"primary\" type=\"button\" [disabled]=\"busy()\" (click)=\"promote(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-promote' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else if (isConfirming('discard', skill.skillId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"discard(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-discard' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('promote', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.promote' | translate }}</button>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('discard', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.discard' | translate }}</button>\n }\n </div>\n @if (comparison(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.result; as result) {\n <div class=\"table-scroll\">\n <table class=\"summary-table\" data-comparison>\n <caption class=\"visually-hidden\">{{ 'nh-assistant.admin.run-config.candidate.comparison' | translate: { skill: (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) } }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{{ 'nh-assistant.admin.evaluation.columns.measure' | translate }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.live-column' | translate: { version: result.live.version } }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.candidate-column' | translate: { version: result.candidate.version } }}</th>\n </tr>\n </thead>\n <tbody>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.runs' | translate }}</th><td>{{ result.live.runs | number }}</td><td>{{ result.candidate.runs | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.completed' | translate }}</th><td>{{ result.live.completed | number }}</td><td>{{ result.candidate.completed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.failed' | translate }}</th><td>{{ result.live.failed | number }}</td><td>{{ result.candidate.failed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.proposals' | translate }}</th><td>{{ result.live.proposals | number }}</td><td>{{ result.candidate.proposals | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.tokens' | translate }}</th><td>{{ result.live.tokens | number }}</td><td>{{ result.candidate.tokens | number }}</td></tr>\n </tbody>\n </table>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.paired' | translate: { count: result.pairedEvents, date: (result.from | date: 'medium') } }}</p>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </div>\n }\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editSkill(skill)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"versions()?.skillId === skill.skillId\" (click)=\"toggleVersions(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.skills.versions' | translate }}\n </button>\n @if (isConfirming('remove-skill', skill.skillId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSkill(skill)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-skill', skill.skillId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('skill:' + skill.skillId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n @if (versions(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.items; as items) {\n <ul class=\"history\" data-versions>\n @for (version of items; track version.version) {\n <li>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: version.version } }}</span>\n <span class=\"badge\" [class.success]=\"version.status === 'live'\" [class.warning]=\"version.status === 'candidate'\">{{ 'nh-assistant.admin.run-config.status.' + version.status | translate }}</span>\n <span>{{ version.description }}</span>\n <span class=\"muted\" [attr.title]=\"accountTitle(version.createdBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(version.createdBy), date: (version.createdAt | date: 'medium') } }}</span>\n @if (version.reason) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: version.reason } }}</span>\n }\n </li>\n }\n </ul>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </li>\n }\n </ul>\n }\n </section>\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-triggers-title'\" data-triggers>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-triggers-title'\">{{ 'nh-assistant.admin.run-config.triggers.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"trigger\" [disabled]=\"busy() || !canAddRunData() || form() === 'trigger'\" (click)=\"addTrigger()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.triggers.add' | translate }}\n </button>\n </header>\n\n @if (form() === 'trigger') {\n <nh-assistant-trigger-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [skills]=\"skillOptions()\"\n [trigger]=\"editingTrigger()\"\n [takenIds]=\"triggerIds()\"\n (saved)=\"onTriggerSaved($event.added)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeTriggers.length === 0 && config.dataTriggers.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.triggers.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (trigger of config.codeTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-code-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n </div>\n @if (trigger.skillId) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.skill-value' | translate: { skill: skillName(trigger.skillId) } }}</p>\n }\n </li>\n }\n @for (trigger of config.dataTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-data-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n @if (trigger.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n } @else {\n <span class=\"badge success\">{{ 'nh-assistant.admin.run-config.triggers.live-badge' | translate }}</span>\n }\n @if (!trigger.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n <div class=\"meta\">\n @if (trigger.source === 'event') {\n <span class=\"mono\">{{ trigger.event }}</span>\n } @else {\n <span class=\"mono\">{{ trigger.cron }} {{ trigger.timeZone ?? 'UTC' }}</span>\n @if (trigger.subjectSet) {\n <span class=\"mono\">{{ trigger.subjectSet }}</span>\n } @else {\n <!-- A schedule without a subject set runs for the whole application, per division for a per-division agent. -->\n <span data-trigger-target>{{ (agent().perDivision ? 'nh-assistant.admin.run-config.triggers.target.every-division' : 'nh-assistant.admin.run-config.triggers.target.application') | translate }}</span>\n }\n }\n <span>{{ (trigger.skillId ? 'nh-assistant.admin.run-config.triggers.skill-value' : 'nh-assistant.admin.run-config.triggers.agent-routes') | translate: { skill: skillName(trigger.skillId) } }}</span>\n <span>{{ 'nh-assistant.admin.run-config.triggers.conflicts.' + trigger.conflict | translate }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: trigger.version } }}</span>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editTrigger(trigger)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.data-trigger-shadow]=\"trigger.shadow ? 'live' : 'shadow'\" [disabled]=\"busy()\" (click)=\"setTriggerShadow(trigger, !trigger.shadow)\">\n {{ (trigger.shadow ? 'nh-assistant.admin.agents.shadow.action.live' : 'nh-assistant.admin.agents.shadow.action.shadow') | translate }}\n </button>\n @if (isConfirming('remove-trigger', trigger.triggerId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeTrigger(trigger)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-trigger', trigger.triggerId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('trigger:' + trigger.triggerId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n </li>\n }\n </ul>\n }\n </section>\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", ".header-actions{display:flex;flex-wrap:wrap;gap:8px}.export-hint{margin-top:4px;font-size:12px}.filters{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));align-items:start;gap:12px}.subsection h4,.list-header h4{margin:0}.list-header{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px}.table-container{container-type:inline-size;min-width:0}.summary-table{width:100%;border-collapse:collapse;font-size:13px}.summary-table th,.summary-table td{border-bottom:1px solid var(--nha-border);padding:8px 10px;text-align:left;vertical-align:top}.summary-table thead th{color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.summary-table tbody th{font-weight:600}.summary-table .number{text-align:right;font-variant-numeric:tabular-nums}.summary-table .mono{overflow-wrap:anywhere}@container (max-width: 820px){.summary-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.summary-table,.summary-table tbody,.summary-table tr{display:block}.summary-table tr{margin-bottom:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 12px;background:var(--nha-background)}.summary-table tbody th,.summary-table td{display:grid;grid-template-columns:minmax(110px,40%) minmax(0,1fr);gap:8px;border:0;padding:4px 0;text-align:left}.summary-table tbody th:before,.summary-table td:before{content:attr(data-label);color:var(--nha-text-muted);font-size:12px;font-weight:700}}.badges{display:flex;flex-wrap:wrap;gap:4px;margin:0;padding:0;list-style:none}.badge .count{font-variant-numeric:tabular-nums;opacity:.85}.feedback-text{margin:0;border-left:3px solid var(--nha-border);padding:2px 0 2px 10px;font-size:13px;white-space:pre-wrap;overflow-wrap:anywhere}.proposal{margin:0;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}.proposal-label{margin-right:4px;color:var(--nha-text);font-weight:700}.pager{display:flex;flex-wrap:wrap;align-items:center;gap:8px}\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}\n"], dependencies: [{ kind: "component", type: _NhAssistantIconComponent, selector: "nh-assistant-icon", inputs: ["name"] }, { kind: "component", type: NhAssistantAgentFlowComponent, selector: "nh-assistant-agent-flow", inputs: ["agent", "configuration", "catalog", "tools", "servers", "accountName", "busy"], outputs: ["entry"] }, { kind: "component", type: NhAssistantAgentWorkSetupComponent, selector: "nh-assistant-agent-work-setup", inputs: ["agentId", "agentName", "catalog", "worksOn", "toolSelectors", "toolCatalog", "takenSkillIds", "takenTriggerIds"], outputs: ["completed", "cancelled"] }, { kind: "component", type: NhAssistantRunSettingsFormComponent, selector: "nh-assistant-run-settings-form", inputs: ["agentId", "catalog", "settings"], outputs: ["saved", "cancelled"] }, { kind: "component", type: NhAssistantSkillFormComponent, selector: "nh-assistant-skill-form", inputs: ["agentId", "catalog", "toolSelectors", "toolCatalog", "skill", "takenIds"], outputs: ["saved", "cancelled"] }, { kind: "component", type: NhAssistantTriggerFormComponent, selector: "nh-assistant-trigger-form", inputs: ["agentId", "catalog", "worksOn", "skills", "trigger", "takenIds"], outputs: ["saved", "cancelled"] }, { kind: "component", type: NhAssistantAccountNamesErrorComponent, selector: "nh-assistant-account-names-error", inputs: ["names"] }, { kind: "component", type: NhAssistantAccountLabelComponent, selector: "nh-assistant-account-label", inputs: ["actorId", "name"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3314
3559
  }
3315
3560
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAgentRunConfigurationComponent, decorators: [{
3316
3561
  type: Component,
@@ -3327,7 +3572,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
3327
3572
  NhAssistantTriggerFormComponent,
3328
3573
  NhAssistantAccountNamesErrorComponent,
3329
3574
  NhAssistantAccountLabelComponent
3330
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading() || busy()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.run-config.title' | translate: { name: agentName() } }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.description' | translate }}</p>\n </div>\n </header>\n\n @if (saved(); as key) {\n <p class=\"message success\" role=\"status\" tabindex=\"-1\" data-saved>{{ key | translate }}</p>\n }\n\n @if (loading() && !configuration()) {\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 (configuration(); as config) {\n <nh-assistant-account-names-error [names]=\"accountNames\" />\n @if (problems().length > 0) {\n <!-- Each problem shows at the step of the flow it concerns, with the form that fixes it. -->\n <p class=\"message warning\" role=\"status\" data-problems>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.run-config.flow.problems' | translate }}\n </p>\n }\n\n <!-- The agent at a glance; the forms below change what each step shows. -->\n <nh-assistant-agent-flow\n [agent]=\"agent()\"\n [configuration]=\"config\"\n [catalog]=\"catalog()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [accountName]=\"accountName()\"\n [busy]=\"busy()\"\n (entry)=\"onFlowEntry($event)\" />\n\n @if (config.source === 'admin') {\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-settings-title'\" data-run-settings>\n <header class=\"section-header\">\n <h4 [id]=\"id + '-settings-title'\">{{ 'nh-assistant.admin.run-config.settings.title' | translate }}</h4>\n </header>\n @if (form() === 'setup') {\n <nh-assistant-agent-work-setup\n [agentId]=\"config.agentId\"\n [agentName]=\"agentName()\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [takenSkillIds]=\"skillIds()\"\n [takenTriggerIds]=\"triggerIds()\"\n (completed)=\"onSetupCompleted($event.live)\"\n (cancelled)=\"cancel()\" />\n } @else if (form() === 'settings') {\n <nh-assistant-run-settings-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [settings]=\"config.runSettings\"\n (saved)=\"onSettingsSaved()\"\n (cancelled)=\"cancel()\" />\n } @else if (config.runSettings; as settings) {\n <dl class=\"review\" data-settings-summary>\n <dt>{{ 'nh-assistant.admin.run-config.settings.who.short' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.run-config.settings.accountability.' + settings.accountability | translate }}\n @if (settings.serviceAccountActorId; as accountId) {\n <span class=\"block\" data-account-name>\n <nh-assistant-account-label [actorId]=\"accountId\" [name]=\"accountName()\" />\n </span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</dt>\n <dd>{{ settings.ruleHandler ?? ('nh-assistant.admin.run-config.model' | translate) }}</dd>\n <dt>{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</dt>\n <dd>\n {{ settings.approvalPolicy ?? ('nh-assistant.admin.run-config.settings.approval.default' | translate) }}\n @if (settingsPolicy(); as sentence) {\n <span class=\"muted block\">{{ sentence }}</span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.agents.version-label' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.agents.version' | translate: { version: settings.version } }}\n @if (!settings.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </dd>\n </dl>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.rights' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.run-config.settings.edit' | translate }}\n </button>\n @if (isConfirming('remove-settings', config.agentId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSettings()\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-settings', config.agentId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.run-config.settings.remove' | translate }}\n </button>\n }\n </div>\n @if (failed('settings')) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n } @else {\n <div class=\"state\" data-setup-offer>\n <p>{{ 'nh-assistant.admin.run-config.settings.empty' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"primary\" type=\"button\" data-open-form=\"setup\" [disabled]=\"busy()\" (click)=\"openSetup()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.setup.start' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n {{ 'nh-assistant.admin.run-config.settings.add' | translate }}\n </button>\n </div>\n </div>\n }\n </section>\n }\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-skills-title'\" data-skills>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-skills-title'\">{{ 'nh-assistant.admin.agents.skills.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"skill\" [disabled]=\"busy() || !canAddRunData() || form() === 'skill'\" (click)=\"addSkill()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.skills.add' | translate }}\n </button>\n </header>\n @if (!canAddRunData()) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.needs-settings' | translate }}</p>\n }\n\n @if (form() === 'skill') {\n <nh-assistant-skill-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [skill]=\"editingSkill()\"\n [takenIds]=\"skillIds()\"\n (saved)=\"onSkillSaved($event)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeSkills.length === 0 && config.dataSkills.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.skills.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (skill of config.codeSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-code-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(config.agentId, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n </li>\n }\n @for (skill of config.dataSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: skill.version } }}</span>\n @if (!skill.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n @if (skill.candidate) {\n <span class=\"badge warning\" data-candidate-badge>{{ 'nh-assistant.admin.run-config.candidate.badge' | translate: { version: skill.candidate.version } }}</span>\n }\n </div>\n <p class=\"muted\">{{ skill.description }}</p>\n <div class=\"meta\">\n <span>{{ skill.ruleHandler ? ('nh-assistant.admin.run-config.rule-handler-value' | translate: { name: skill.ruleHandler }) : ('nh-assistant.admin.run-config.model' | translate) }}</span>\n @if (skill.profile) {\n <span>{{ 'nh-assistant.admin.run-config.profile-value' | translate: { name: skill.profile } }}</span>\n }\n <span>{{ (skill.tools.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: skill.tools.length } }}</span>\n <span [attr.title]=\"accountTitle(skill.changedBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(skill.changedBy), date: (skill.changedAt | date: 'medium') } }}</span>\n </div>\n @if (skill.candidate; as candidate) {\n <div class=\"subsection\" data-candidate>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.explain' | translate: { version: candidate.version, description: candidate.description } }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"comparison()?.skillId === skill.skillId\" (click)=\"toggleComparison(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.candidate.compare' | translate }}\n </button>\n @if (isConfirming('promote', skill.skillId)) {\n <button class=\"primary\" type=\"button\" [disabled]=\"busy()\" (click)=\"promote(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-promote' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else if (isConfirming('discard', skill.skillId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"discard(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-discard' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('promote', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.promote' | translate }}</button>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('discard', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.discard' | translate }}</button>\n }\n </div>\n @if (comparison(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.result; as result) {\n <div class=\"table-scroll\">\n <table class=\"summary-table\" data-comparison>\n <caption class=\"visually-hidden\">{{ 'nh-assistant.admin.run-config.candidate.comparison' | translate: { skill: (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) } }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{{ 'nh-assistant.admin.evaluation.columns.measure' | translate }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.live-column' | translate: { version: result.live.version } }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.candidate-column' | translate: { version: result.candidate.version } }}</th>\n </tr>\n </thead>\n <tbody>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.runs' | translate }}</th><td>{{ result.live.runs | number }}</td><td>{{ result.candidate.runs | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.completed' | translate }}</th><td>{{ result.live.completed | number }}</td><td>{{ result.candidate.completed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.failed' | translate }}</th><td>{{ result.live.failed | number }}</td><td>{{ result.candidate.failed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.proposals' | translate }}</th><td>{{ result.live.proposals | number }}</td><td>{{ result.candidate.proposals | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.tokens' | translate }}</th><td>{{ result.live.tokens | number }}</td><td>{{ result.candidate.tokens | number }}</td></tr>\n </tbody>\n </table>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.paired' | translate: { count: result.pairedEvents, date: (result.from | date: 'medium') } }}</p>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </div>\n }\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editSkill(skill)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"versions()?.skillId === skill.skillId\" (click)=\"toggleVersions(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.skills.versions' | translate }}\n </button>\n @if (isConfirming('remove-skill', skill.skillId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSkill(skill)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-skill', skill.skillId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('skill:' + skill.skillId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n @if (versions(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.items; as items) {\n <ul class=\"history\" data-versions>\n @for (version of items; track version.version) {\n <li>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: version.version } }}</span>\n <span class=\"badge\" [class.success]=\"version.status === 'live'\" [class.warning]=\"version.status === 'candidate'\">{{ 'nh-assistant.admin.run-config.status.' + version.status | translate }}</span>\n <span>{{ version.description }}</span>\n <span class=\"muted\" [attr.title]=\"accountTitle(version.createdBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(version.createdBy), date: (version.createdAt | date: 'medium') } }}</span>\n @if (version.reason) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: version.reason } }}</span>\n }\n </li>\n }\n </ul>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </li>\n }\n </ul>\n }\n </section>\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-triggers-title'\" data-triggers>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-triggers-title'\">{{ 'nh-assistant.admin.run-config.triggers.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"trigger\" [disabled]=\"busy() || !canAddRunData() || form() === 'trigger'\" (click)=\"addTrigger()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.triggers.add' | translate }}\n </button>\n </header>\n\n @if (form() === 'trigger') {\n <nh-assistant-trigger-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [skills]=\"skillOptions()\"\n [trigger]=\"editingTrigger()\"\n [takenIds]=\"triggerIds()\"\n (saved)=\"onTriggerSaved($event.added)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeTriggers.length === 0 && config.dataTriggers.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.triggers.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (trigger of config.codeTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-code-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n </div>\n @if (trigger.skillId) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.skill-value' | translate: { skill: skillName(trigger.skillId) } }}</p>\n }\n </li>\n }\n @for (trigger of config.dataTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-data-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n @if (trigger.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n } @else {\n <span class=\"badge success\">{{ 'nh-assistant.admin.run-config.triggers.live-badge' | translate }}</span>\n }\n @if (!trigger.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n <div class=\"meta\">\n @if (trigger.source === 'event') {\n <span class=\"mono\">{{ trigger.event }}</span>\n } @else {\n <span class=\"mono\">{{ trigger.cron }} {{ trigger.timeZone ?? 'UTC' }}</span>\n @if (trigger.subjectSet) {\n <span class=\"mono\">{{ trigger.subjectSet }}</span>\n } @else {\n <!-- A schedule without a subject set runs for the whole application, per division for a per-division agent. -->\n <span data-trigger-target>{{ (agent().perDivision ? 'nh-assistant.admin.run-config.triggers.target.every-division' : 'nh-assistant.admin.run-config.triggers.target.application') | translate }}</span>\n }\n }\n <span>{{ (trigger.skillId ? 'nh-assistant.admin.run-config.triggers.skill-value' : 'nh-assistant.admin.run-config.triggers.agent-routes') | translate: { skill: skillName(trigger.skillId) } }}</span>\n <span>{{ 'nh-assistant.admin.run-config.triggers.conflicts.' + trigger.conflict | translate }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: trigger.version } }}</span>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editTrigger(trigger)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.data-trigger-shadow]=\"trigger.shadow ? 'live' : 'shadow'\" [disabled]=\"busy()\" (click)=\"setTriggerShadow(trigger, !trigger.shadow)\">\n {{ (trigger.shadow ? 'nh-assistant.admin.agents.shadow.action.live' : 'nh-assistant.admin.agents.shadow.action.shadow') | translate }}\n </button>\n @if (isConfirming('remove-trigger', trigger.triggerId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeTrigger(trigger)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-trigger', trigger.triggerId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('trigger:' + trigger.triggerId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n </li>\n }\n </ul>\n }\n </section>\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", ".header-actions{display:flex;flex-wrap:wrap;gap:8px}.export-hint{margin-top:4px;font-size:12px}.filters{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));align-items:start;gap:12px}.subsection h4,.list-header h4{margin:0}.list-header{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px}.table-container{container-type:inline-size;min-width:0}.summary-table{width:100%;border-collapse:collapse;font-size:13px}.summary-table th,.summary-table td{border-bottom:1px solid var(--nha-border);padding:8px 10px;text-align:left;vertical-align:top}.summary-table thead th{color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.summary-table tbody th{font-weight:600}.summary-table .number{text-align:right;font-variant-numeric:tabular-nums}.summary-table .mono{overflow-wrap:anywhere}@container (max-width: 820px){.summary-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.summary-table,.summary-table tbody,.summary-table tr{display:block}.summary-table tr{margin-bottom:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 12px;background:var(--nha-background)}.summary-table tbody th,.summary-table td{display:grid;grid-template-columns:minmax(110px,40%) minmax(0,1fr);gap:8px;border:0;padding:4px 0;text-align:left}.summary-table tbody th:before,.summary-table td:before{content:attr(data-label);color:var(--nha-text-muted);font-size:12px;font-weight:700}}.badges{display:flex;flex-wrap:wrap;gap:4px;margin:0;padding:0;list-style:none}.badge .count{font-variant-numeric:tabular-nums;opacity:.85}.feedback-text{margin:0;border-left:3px solid var(--nha-border);padding:2px 0 2px 10px;font-size:13px;white-space:pre-wrap;overflow-wrap:anywhere}.proposal{margin:0;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}.proposal-label{margin-right:4px;color:var(--nha-text);font-weight:700}.pager{display:flex;flex-wrap:wrap;align-items:center;gap:8px}\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}\n"] }]
3575
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"section\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"loading() || busy()\">\n <header class=\"section-header\">\n <div>\n <h3 [id]=\"id + '-title'\">{{ 'nh-assistant.admin.run-config.title' | translate: { name: agentName() } }}</h3>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.description' | translate }}</p>\n </div>\n </header>\n\n @if (saved(); as key) {\n <p class=\"message success\" role=\"status\" tabindex=\"-1\" data-saved>{{ key | translate }}</p>\n <!-- The save succeeded; a warning says what may still keep the skill from working. -->\n @for (warning of savedWarnings(); track warning) {\n <p class=\"message warning\" role=\"status\" [attr.data-saved-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('skill', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n }\n\n @if (loading() && !configuration()) {\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 (configuration(); as config) {\n <nh-assistant-account-names-error [names]=\"accountNames\" />\n @if (problems().length > 0) {\n <!-- Each problem shows at the step of the flow it concerns, with the form that fixes it. -->\n <p class=\"message warning\" role=\"status\" data-problems>\n <nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.run-config.flow.problems' | translate }}\n </p>\n }\n\n <!-- The agent at a glance; the forms below change what each step shows. -->\n <nh-assistant-agent-flow\n [agent]=\"agent()\"\n [configuration]=\"config\"\n [catalog]=\"catalog()\"\n [tools]=\"tools()\"\n [servers]=\"servers()\"\n [accountName]=\"accountName()\"\n [busy]=\"busy()\"\n (entry)=\"onFlowEntry($event)\" />\n\n @if (config.source === 'admin') {\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-settings-title'\" data-run-settings>\n <header class=\"section-header\">\n <h4 [id]=\"id + '-settings-title'\">{{ 'nh-assistant.admin.run-config.settings.title' | translate }}</h4>\n </header>\n @if (form() === 'setup') {\n <nh-assistant-agent-work-setup\n [agentId]=\"config.agentId\"\n [agentName]=\"agentName()\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [takenSkillIds]=\"skillIds()\"\n [takenTriggerIds]=\"triggerIds()\"\n (completed)=\"onSetupCompleted($event.live)\"\n (cancelled)=\"cancel()\" />\n } @else if (form() === 'settings') {\n <nh-assistant-run-settings-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [settings]=\"config.runSettings\"\n (saved)=\"onSettingsSaved()\"\n (cancelled)=\"cancel()\" />\n } @else if (config.runSettings; as settings) {\n <dl class=\"review\" data-settings-summary>\n <dt>{{ 'nh-assistant.admin.run-config.settings.who.short' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.run-config.settings.accountability.' + settings.accountability | translate }}\n @if (settings.serviceAccountActorId; as accountId) {\n <span class=\"block\" data-account-name>\n <nh-assistant-account-label [actorId]=\"accountId\" [name]=\"accountName()\" />\n </span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.run-config.way-of-working' | translate }}</dt>\n <dd>{{ settings.ruleHandler ?? ('nh-assistant.admin.run-config.model' | translate) }}</dd>\n <dt>{{ 'nh-assistant.admin.run-config.approval-policy' | translate }}</dt>\n <dd>\n {{ settings.approvalPolicy ?? ('nh-assistant.admin.run-config.settings.approval.default' | translate) }}\n @if (settingsPolicy(); as sentence) {\n <span class=\"muted block\">{{ sentence }}</span>\n }\n </dd>\n <dt>{{ 'nh-assistant.admin.agents.version-label' | translate }}</dt>\n <dd>\n {{ 'nh-assistant.admin.agents.version' | translate: { version: settings.version } }}\n @if (!settings.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </dd>\n </dl>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.rights' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.run-config.settings.edit' | translate }}\n </button>\n @if (isConfirming('remove-settings', config.agentId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.settings.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSettings()\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-settings', config.agentId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.run-config.settings.remove' | translate }}\n </button>\n }\n </div>\n @if (failed('settings')) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n } @else {\n <div class=\"state\" data-setup-offer>\n <p>{{ 'nh-assistant.admin.run-config.settings.empty' | translate }}</p>\n <div class=\"card-actions\">\n <button class=\"primary\" type=\"button\" data-open-form=\"setup\" [disabled]=\"busy()\" (click)=\"openSetup()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.setup.start' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" data-open-form=\"settings\" [disabled]=\"busy()\" (click)=\"editSettings()\">\n {{ 'nh-assistant.admin.run-config.settings.add' | translate }}\n </button>\n </div>\n </div>\n }\n </section>\n }\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-skills-title'\" data-skills>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-skills-title'\">{{ 'nh-assistant.admin.agents.skills.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"skill\" [disabled]=\"busy() || !canAddRunData() || form() === 'skill'\" (click)=\"addSkill()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.skills.add' | translate }}\n </button>\n </header>\n @if (!canAddRunData()) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.needs-settings' | translate }}</p>\n }\n\n @if (form() === 'skill') {\n <nh-assistant-skill-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [toolSelectors]=\"config.toolSelectors\"\n [toolCatalog]=\"tools()\"\n [skill]=\"editingSkill()\"\n [takenIds]=\"skillIds()\"\n (saved)=\"onSkillSaved($event)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeSkills.length === 0 && config.dataSkills.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.skills.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (skill of config.codeSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-code-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n </div>\n <p class=\"muted\">{{ skillDescriptionKeys(config.agentId, skill.skillId) | nhAssistantTranslate: skill.description }}</p>\n </li>\n }\n @for (skill of config.dataSkills; track skill.skillId) {\n <li class=\"skill\" [attr.data-data-skill]=\"skill.skillId\">\n <div class=\"card-header\">\n <strong>{{ (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) }}</strong>\n <span class=\"mono muted\">{{ skill.skillId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: skill.version } }}</span>\n @if (!skill.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n @if (skill.candidate) {\n <span class=\"badge warning\" data-candidate-badge>{{ 'nh-assistant.admin.run-config.candidate.badge' | translate: { version: skill.candidate.version } }}</span>\n }\n </div>\n <p class=\"muted\">{{ skill.description }}</p>\n @for (warning of skill.warnings ?? []; track warning) {\n <p class=\"message warning\" [attr.data-skill-warning]=\"warning\">\n <nh-assistant-icon name=\"warning\" />{{ warningKeys('skill', warning) | nhAssistantTranslate: warning }}\n </p>\n }\n <div class=\"meta\">\n <span>{{ skill.ruleHandler ? ('nh-assistant.admin.run-config.rule-handler-value' | translate: { name: skill.ruleHandler }) : ('nh-assistant.admin.run-config.model' | translate) }}</span>\n @if (skill.profile) {\n <span>{{ 'nh-assistant.admin.run-config.profile-value' | translate: { name: skill.profile } }}</span>\n }\n <span>{{ (skill.tools.length === 1 ? 'nh-assistant.admin.agents.tool-count-one' : 'nh-assistant.admin.agents.tool-count') | translate: { count: skill.tools.length } }}</span>\n <span [attr.title]=\"accountTitle(skill.changedBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(skill.changedBy), date: (skill.changedAt | date: 'medium') } }}</span>\n </div>\n @if (skill.candidate; as candidate) {\n <div class=\"subsection\" data-candidate>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.explain' | translate: { version: candidate.version, description: candidate.description } }}</p>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"comparison()?.skillId === skill.skillId\" (click)=\"toggleComparison(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.candidate.compare' | translate }}\n </button>\n @if (isConfirming('promote', skill.skillId)) {\n <button class=\"primary\" type=\"button\" [disabled]=\"busy()\" (click)=\"promote(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-promote' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else if (isConfirming('discard', skill.skillId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"discard(skill)\">{{ 'nh-assistant.admin.run-config.candidate.confirm-discard' | translate }}</button>\n <button class=\"secondary\" type=\"button\" (click)=\"confirming.set(null)\">{{ 'nh-assistant.admin.cancel' | translate }}</button>\n } @else {\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('promote', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.promote' | translate }}</button>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('discard', skill.skillId)\">{{ 'nh-assistant.admin.run-config.candidate.discard' | translate }}</button>\n }\n </div>\n @if (comparison(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.result; as result) {\n <div class=\"table-scroll\">\n <table class=\"summary-table\" data-comparison>\n <caption class=\"visually-hidden\">{{ 'nh-assistant.admin.run-config.candidate.comparison' | translate: { skill: (skillNameKeys(config.agentId, skill.skillId) | nhAssistantTranslate: readableId(skill.skillId)) } }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{{ 'nh-assistant.admin.evaluation.columns.measure' | translate }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.live-column' | translate: { version: result.live.version } }}</th>\n <th scope=\"col\">{{ 'nh-assistant.admin.run-config.candidate.candidate-column' | translate: { version: result.candidate.version } }}</th>\n </tr>\n </thead>\n <tbody>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.runs' | translate }}</th><td>{{ result.live.runs | number }}</td><td>{{ result.candidate.runs | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.completed' | translate }}</th><td>{{ result.live.completed | number }}</td><td>{{ result.candidate.completed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.failed' | translate }}</th><td>{{ result.live.failed | number }}</td><td>{{ result.candidate.failed | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.proposals' | translate }}</th><td>{{ result.live.proposals | number }}</td><td>{{ result.candidate.proposals | number }}</td></tr>\n <tr><th scope=\"row\">{{ 'nh-assistant.admin.run-config.candidate.tokens' | translate }}</th><td>{{ result.live.tokens | number }}</td><td>{{ result.candidate.tokens | number }}</td></tr>\n </tbody>\n </table>\n </div>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.candidate.paired' | translate: { count: result.pairedEvents, date: (result.from | date: 'medium') } }}</p>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </div>\n }\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editSkill(skill)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.aria-expanded]=\"versions()?.skillId === skill.skillId\" (click)=\"toggleVersions(skill)\">\n <nh-assistant-icon name=\"list\" />{{ 'nh-assistant.admin.run-config.skills.versions' | translate }}\n </button>\n @if (isConfirming('remove-skill', skill.skillId)) {\n <span class=\"muted\">{{ 'nh-assistant.admin.run-config.skills.remove-explain' | translate }}</span>\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeSkill(skill)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-skill', skill.skillId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('skill:' + skill.skillId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n @if (versions(); as shown) {\n @if (shown.skillId === skill.skillId) {\n @if (shown.failed) {\n <p class=\"message error\" role=\"alert\">{{ 'nh-assistant.admin.load-failed' | translate }}</p>\n } @else if (shown.items; as items) {\n <ul class=\"history\" data-versions>\n @for (version of items; track version.version) {\n <li>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.version' | translate: { version: version.version } }}</span>\n <span class=\"badge\" [class.success]=\"version.status === 'live'\" [class.warning]=\"version.status === 'candidate'\">{{ 'nh-assistant.admin.run-config.status.' + version.status | translate }}</span>\n <span>{{ version.description }}</span>\n <span class=\"muted\" [attr.title]=\"accountTitle(version.createdBy)\">{{ 'nh-assistant.admin.run-config.changed' | translate: { user: nameOf(version.createdBy), date: (version.createdAt | date: 'medium') } }}</span>\n @if (version.reason) {\n <span class=\"muted\">{{ 'nh-assistant.admin.agents.state.reason' | translate: { reason: version.reason } }}</span>\n }\n </li>\n }\n </ul>\n } @else {\n <p class=\"state\" role=\"status\">{{ 'nh-assistant.admin.loading' | translate }}</p>\n }\n }\n }\n </li>\n }\n </ul>\n }\n </section>\n\n <section class=\"subsection\" [attr.aria-labelledby]=\"id + '-triggers-title'\" data-triggers>\n <header class=\"section-header\">\n <div>\n <h4 [id]=\"id + '-triggers-title'\">{{ 'nh-assistant.admin.run-config.triggers.title' | translate }}</h4>\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.description' | translate }}</p>\n </div>\n <button class=\"secondary\" type=\"button\" data-open-form=\"trigger\" [disabled]=\"busy() || !canAddRunData() || form() === 'trigger'\" (click)=\"addTrigger()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.run-config.triggers.add' | translate }}\n </button>\n </header>\n\n @if (form() === 'trigger') {\n <nh-assistant-trigger-form\n [agentId]=\"config.agentId\"\n [catalog]=\"catalog()\"\n [worksOn]=\"agent()\"\n [skills]=\"skillOptions()\"\n [trigger]=\"editingTrigger()\"\n [takenIds]=\"triggerIds()\"\n (saved)=\"onTriggerSaved($event.added)\"\n (cancelled)=\"cancel()\" />\n }\n\n @if (config.codeTriggers.length === 0 && config.dataTriggers.length === 0) {\n <p class=\"state\">{{ 'nh-assistant.admin.run-config.triggers.empty' | translate }}</p>\n } @else {\n <ul class=\"skills\">\n @for (trigger of config.codeTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-code-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.agents.source-code' | translate }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n </div>\n @if (trigger.skillId) {\n <p class=\"muted\">{{ 'nh-assistant.admin.run-config.triggers.skill-value' | translate: { skill: skillName(trigger.skillId) } }}</p>\n }\n </li>\n }\n @for (trigger of config.dataTriggers; track trigger.triggerId) {\n <li class=\"skill\" [attr.data-data-trigger]=\"trigger.triggerId\">\n <div class=\"card-header\">\n <span class=\"mono\">{{ trigger.triggerId }}</span>\n <span class=\"badge\">{{ 'nh-assistant.admin.run-config.triggers.sources.' + trigger.source | translate }}</span>\n @if (trigger.shadow) {\n <span class=\"badge warning\" data-shadow-badge>{{ 'nh-assistant.admin.agents.shadow.badge' | translate }}</span>\n } @else {\n <span class=\"badge success\">{{ 'nh-assistant.admin.run-config.triggers.live-badge' | translate }}</span>\n }\n @if (!trigger.inEffect) {\n <span class=\"badge danger\">{{ 'nh-assistant.admin.run-config.out-of-effect' | translate }}</span>\n }\n </div>\n <div class=\"meta\">\n @if (trigger.source === 'event') {\n <span class=\"mono\">{{ trigger.event }}</span>\n } @else {\n <span class=\"mono\">{{ trigger.cron }} {{ trigger.timeZone ?? 'UTC' }}</span>\n @if (trigger.subjectSet) {\n <span class=\"mono\">{{ trigger.subjectSet }}</span>\n } @else {\n <!-- A schedule without a subject set runs for the whole application, per division for a per-division agent. -->\n <span data-trigger-target>{{ (agent().perDivision ? 'nh-assistant.admin.run-config.triggers.target.every-division' : 'nh-assistant.admin.run-config.triggers.target.application') | translate }}</span>\n }\n }\n <span>{{ (trigger.skillId ? 'nh-assistant.admin.run-config.triggers.skill-value' : 'nh-assistant.admin.run-config.triggers.agent-routes') | translate: { skill: skillName(trigger.skillId) } }}</span>\n <span>{{ 'nh-assistant.admin.run-config.triggers.conflicts.' + trigger.conflict | translate }}</span>\n <span>{{ 'nh-assistant.admin.agents.version' | translate: { version: trigger.version } }}</span>\n </div>\n <div class=\"card-actions\">\n <button class=\"secondary\" type=\"button\" [disabled]=\"busy()\" (click)=\"editTrigger(trigger)\">\n <nh-assistant-icon name=\"edit\" />{{ 'nh-assistant.admin.edit' | translate }}\n </button>\n <button class=\"secondary\" type=\"button\" [attr.data-trigger-shadow]=\"trigger.shadow ? 'live' : 'shadow'\" [disabled]=\"busy()\" (click)=\"setTriggerShadow(trigger, !trigger.shadow)\">\n {{ (trigger.shadow ? 'nh-assistant.admin.agents.shadow.action.live' : 'nh-assistant.admin.agents.shadow.action.shadow') | translate }}\n </button>\n @if (isConfirming('remove-trigger', trigger.triggerId)) {\n <button class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"removeTrigger(trigger)\">{{ '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 class=\"danger\" type=\"button\" [disabled]=\"busy()\" (click)=\"confirm('remove-trigger', trigger.triggerId)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\n }\n </div>\n @if (failed('trigger:' + trigger.triggerId)) {\n <p class=\"form-error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ errorKeys() | nhAssistantTranslate: error()!.code }}</p>\n }\n </li>\n }\n </ul>\n }\n </section>\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", ".header-actions{display:flex;flex-wrap:wrap;gap:8px}.export-hint{margin-top:4px;font-size:12px}.filters{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));align-items:start;gap:12px}.subsection h4,.list-header h4{margin:0}.list-header{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px}.table-container{container-type:inline-size;min-width:0}.summary-table{width:100%;border-collapse:collapse;font-size:13px}.summary-table th,.summary-table td{border-bottom:1px solid var(--nha-border);padding:8px 10px;text-align:left;vertical-align:top}.summary-table thead th{color:var(--nha-text-muted);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.summary-table tbody th{font-weight:600}.summary-table .number{text-align:right;font-variant-numeric:tabular-nums}.summary-table .mono{overflow-wrap:anywhere}@container (max-width: 820px){.summary-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.summary-table,.summary-table tbody,.summary-table tr{display:block}.summary-table tr{margin-bottom:8px;border:1px solid var(--nha-border);border-radius:var(--nha-radius-control);padding:6px 12px;background:var(--nha-background)}.summary-table tbody th,.summary-table td{display:grid;grid-template-columns:minmax(110px,40%) minmax(0,1fr);gap:8px;border:0;padding:4px 0;text-align:left}.summary-table tbody th:before,.summary-table td:before{content:attr(data-label);color:var(--nha-text-muted);font-size:12px;font-weight:700}}.badges{display:flex;flex-wrap:wrap;gap:4px;margin:0;padding:0;list-style:none}.badge .count{font-variant-numeric:tabular-nums;opacity:.85}.feedback-text{margin:0;border-left:3px solid var(--nha-border);padding:2px 0 2px 10px;font-size:13px;white-space:pre-wrap;overflow-wrap:anywhere}.proposal{margin:0;color:var(--nha-text-muted);font-size:12px;overflow-wrap:anywhere}.proposal-label{margin-right:4px;color:var(--nha-text);font-weight:700}.pager{display:flex;flex-wrap:wrap;align-items:center;gap:8px}\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}\n"] }]
3331
3576
  }], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], startSetup: [{ type: i0.Input, args: [{ isSignal: true, alias: "startSetup", required: false }] }], tools: [{ type: i0.Input, args: [{ isSignal: true, alias: "tools", required: false }] }], servers: [{ type: i0.Input, args: [{ isSignal: true, alias: "servers", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }], editAgent: [{ type: i0.Output, args: ["editAgent"] }], changeAccount: [{ type: i0.Output, args: ["changeAccount"] }], openRuns: [{ type: i0.Output, args: ["openRuns"] }], openMcpServers: [{ type: i0.Output, args: ["openMcpServers"] }] } });
3332
3577
  function blank(value) {
3333
3578
  const trimmed = value.trim();
@@ -3341,7 +3586,8 @@ const maxStateReason = 500;
3341
3586
  const accountRefusals = new Set(['assistant-service-account-not-found', 'assistant-service-account-not-used']);
3342
3587
  /**
3343
3588
  * Agent administration: code agents (override, reset) and agents created here (edit, delete),
3344
- * and for every agent its run state with pause, stop and resume, its shadow mode and that of each
3589
+ * and for every agent and skill its run state with pause, switch off, stop and resume (switch on
3590
+ * for one that is off), its shadow mode and that of each
3345
3591
  * skill, and the technical account of an agent that answers to one, each with an optional reason.
3346
3592
  * Editing opens `nh-assistant-admin-agent-editor`; the feedback action opens
3347
3593
  * `nh-assistant-agent-feedback-report` for the agent, the evaluation action of an agent with
@@ -3444,6 +3690,7 @@ class NhAssistantAdminAgentsComponent {
3444
3690
  this.errorKeys = computed(() => _nhAssistantErrorKeys(this.error()), ...(ngDevMode ? [{ debugName: "errorKeys" }] : []));
3445
3691
  this.codeTextKeys = codeTextKeys;
3446
3692
  this.skillNameKeys = skillNameKeys;
3693
+ this.warningKeys = warningKeys;
3447
3694
  this.skillDescriptionKeys = skillDescriptionKeys;
3448
3695
  this.policyKeys = policyKeys;
3449
3696
  this.readableId = readableId;
@@ -3527,13 +3774,13 @@ class NhAssistantAdminAgentsComponent {
3527
3774
  }
3528
3775
  /**
3529
3776
  * Whether the agent can be run now: it runs on its own, so it has a run configuration, it is
3530
- * neither stopped nor disabled in code, and the run catalog names what it can run on. The server
3531
- * decides the rest when the run starts.
3777
+ * neither stopped nor disabled in code, and the run catalog names what it can run on. An agent
3778
+ * that is off still runs for a person. The server decides the rest when the run starts.
3532
3779
  */
3533
3780
  canRunNow(agent) {
3534
3781
  return this.catalog() !== null
3535
3782
  && this.hasRunConfiguration(agent)
3536
- && (agent.runState === 'active' || agent.runState === 'paused');
3783
+ && (agent.runState === 'active' || agent.runState === 'paused' || agent.runState === 'off');
3537
3784
  }
3538
3785
  /** Opens the run-now dialog of the agent. */
3539
3786
  runNow(agent) {
@@ -3699,11 +3946,13 @@ class NhAssistantAdminAgentsComponent {
3699
3946
  stateActions(agent) {
3700
3947
  switch (agent.runState) {
3701
3948
  case 'active':
3702
- return ['paused', 'stopped'];
3949
+ return ['paused', 'off', 'stopped'];
3703
3950
  case 'paused':
3951
+ return ['active', 'off', 'stopped'];
3952
+ case 'off':
3704
3953
  return ['active', 'stopped'];
3705
3954
  case 'stopped':
3706
- return ['active'];
3955
+ return ['active', 'off'];
3707
3956
  default:
3708
3957
  return [];
3709
3958
  }
@@ -3712,17 +3961,30 @@ class NhAssistantAdminAgentsComponent {
3712
3961
  skillActions(skill) {
3713
3962
  switch (skill.runState) {
3714
3963
  case 'active':
3715
- return ['paused', 'stopped'];
3964
+ return ['paused', 'off', 'stopped'];
3716
3965
  case 'paused':
3966
+ return ['active', 'off', 'stopped'];
3967
+ case 'off':
3717
3968
  return ['active', 'stopped'];
3718
3969
  default:
3719
3970
  return ['active'];
3720
3971
  }
3721
3972
  }
3973
+ /**
3974
+ * The key of a state change's label, explanation or confirmation: making an agent or skill that is
3975
+ * off active again switches it on, which replays nothing, unlike a resume.
3976
+ */
3977
+ stateKey(part, from, action) {
3978
+ return `nh-assistant.admin.agents.state.${part}.${from === 'off' && action === 'active' ? 'switch-on' : action}`;
3979
+ }
3980
+ /** The explanation of a state change of one skill. */
3981
+ skillStateExplainKey(change) {
3982
+ return `nh-assistant.admin.agents.skills.explain.${change.from === 'off' && change.state === 'active' ? 'switch-on' : change.state}`;
3983
+ }
3722
3984
  /** Opens the reason form of a state change of the agent or, with a skill, of that skill. */
3723
3985
  askState(agent, state, skill) {
3724
3986
  this.closeForms();
3725
- this.changingState.set({ agentId: agent.id, skillId: skill?.skillId, state });
3987
+ this.changingState.set({ agentId: agent.id, skillId: skill?.skillId, state, from: skill?.runState ?? agent.runState });
3726
3988
  afterNextRender(() => this.reasonInput()?.nativeElement.focus(), { injector: this.injector });
3727
3989
  }
3728
3990
  /**
@@ -3957,7 +4219,7 @@ class NhAssistantAdminAgentsComponent {
3957
4219
  void this.store.reloadStatus();
3958
4220
  }
3959
4221
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3960
- 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 (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\" />\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 <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 </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 </div>\n @if (agent.description) {\n <p class=\"muted\">{{ codeTextKeys(agent.source, agent.description) | nhAssistantTranslate: agent.description }}</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 }\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.aria-expanded]=\"isChangingState(agent.id, action)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action)\">\n {{ 'nh-assistant.admin.agents.state.action.' + 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 @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 class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\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 class=\"danger\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\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.aria-label]=\"('nh-assistant.admin.agents.state.action.' + 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 {{ 'nh-assistant.admin.agents.state.action.' + 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\">{{ 'nh-assistant.admin.agents.skills.explain.' + change.state | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)) } }}</p>\n } @else {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.explain.' + 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 {{ 'nh-assistant.admin.agents.state.confirm.' + 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 (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"], outputs: ["changed", "editAgent", "changeAccount", "openRuns", "openMcpServers"] }, { 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: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4222
+ 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 (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\" />\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 <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 </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 </div>\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 @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 @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 @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 class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\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 class=\"danger\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\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 (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"], outputs: ["changed", "editAgent", "changeAccount", "openRuns", "openMcpServers"] }, { 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: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3961
4223
  }
3962
4224
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminAgentsComponent, decorators: [{
3963
4225
  type: Component,
@@ -3974,7 +4236,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
3974
4236
  NhAssistantAccountPickerComponent,
3975
4237
  _NhAssistantRunNowDialogComponent,
3976
4238
  NhAssistantAccountNamesErrorComponent
3977
- ], 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 (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\" />\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 <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 </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 </div>\n @if (agent.description) {\n <p class=\"muted\">{{ codeTextKeys(agent.source, agent.description) | nhAssistantTranslate: agent.description }}</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 }\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.aria-expanded]=\"isChangingState(agent.id, action)\"\n [disabled]=\"busyAgentId() !== null\"\n (click)=\"askState(agent, action)\">\n {{ 'nh-assistant.admin.agents.state.action.' + 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 @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 class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\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 class=\"danger\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\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.aria-label]=\"('nh-assistant.admin.agents.state.action.' + 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 {{ 'nh-assistant.admin.agents.state.action.' + 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\">{{ 'nh-assistant.admin.agents.skills.explain.' + change.state | translate: { skill: (skillNameKeys(agent.id, change.skillId) | nhAssistantTranslate: readableId(change.skillId)) } }}</p>\n } @else {\n <p class=\"muted\">{{ 'nh-assistant.admin.agents.state.explain.' + 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 {{ 'nh-assistant.admin.agents.state.confirm.' + 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 (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"] }]
4239
+ ], 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 (editAgent)=\"editFromRunConfiguration(agent)\"\n (openRuns)=\"runsFromRunConfiguration(agent)\"\n (changeAccount)=\"accountFromRunConfiguration(agent)\"\n (openMcpServers)=\"openMcpServers.emit()\" />\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 <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 </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 </div>\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 @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 @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 @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 class=\"secondary\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'reset')\">\n <nh-assistant-icon name=\"refresh\" />{{ 'nh-assistant.admin.agents.reset' | translate }}\n </button>\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 class=\"danger\" type=\"button\" [disabled]=\"busyAgentId() !== null\" (click)=\"confirm(agent.id, 'delete')\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.delete' | translate }}\n </button>\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 (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"] }]
3978
4240
  }], ctorParameters: () => [], propDecorators: { backButton: [{ type: i0.ViewChild, args: ['back', { isSignal: true }] }], reasonInput: [{ type: i0.ViewChild, args: ['reasonInput', { isSignal: true }] }], openMcpServers: [{ type: i0.Output, args: ["openMcpServers"] }] } });
3979
4241
  function withState(agent, state) {
3980
4242
  return {
@@ -4036,8 +4298,11 @@ const serverFields = [
4036
4298
  'oauth.organizationAccountLabel',
4037
4299
  'oauth.confirmAuthorization',
4038
4300
  'requiredPolicy',
4039
- 'headlessUse'
4301
+ 'headlessUse',
4302
+ 'readers'
4040
4303
  ];
4304
+ /** The fields of one reader the server reports errors for, as `readers[<index>].<field>`. */
4305
+ const readerFieldPattern = /^readers\[\d+\]\.(mediaTypes|toolName|maxClassification|priority)$/;
4041
4306
  /** A header name the server accepts: 1 to 128 letters, digits and dashes. */
4042
4307
  const headerNamePattern = /^[A-Za-z0-9-]{1,128}$/;
4043
4308
  /** `<prefix>:<name>` as the server accepts it; the name never climbs a path. */
@@ -4045,13 +4310,25 @@ const secretReferencePattern = /^[a-z][a-z0-9-]{0,31}:[A-Za-z0-9][A-Za-z0-9._/-]
4045
4310
  const certificateNamePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
4046
4311
  /** Space-separated scope tokens: printable ASCII without quotes or backslashes (RFC 6749). */
4047
4312
  const scopesPattern = /^[\x21\x23-\x5B\x5D-\x7E]+( [\x21\x23-\x5B\x5D-\x7E]+)*$/;
4313
+ /** A media type without parameters, as the server compares them (`type/subtype`). */
4314
+ const mediaTypePattern = /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/;
4315
+ /** The most media types one reader reads. */
4316
+ const maxReaderMediaTypes = 16;
4317
+ /** The most readers one server has. */
4318
+ const maxReaders = 16;
4319
+ /** The priorities a reader can have; a higher one is asked first. */
4320
+ const readerPriority = { min: -1000, max: 1000 };
4048
4321
  let nextId$3 = 0;
4322
+ let nextReaderKey = 0;
4049
4323
  /**
4050
4324
  * Creates or edits one MCP server: the authentication with a write-only secret or a reference to
4051
4325
  * one, OAuth with discovery the administrator confirms, an optional client certificate, the
4052
- * transport and the use in background runs. Every field stops at the length the server accepts; a
4053
- * refused save shows each of the server's field errors at its field, for example a secret reference
4054
- * the application cannot resolve (`not-found`), and moves the focus to the first of them.
4326
+ * transport, the use in background runs and, for a server that exists, its readers: per reader the
4327
+ * synced tool that turns files into text, the media types it reads, the highest classification that
4328
+ * may be sent to it and its priority, with readers to add and remove. Every field stops at the length
4329
+ * the server accepts; a refused save shows each of the server's field errors at its field, those of a
4330
+ * reader at that reader (`readers[0].toolName`), for example a secret reference the application cannot
4331
+ * resolve (`not-found`), and moves the focus to the first of them.
4055
4332
  */
4056
4333
  class NhAssistantAdminMcpServerEditorComponent {
4057
4334
  constructor() {
@@ -4078,6 +4355,7 @@ class NhAssistantAdminMcpServerEditorComponent {
4078
4355
  this.transports = ['streamable-http', 'auto'];
4079
4356
  this.secretSources = ['stored', 'reference'];
4080
4357
  this.connectionScopes = ['organization', 'user'];
4358
+ this.classifications = ['public', 'internal', 'confidential', 'restricted'];
4081
4359
  this.serverId = signal('', ...(ngDevMode ? [{ debugName: "serverId" }] : []));
4082
4360
  this.displayName = signal('', ...(ngDevMode ? [{ debugName: "displayName" }] : []));
4083
4361
  this.url = signal('', ...(ngDevMode ? [{ debugName: "url" }] : []));
@@ -4108,6 +4386,12 @@ class NhAssistantAdminMcpServerEditorComponent {
4108
4386
  this.discovering = signal(false, ...(ngDevMode ? [{ debugName: "discovering" }] : []));
4109
4387
  this.discoveryError = signal(null, ...(ngDevMode ? [{ debugName: "discoveryError" }] : []));
4110
4388
  this.confirmAuthorization = signal(false, ...(ngDevMode ? [{ debugName: "confirmAuthorization" }] : []));
4389
+ /** The readers of the server as the editor shows them, in their order. */
4390
+ this.readers = signal([], ...(ngDevMode ? [{ debugName: "readers" }] : []));
4391
+ this.maxReaders = maxReaders;
4392
+ this.readerPriority = readerPriority;
4393
+ /** The server's synced tools, which can read files; empty until they are loaded. */
4394
+ this.readerTools = signal([], ...(ngDevMode ? [{ debugName: "readerTools" }] : []));
4111
4395
  this.submitted = signal(false, ...(ngDevMode ? [{ debugName: "submitted" }] : []));
4112
4396
  this.saving = signal(false, ...(ngDevMode ? [{ debugName: "saving" }] : []));
4113
4397
  this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
@@ -4183,8 +4467,39 @@ class NhAssistantAdminMcpServerEditorComponent {
4183
4467
  const header = this.headerName().trim();
4184
4468
  return this.authMode() === 'api-key' && header.length > 0 && !headerNamePattern.test(header);
4185
4469
  }, ...(ngDevMode ? [{ debugName: "headerNameInvalid" }] : []));
4470
+ /** The tool names to choose from, keeping the stored tools the list no longer holds selectable. */
4471
+ this.readerToolNames = computed(() => {
4472
+ const names = this.readerTools().map(tool => tool.remoteName);
4473
+ const stored = (this.server()?.readers ?? []).map(reader => reader.toolName).filter(name => !names.includes(name));
4474
+ return [...names, ...stored];
4475
+ }, ...(ngDevMode ? [{ debugName: "readerToolNames" }] : []));
4476
+ /** What is wrong with each reader, in the order of `readers`. */
4477
+ this.readerProblems = computed(() => {
4478
+ const seen = new Set();
4479
+ return this.readers().map(reader => {
4480
+ const types = splitMediaTypes(reader.mediaTypes);
4481
+ const duplicate = reader.toolName.length > 0 && seen.has(reader.toolName);
4482
+ seen.add(reader.toolName);
4483
+ return {
4484
+ types: types.length === 0 || types.some(type => !isMediaType(type)) ||
4485
+ new Set(types.map(type => type.split(';')[0].trim().toLowerCase())).size > maxReaderMediaTypes,
4486
+ tool: reader.toolName.length === 0,
4487
+ duplicate,
4488
+ classification: reader.maxClassification === '',
4489
+ priority: parsePriority(reader.priority) === null
4490
+ };
4491
+ });
4492
+ }, ...(ngDevMode ? [{ debugName: "readerProblems" }] : []));
4493
+ /** Why a reader can or cannot be added: the server's tools are not synced, or it has the most. */
4494
+ this.readerAddHint = computed(() => this.readerToolNames().length === 0
4495
+ ? 'nh-assistant.admin.server-editor.reader.tool-sync'
4496
+ : this.readers().length >= maxReaders
4497
+ ? 'nh-assistant.admin.server-editor.reader.limit'
4498
+ : 'nh-assistant.admin.server-editor.reader.add-hint', ...(ngDevMode ? [{ debugName: "readerAddHint" }] : []));
4499
+ this.readerInvalid = computed(() => this.readerProblems().some(problems => problems.types || problems.tool || problems.duplicate || problems.classification || problems.priority), ...(ngDevMode ? [{ debugName: "readerInvalid" }] : []));
4186
4500
  this.valid = computed(() => !this.idInvalid() && !this.nameMissing() && !this.urlInvalid() && !this.headerNameInvalid() &&
4187
- !this.userNameInvalid() && !this.secretReferenceInvalid() && !this.certificateInvalid() && !this.oauthInvalid(), ...(ngDevMode ? [{ debugName: "valid" }] : []));
4501
+ !this.userNameInvalid() && !this.secretReferenceInvalid() && !this.certificateInvalid() && !this.oauthInvalid() &&
4502
+ !this.readerInvalid(), ...(ngDevMode ? [{ debugName: "valid" }] : []));
4188
4503
  this.errorKeys = computed(() => _nhAssistantErrorKeys(this.error()), ...(ngDevMode ? [{ debugName: "errorKeys" }] : []));
4189
4504
  /** The server's first error per field of the refused save, until the administrator changes the field. */
4190
4505
  this.serverErrors = computed(() => {
@@ -4199,13 +4514,14 @@ class NhAssistantAdminMcpServerEditorComponent {
4199
4514
  }, ...(ngDevMode ? [{ debugName: "serverErrors" }] : []));
4200
4515
  /** Field errors of fields the editor does not show, listed with the form's error. */
4201
4516
  this.otherServerErrors = computed(() => Object.entries(this.serverErrors())
4202
- .filter(([field]) => !serverFields.includes(field))
4517
+ .filter(([field]) => !serverFields.includes(field) && !this.showsReaderField(field))
4203
4518
  .map(([field, value]) => ({ field, keys: this.valueKeys(value) })), ...(ngDevMode ? [{ debugName: "otherServerErrors" }] : []));
4204
4519
  this.discoveryErrorKeys = computed(() => _nhAssistantErrorKeys(this.discoveryError()), ...(ngDevMode ? [{ debugName: "discoveryErrorKeys" }] : []));
4205
4520
  inject(DestroyRef).onDestroy(() => {
4206
4521
  this.subscription?.unsubscribe();
4207
4522
  this.discoverySubscription?.unsubscribe();
4208
4523
  this.modesSubscription?.unsubscribe();
4524
+ this.toolsSubscription?.unsubscribe();
4209
4525
  });
4210
4526
  // The application's own modes; without them the editor offers the built-in modes.
4211
4527
  this.modesSubscription = this.admin.getMcpAuthModes().subscribe({
@@ -4231,7 +4547,36 @@ class NhAssistantAdminMcpServerEditorComponent {
4231
4547
  }
4232
4548
  /** The id of a field's error, for `aria-describedby`. */
4233
4549
  errorId(field) {
4234
- return `${this.id}-${field.replace('.', '-')}-error`;
4550
+ return `${this.id}-${field.replace(/[^A-Za-z0-9-]+/g, '-')}-error`;
4551
+ }
4552
+ /** The name of a reader's field in the server's errors, such as `readers[0].toolName`. */
4553
+ readerField(index, field) {
4554
+ return `readers[${index}].${field}`;
4555
+ }
4556
+ /** Adds an empty reader at the end, at priority 0, and moves the focus to its tool. */
4557
+ addReader() {
4558
+ if (this.readers().length >= maxReaders) {
4559
+ return;
4560
+ }
4561
+ this.forgetReaderErrors();
4562
+ const key = nextReaderKey++;
4563
+ this.readers.set([...this.readers(), { key, toolName: '', mediaTypes: '', maxClassification: '', priority: '0' }]);
4564
+ this.focusById(`${this.id}-reader-tool-${key}`);
4565
+ }
4566
+ /**
4567
+ * Removes a reader and moves the focus to the button that adds one; the server's errors of the
4568
+ * readers no longer match their positions.
4569
+ */
4570
+ removeReader(index) {
4571
+ this.forgetReaderErrors();
4572
+ this.readers.set(this.readers().filter((_, position) => position !== index));
4573
+ this.focusById(`${this.id}-reader-add`);
4574
+ }
4575
+ /** Changes one field of a reader as the administrator typed or chose it. */
4576
+ updateReader(index, field, value) {
4577
+ // The classification comes from the select's options, the empty choice included.
4578
+ this.readers.set(this.readers().map((reader, position) => position === index ? { ...reader, [field]: value } : reader));
4579
+ this.touch(this.readerField(index, field));
4235
4580
  }
4236
4581
  /** The ids a control describes itself with: its hint and, while the server refused it, its error. */
4237
4582
  describedBy(hintId, field) {
@@ -4358,6 +4703,15 @@ class NhAssistantAdminMcpServerEditorComponent {
4358
4703
  input.connectionScope = authMode === 'oauth' ? this.connectionScope() : 'organization';
4359
4704
  input.oauth = this.oauthInput();
4360
4705
  }
4706
+ if (!this.isNew()) {
4707
+ // Every save sends the readers as shown; none removes them all.
4708
+ input.readers = this.readers().map(reader => ({
4709
+ mediaTypes: splitMediaTypes(reader.mediaTypes),
4710
+ toolName: reader.toolName,
4711
+ maxClassification: reader.maxClassification || null,
4712
+ priority: parsePriority(reader.priority) ?? 0
4713
+ }));
4714
+ }
4361
4715
  const existing = this.server();
4362
4716
  const request = existing ? this.admin.updateMcpServer(existing.id, input) : this.admin.createMcpServer(input);
4363
4717
  this.saving.set(true);
@@ -4381,9 +4735,24 @@ class NhAssistantAdminMcpServerEditorComponent {
4381
4735
  focusFirstInvalid() {
4382
4736
  afterNextRender(() => focusFirstInvalid(this.host.nativeElement.querySelector('form')), { injector: this.injector });
4383
4737
  }
4738
+ focusById(id) {
4739
+ afterNextRender(() => this.host.nativeElement.querySelector(`[id="${id}"]`)?.focus(), { injector: this.injector });
4740
+ }
4384
4741
  valueKeys(value) {
4385
4742
  return [`nh-assistant.admin.run-config.field-errors.${value}`, 'nh-assistant.errors.generic'];
4386
4743
  }
4744
+ /** Whether the editor shows a field error at a reader's own field. */
4745
+ showsReaderField(field) {
4746
+ const match = /^readers\[(\d+)\]\./.exec(field);
4747
+ return match !== null && readerFieldPattern.test(field) && Number(match[1]) < this.readers().length;
4748
+ }
4749
+ /** The server's errors of the readers no longer apply once a reader is added or removed. */
4750
+ forgetReaderErrors() {
4751
+ const readerFields = Object.keys(this.serverErrors()).filter(field => field.startsWith('readers'));
4752
+ if (readerFields.length > 0) {
4753
+ this.touched.set(new Set([...this.touched(), ...readerFields]));
4754
+ }
4755
+ }
4387
4756
  reset(server) {
4388
4757
  this.serverId.set(server?.id ?? '');
4389
4758
  this.displayName.set(server?.displayName ?? '');
@@ -4413,10 +4782,30 @@ class NhAssistantAdminMcpServerEditorComponent {
4413
4782
  this.discovery.set(null);
4414
4783
  this.discoveryError.set(null);
4415
4784
  this.confirmAuthorization.set(false);
4785
+ this.readers.set((server?.readers ?? []).map(reader => ({
4786
+ key: nextReaderKey++,
4787
+ toolName: reader.toolName,
4788
+ mediaTypes: reader.mediaTypes.join(', '),
4789
+ maxClassification: reader.maxClassification,
4790
+ priority: String(reader.priority)
4791
+ })));
4792
+ this.loadReaderTools(server);
4416
4793
  this.submitted.set(false);
4417
4794
  this.error.set(null);
4418
4795
  this.touched.set(new Set());
4419
4796
  }
4797
+ /** The synced tools of an existing server, to choose the reading tool from. */
4798
+ loadReaderTools(server) {
4799
+ this.toolsSubscription?.unsubscribe();
4800
+ this.readerTools.set([]);
4801
+ if (server === null) {
4802
+ return;
4803
+ }
4804
+ this.toolsSubscription = this.admin.getMcpTools(server.id).subscribe({
4805
+ next: tools => this.readerTools.set(tools),
4806
+ error: () => this.readerTools.set([])
4807
+ });
4808
+ }
4420
4809
  /**
4421
4810
  * The OAuth settings as the editor shows them: every value is sent, so an emptied field clears the
4422
4811
  * stored value. The client secret is write-only: sent only when replaced.
@@ -4444,15 +4833,36 @@ class NhAssistantAdminMcpServerEditorComponent {
4444
4833
  return input;
4445
4834
  }
4446
4835
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminMcpServerEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4447
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAdminMcpServerEditorComponent, isStandalone: true, selector: "nh-assistant-admin-mcp-server-editor", inputs: { server: { classPropertyName: "server", publicName: "server", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, ngImport: i0, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" autocomplete=\"off\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (server(); as current) {\n {{ 'nh-assistant.admin.server-editor.edit-title' | translate: { name: current.displayName } }}\n } @else {\n {{ 'nh-assistant.admin.server-editor.new-title' | translate }}\n }\n </h3>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.server-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-id'\"\n [maxLength]=\"limits.id\"\n [value]=\"serverId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id')\"\n [attr.aria-invalid]=\"(submitted() && idInvalid()) || serverInvalid('id') ? true : null\"\n (input)=\"serverId.set(value($event)); touch('id')\" />\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.server-editor.id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('id')) {\n <p class=\"field-error\" [id]=\"errorId('id')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('id') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.server-editor.display-name' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [maxLength]=\"limits.displayName\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"(submitted() && nameMissing()) || serverInvalid('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-name-hint', 'displayName')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\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 @if (serverInvalid('displayName')) {\n <p class=\"field-error\" [id]=\"errorId('displayName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('displayName') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-url'\">{{ 'nh-assistant.admin.server-editor.url' | translate }}</label>\n <input\n type=\"url\"\n class=\"mono\"\n inputmode=\"url\"\n [id]=\"id + '-url'\"\n [maxLength]=\"limits.url\"\n [value]=\"url()\"\n [attr.aria-describedby]=\"describedBy(id + '-url-hint', 'url')\"\n [attr.aria-invalid]=\"(submitted() && urlInvalid()) || serverInvalid('url') ? true : null\"\n (input)=\"onUrlInput($event); touch('url')\" />\n <p class=\"hint\" [id]=\"id + '-url-hint'\">\n <span [class.error-text]=\"submitted() && urlInvalid()\">\n {{ (submitted() && urlInvalid() ? 'nh-assistant.admin.server-editor.url-invalid' : 'nh-assistant.admin.server-editor.url-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('url')) {\n <p class=\"field-error\" [id]=\"errorId('url')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('url') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-auth'\">{{ 'nh-assistant.admin.server-editor.auth-mode' | translate }}</label>\n <select\n [id]=\"id + '-auth'\"\n [attr.aria-describedby]=\"describedBy(null, 'authMode')\"\n [attr.aria-invalid]=\"serverInvalid('authMode') ? true : null\"\n (change)=\"authMode.set($any(value($event))); touch('authMode')\">\n @for (mode of authModes(); track mode) {\n <option [value]=\"mode\" [selected]=\"authMode() === mode\">{{ ['nh-assistant.admin.mcp.auth.' + mode] | nhAssistantTranslate: mode }}</option>\n }\n </select>\n @if (customOwnership(); as ownership) {\n <p class=\"hint\" data-custom-auth-mode>{{ 'nh-assistant.admin.server-editor.custom-auth.' + ownership | translate }}</p>\n }\n @if (serverInvalid('authMode')) {\n <p class=\"field-error\" [id]=\"errorId('authMode')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('authMode') | nhAssistantTranslate }}</p>\n }\n </div>\n\n @if (authMode() === 'api-key') {\n <div class=\"field\">\n <label [for]=\"id + '-header'\">{{ 'nh-assistant.admin.server-editor.header-name' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n placeholder=\"X-Api-Key\"\n [id]=\"id + '-header'\"\n [maxLength]=\"limits.headerName\"\n [value]=\"headerName()\"\n [attr.aria-describedby]=\"describedBy(id + '-header-hint', 'headerName')\"\n [attr.aria-invalid]=\"(submitted() && headerNameInvalid()) || serverInvalid('headerName') ? true : null\"\n (input)=\"headerName.set(value($event)); touch('headerName')\" />\n <p class=\"hint\" [id]=\"id + '-header-hint'\">\n <span [class.error-text]=\"submitted() && headerNameInvalid()\">\n {{ (submitted() && headerNameInvalid() ? 'nh-assistant.admin.server-editor.header-name-invalid' : 'nh-assistant.admin.server-editor.header-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('headerName')) {\n <p class=\"field-error\" [id]=\"errorId('headerName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headerName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n\n @if (authMode() === 'basic') {\n <div class=\"field\">\n <label [for]=\"id + '-user'\">{{ 'nh-assistant.admin.server-editor.user-name' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [id]=\"id + '-user'\"\n [maxLength]=\"limits.userName\"\n [value]=\"userName()\"\n [attr.aria-describedby]=\"describedBy(id + '-user-hint', 'userName')\"\n [attr.aria-invalid]=\"(submitted() && userNameInvalid()) || serverInvalid('userName') ? true : null\"\n (input)=\"userName.set(value($event)); touch('userName')\" />\n <p class=\"hint\" [id]=\"id + '-user-hint'\">\n <span [class.error-text]=\"submitted() && userNameInvalid()\">\n {{ (submitted() && userNameInvalid() ? 'nh-assistant.admin.server-editor.user-name-invalid' : 'nh-assistant.admin.server-editor.user-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('userName')) {\n <p class=\"field-error\" [id]=\"errorId('userName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('userName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n </div>\n\n @if (authMode() === 'forward-user-token') {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.forward-warning' | translate }}</p>\n }\n\n @if (isOAuth()) {\n <fieldset class=\"field\">\n <legend>OAuth</legend>\n\n @if (authMode() === 'oauth') {\n <div\n class=\"inline\"\n role=\"radiogroup\"\n [attr.aria-label]=\"'nh-assistant.admin.server-editor.connection-scope' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-scope-hint', 'connectionScope')\">\n @for (scope of connectionScopes; track scope) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-connection-scope'\"\n [value]=\"scope\"\n [checked]=\"connectionScope() === scope\"\n [attr.aria-invalid]=\"serverInvalid('connectionScope') ? true : null\"\n (change)=\"connectionScope.set(scope); touch('connectionScope')\" />\n <span>{{ 'nh-assistant.admin.mcp.connection-scope.' + scope | translate }}</span>\n </label>\n }\n </div>\n <p class=\"hint\" [id]=\"id + '-scope-hint'\">{{ 'nh-assistant.admin.server-editor.connection-scope-hint' | translate }}</p>\n @if (serverInvalid('connectionScope')) {\n <p class=\"field-error\" [id]=\"errorId('connectionScope')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('connectionScope') | nhAssistantTranslate }}</p>\n }\n }\n\n @if (isOrganizationOAuth()) {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.oauth-warning' | translate }}</p>\n <label [for]=\"id + '-account-label'\">{{ 'nh-assistant.admin.server-editor.organization-account-label' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-account-label'\"\n [maxLength]=\"limits.organizationAccountLabel\"\n [value]=\"organizationAccountLabel()\"\n [attr.aria-describedby]=\"describedBy(id + '-account-label-hint', 'oauth.organizationAccountLabel')\"\n [attr.aria-invalid]=\"(submitted() && labelMissing()) || serverInvalid('oauth.organizationAccountLabel') ? true : null\"\n (input)=\"organizationAccountLabel.set(value($event)); touch('oauth.organizationAccountLabel')\" />\n <p class=\"hint\" [id]=\"id + '-account-label-hint'\">\n <span [class.error-text]=\"submitted() && labelMissing()\">\n {{ (submitted() && labelMissing() ? 'nh-assistant.admin.server-editor.organization-account-label-required' : 'nh-assistant.admin.server-editor.organization-account-label-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.organizationAccountLabel')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.organizationAccountLabel')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.organizationAccountLabel') | nhAssistantTranslate }}</p>\n }\n }\n\n <div class=\"meta\">\n @if (server()?.authorization; as confirmed) {\n @if (!needsConfirmation()) {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.confirmed-authorization' | translate: { issuer: confirmed.issuer } }}</span>\n }\n }\n <button class=\"secondary\" type=\"button\" [disabled]=\"discovering() || urlInvalid()\" (click)=\"discover()\">\n <nh-assistant-icon name=\"link\" />{{ (discovering() ? 'nh-assistant.admin.server-editor.discovering' : 'nh-assistant.admin.server-editor.discover') | translate }}\n </button>\n </div>\n @if (discoveryError(); as failure) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ discoveryErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n @if (discovery(); as found) {\n <div class=\"discovery\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.discovery-title' | translate\">\n <dl>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-issuer' | translate }}</dt>\n <dd class=\"mono\">{{ found.issuer }}</dd>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-resource' | translate }}</dt>\n <dd class=\"mono\">{{ found.resource }}</dd>\n @if (found.scopesSupported.length > 0) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-scopes' | translate }}</dt>\n <dd class=\"mono\">{{ found.scopesSupported.join(' ') }}</dd>\n }\n @if (authMode() === 'oauth' && registration(); as kind) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-registration' | translate }}</dt>\n <dd>{{ 'nh-assistant.admin.server-editor.registration-' + kind | translate }}</dd>\n }\n </dl>\n @if (pkceMissing()) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.pkce-missing' | translate }}</p>\n } @else {\n <label class=\"check\">\n <input\n type=\"checkbox\"\n [checked]=\"confirmAuthorization()\"\n [attr.aria-describedby]=\"describedBy(id + '-confirm-hint', 'oauth.confirmAuthorization')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.confirmAuthorization') ? true : null\"\n (change)=\"confirmAuthorization.set(checked($event)); touch('oauth.confirmAuthorization')\" />\n <span>{{ 'nh-assistant.admin.server-editor.confirm-authorization' | translate }}</span>\n </label>\n <p class=\"hint\" [id]=\"id + '-confirm-hint'\">{{ 'nh-assistant.admin.server-editor.confirm-authorization-hint' | translate }}</p>\n }\n </div>\n }\n @if (submitted() && confirmMissing()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</span></p>\n } @else if (serverInvalid('oauth.confirmAuthorization')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.confirmAuthorization')\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</p>\n }\n\n <label [for]=\"id + '-scopes'\">{{ 'nh-assistant.admin.server-editor.scopes' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-scopes'\"\n [maxLength]=\"limits.scopes\"\n [value]=\"oauthScopes()\"\n [attr.aria-describedby]=\"describedBy(id + '-scopes-hint', 'oauth.scopes')\"\n [attr.aria-invalid]=\"(submitted() && scopesInvalid()) || serverInvalid('oauth.scopes') ? true : null\"\n (input)=\"oauthScopes.set(value($event)); touch('oauth.scopes')\" />\n <p class=\"hint\" [id]=\"id + '-scopes-hint'\">\n <span [class.error-text]=\"submitted() && scopesInvalid()\">\n {{ (submitted() && scopesInvalid() ? 'nh-assistant.admin.server-editor.scopes-invalid' : 'nh-assistant.admin.server-editor.scopes-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.scopes')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.scopes')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.scopes') | nhAssistantTranslate }}</p>\n }\n\n <label [for]=\"id + '-client-id'\">{{ 'nh-assistant.admin.server-editor.client-id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-client-id'\"\n [maxLength]=\"limits.clientId\"\n [value]=\"oauthClientId()\"\n [attr.aria-describedby]=\"describedBy(id + '-client-id-hint', 'oauth.clientId')\"\n [attr.aria-invalid]=\"(submitted() && clientIdMissing()) || serverInvalid('oauth.clientId') ? true : null\"\n (input)=\"oauthClientId.set(value($event)); touch('oauth.clientId')\" />\n <p class=\"hint\" [id]=\"id + '-client-id-hint'\">\n <span [class.error-text]=\"submitted() && clientIdMissing()\">\n {{ (submitted() && clientIdMissing() ? 'nh-assistant.admin.server-editor.client-id-required' : 'nh-assistant.admin.server-editor.client-id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.clientId')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientId')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientId') | nhAssistantTranslate }}</p>\n }\n\n @if (oauthClientId().trim().length > 0) {\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.client-secret' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-oauth-secret-source'\"\n [value]=\"source\"\n [checked]=\"oauthSecretSource() === source\"\n (change)=\"setOAuthSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesOAuthReference()) {\n <label [for]=\"id + '-oauth-reference'\">{{ 'nh-assistant.admin.server-editor.client-secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-client-secret\"\n [id]=\"id + '-oauth-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"oauthSecretReference()\"\n [attr.aria-describedby]=\"describedBy(null, 'oauth.clientSecretReference')\"\n [attr.aria-invalid]=\"(submitted() && oauthReferenceInvalid()) || serverInvalid('oauth.clientSecretReference') ? true : null\"\n (input)=\"oauthSecretReference.set(value($event)); touch('oauth.clientSecretReference')\" />\n @if (submitted() && oauthReferenceInvalid()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.secret-reference-invalid' | translate }}</span></p>\n }\n @if (serverInvalid('oauth.clientSecretReference')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecretReference') | nhAssistantTranslate }}</p>\n }\n } @else {\n @if (hasOAuthSecret() && oauthSecretAction() === 'keep') {\n <div class=\"meta secret-state\">\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"oauthSecretAction.set('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n </div>\n }\n @if (showOAuthSecretInput()) {\n <label [for]=\"id + '-oauth-secret'\">{{ 'nh-assistant.admin.server-editor.client-secret' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-oauth-secret'\"\n [maxLength]=\"limits.clientSecret\"\n [attr.aria-describedby]=\"describedBy(id + '-oauth-secret-hint', 'oauth.clientSecret')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.clientSecret') ? true : null\"\n [value]=\"oauthSecret()\"\n (input)=\"onOAuthSecretInput($event); touch('oauth.clientSecret')\" />\n }\n <p class=\"hint\" [id]=\"id + '-oauth-secret-hint'\">{{ 'nh-assistant.admin.server-editor.client-secret-hint' | translate }}</p>\n }\n }\n @if (serverInvalid('oauth.clientSecret')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n @if (usesSecret()) {\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.server-editor.secret' | translate }}</legend>\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.secret-source' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-secret-source'\"\n [value]=\"source\"\n [checked]=\"secretSource() === source\"\n (change)=\"setSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesReference()) {\n <label [for]=\"id + '-secret-reference'\">{{ 'nh-assistant.admin.server-editor.secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-token\"\n [id]=\"id + '-secret-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"secretReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-reference-hint', 'secretReference')\"\n [attr.aria-invalid]=\"(submitted() && secretReferenceInvalid()) || serverInvalid('secretReference') ? true : null\"\n (input)=\"secretReference.set(value($event)); touch('secretReference')\" />\n <p class=\"hint\" [id]=\"id + '-secret-reference-hint'\">\n <span [class.error-text]=\"submitted() && secretReferenceInvalid()\">\n {{ (submitted() && secretReferenceInvalid() ? 'nh-assistant.admin.server-editor.secret-reference-invalid' : 'nh-assistant.admin.server-editor.secret-reference-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('secretReference')) {\n <p class=\"field-error\" [id]=\"errorId('secretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secretReference') | nhAssistantTranslate }}</p>\n }\n } @else if (hasSecret()) {\n <div class=\"meta secret-state\">\n @switch (secretAction()) {\n @case ('clear') {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.server-editor.secret-will-clear' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @case ('replace') {\n <span class=\"badge\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @default {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <!-- A mode with a secret always needs one: it is replaced, or removed by choosing a reference or another mode. -->\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n }\n }\n </div>\n } @else {\n <p class=\"muted\">{{ 'nh-assistant.admin.server-editor.secret-none' | translate }}</p>\n }\n @if (showSecretInput()) {\n <label class=\"visually-hidden\" [for]=\"id + '-secret'\">{{ 'nh-assistant.admin.server-editor.secret-new' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-secret'\"\n [maxLength]=\"limits.secret\"\n [attr.placeholder]=\"'nh-assistant.admin.server-editor.secret-new' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-hint', 'secret')\"\n [attr.aria-invalid]=\"serverInvalid('secret') ? true : null\"\n [value]=\"secret()\"\n (input)=\"onSecretInput($event); touch('secret')\" />\n }\n @if (!usesReference()) {\n <p class=\"hint\" [id]=\"id + '-secret-hint'\">{{ 'nh-assistant.admin.server-editor.secret-hint' | translate }}</p>\n }\n @if (serverInvalid('secret')) {\n <p class=\"field-error\" [id]=\"errorId('secret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-certificate'\">{{ 'nh-assistant.admin.server-editor.client-certificate' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-certificate'\"\n [maxLength]=\"limits.clientCertificateReference\"\n [value]=\"clientCertificateReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-certificate-hint', 'clientCertificateReference')\"\n [attr.aria-invalid]=\"(submitted() && certificateInvalid()) || serverInvalid('clientCertificateReference') ? true : null\"\n (input)=\"clientCertificateReference.set(value($event)); touch('clientCertificateReference')\" />\n <p class=\"hint\" [id]=\"id + '-certificate-hint'\">\n <span [class.error-text]=\"submitted() && certificateInvalid()\">\n {{ (submitted() && certificateInvalid() ? 'nh-assistant.admin.server-editor.client-certificate-invalid' : 'nh-assistant.admin.server-editor.client-certificate-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('clientCertificateReference')) {\n <p class=\"field-error\" [id]=\"errorId('clientCertificateReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('clientCertificateReference') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-transport'\">{{ 'nh-assistant.admin.server-editor.transport' | translate }}</label>\n <select\n [id]=\"id + '-transport'\"\n [attr.aria-describedby]=\"describedBy(id + '-transport-hint', 'transport')\"\n [attr.aria-invalid]=\"serverInvalid('transport') ? true : null\"\n (change)=\"transport.set($any(value($event))); touch('transport')\">\n @for (option of transports; track option) {\n <option [value]=\"option\" [selected]=\"transport() === option\">{{ 'nh-assistant.admin.mcp.transport.' + option | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-transport-hint'\">{{ 'nh-assistant.admin.server-editor.transport-hint' | translate }}</p>\n @if (serverInvalid('transport')) {\n <p class=\"field-error\" [id]=\"errorId('transport')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('transport') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.server-editor.required-policy' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-policy'\"\n [maxLength]=\"limits.requiredPolicy\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"describedBy(id + '-policy-hint', 'requiredPolicy')\"\n [attr.aria-invalid]=\"serverInvalid('requiredPolicy') ? true : null\"\n (input)=\"requiredPolicy.set(value($event)); touch('requiredPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.server-editor.required-policy-hint' | translate }}</p>\n @if (serverInvalid('requiredPolicy')) {\n <p class=\"field-error\" [id]=\"errorId('requiredPolicy')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('requiredPolicy') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-headless'\">{{ 'nh-assistant.admin.server-editor.headless-use' | translate }}</label>\n <select\n [id]=\"id + '-headless'\"\n [attr.aria-describedby]=\"describedBy(id + '-headless-hint', 'headlessUse')\"\n [attr.aria-invalid]=\"serverInvalid('headlessUse') ? true : null\"\n (change)=\"headlessUse.set($any(value($event))); touch('headlessUse')\">\n @for (use of headlessUses(); track use) {\n <option [value]=\"use\" [selected]=\"effectiveHeadlessUse() === use\">{{ 'nh-assistant.admin.mcp.headless.' + use | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-headless-hint'\">\n {{ (personalCredential() ? 'nh-assistant.admin.server-editor.headless-use-personal' : 'nh-assistant.admin.server-editor.headless-use-hint') | translate }}\n </p>\n @if (serverInvalid('headlessUse')) {\n <p class=\"field-error\" [id]=\"errorId('headlessUse')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headlessUse') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"isEnabled()\" (change)=\"isEnabled.set(checked($event))\" />\n <span>{{ 'nh-assistant.admin.server-editor.enabled' | translate }}</span>\n </label>\n\n @if (error(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-server-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <span>{{ errorKeys() | nhAssistantTranslate: failure.code }}</span>\n @if (otherServerErrors().length > 0) {\n <ul>\n @for (other of otherServerErrors(); track other.field) {\n <li><code class=\"mono\">{{ other.field }}</code>: {{ other.keys | nhAssistantTranslate }}</li>\n }\n </ul>\n }\n </div>\n </div>\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()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\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: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4836
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: NhAssistantAdminMcpServerEditorComponent, isStandalone: true, selector: "nh-assistant-admin-mcp-server-editor", inputs: { server: { classPropertyName: "server", publicName: "server", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, ngImport: i0, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" autocomplete=\"off\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (server(); as current) {\n {{ 'nh-assistant.admin.server-editor.edit-title' | translate: { name: current.displayName } }}\n } @else {\n {{ 'nh-assistant.admin.server-editor.new-title' | translate }}\n }\n </h3>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.server-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-id'\"\n [maxLength]=\"limits.id\"\n [value]=\"serverId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id')\"\n [attr.aria-invalid]=\"(submitted() && idInvalid()) || serverInvalid('id') ? true : null\"\n (input)=\"serverId.set(value($event)); touch('id')\" />\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.server-editor.id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('id')) {\n <p class=\"field-error\" [id]=\"errorId('id')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('id') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.server-editor.display-name' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [maxLength]=\"limits.displayName\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"(submitted() && nameMissing()) || serverInvalid('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-name-hint', 'displayName')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\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 @if (serverInvalid('displayName')) {\n <p class=\"field-error\" [id]=\"errorId('displayName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('displayName') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-url'\">{{ 'nh-assistant.admin.server-editor.url' | translate }}</label>\n <input\n type=\"url\"\n class=\"mono\"\n inputmode=\"url\"\n [id]=\"id + '-url'\"\n [maxLength]=\"limits.url\"\n [value]=\"url()\"\n [attr.aria-describedby]=\"describedBy(id + '-url-hint', 'url')\"\n [attr.aria-invalid]=\"(submitted() && urlInvalid()) || serverInvalid('url') ? true : null\"\n (input)=\"onUrlInput($event); touch('url')\" />\n <p class=\"hint\" [id]=\"id + '-url-hint'\">\n <span [class.error-text]=\"submitted() && urlInvalid()\">\n {{ (submitted() && urlInvalid() ? 'nh-assistant.admin.server-editor.url-invalid' : 'nh-assistant.admin.server-editor.url-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('url')) {\n <p class=\"field-error\" [id]=\"errorId('url')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('url') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-auth'\">{{ 'nh-assistant.admin.server-editor.auth-mode' | translate }}</label>\n <select\n [id]=\"id + '-auth'\"\n [attr.aria-describedby]=\"describedBy(null, 'authMode')\"\n [attr.aria-invalid]=\"serverInvalid('authMode') ? true : null\"\n (change)=\"authMode.set($any(value($event))); touch('authMode')\">\n @for (mode of authModes(); track mode) {\n <option [value]=\"mode\" [selected]=\"authMode() === mode\">{{ ['nh-assistant.admin.mcp.auth.' + mode] | nhAssistantTranslate: mode }}</option>\n }\n </select>\n @if (customOwnership(); as ownership) {\n <p class=\"hint\" data-custom-auth-mode>{{ 'nh-assistant.admin.server-editor.custom-auth.' + ownership | translate }}</p>\n }\n @if (serverInvalid('authMode')) {\n <p class=\"field-error\" [id]=\"errorId('authMode')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('authMode') | nhAssistantTranslate }}</p>\n }\n </div>\n\n @if (authMode() === 'api-key') {\n <div class=\"field\">\n <label [for]=\"id + '-header'\">{{ 'nh-assistant.admin.server-editor.header-name' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n placeholder=\"X-Api-Key\"\n [id]=\"id + '-header'\"\n [maxLength]=\"limits.headerName\"\n [value]=\"headerName()\"\n [attr.aria-describedby]=\"describedBy(id + '-header-hint', 'headerName')\"\n [attr.aria-invalid]=\"(submitted() && headerNameInvalid()) || serverInvalid('headerName') ? true : null\"\n (input)=\"headerName.set(value($event)); touch('headerName')\" />\n <p class=\"hint\" [id]=\"id + '-header-hint'\">\n <span [class.error-text]=\"submitted() && headerNameInvalid()\">\n {{ (submitted() && headerNameInvalid() ? 'nh-assistant.admin.server-editor.header-name-invalid' : 'nh-assistant.admin.server-editor.header-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('headerName')) {\n <p class=\"field-error\" [id]=\"errorId('headerName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headerName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n\n @if (authMode() === 'basic') {\n <div class=\"field\">\n <label [for]=\"id + '-user'\">{{ 'nh-assistant.admin.server-editor.user-name' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [id]=\"id + '-user'\"\n [maxLength]=\"limits.userName\"\n [value]=\"userName()\"\n [attr.aria-describedby]=\"describedBy(id + '-user-hint', 'userName')\"\n [attr.aria-invalid]=\"(submitted() && userNameInvalid()) || serverInvalid('userName') ? true : null\"\n (input)=\"userName.set(value($event)); touch('userName')\" />\n <p class=\"hint\" [id]=\"id + '-user-hint'\">\n <span [class.error-text]=\"submitted() && userNameInvalid()\">\n {{ (submitted() && userNameInvalid() ? 'nh-assistant.admin.server-editor.user-name-invalid' : 'nh-assistant.admin.server-editor.user-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('userName')) {\n <p class=\"field-error\" [id]=\"errorId('userName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('userName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n </div>\n\n @if (authMode() === 'forward-user-token') {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.forward-warning' | translate }}</p>\n }\n\n @if (isOAuth()) {\n <fieldset class=\"field\">\n <legend>OAuth</legend>\n\n @if (authMode() === 'oauth') {\n <div\n class=\"inline\"\n role=\"radiogroup\"\n [attr.aria-label]=\"'nh-assistant.admin.server-editor.connection-scope' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-scope-hint', 'connectionScope')\">\n @for (scope of connectionScopes; track scope) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-connection-scope'\"\n [value]=\"scope\"\n [checked]=\"connectionScope() === scope\"\n [attr.aria-invalid]=\"serverInvalid('connectionScope') ? true : null\"\n (change)=\"connectionScope.set(scope); touch('connectionScope')\" />\n <span>{{ 'nh-assistant.admin.mcp.connection-scope.' + scope | translate }}</span>\n </label>\n }\n </div>\n <p class=\"hint\" [id]=\"id + '-scope-hint'\">{{ 'nh-assistant.admin.server-editor.connection-scope-hint' | translate }}</p>\n @if (serverInvalid('connectionScope')) {\n <p class=\"field-error\" [id]=\"errorId('connectionScope')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('connectionScope') | nhAssistantTranslate }}</p>\n }\n }\n\n @if (isOrganizationOAuth()) {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.oauth-warning' | translate }}</p>\n <label [for]=\"id + '-account-label'\">{{ 'nh-assistant.admin.server-editor.organization-account-label' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-account-label'\"\n [maxLength]=\"limits.organizationAccountLabel\"\n [value]=\"organizationAccountLabel()\"\n [attr.aria-describedby]=\"describedBy(id + '-account-label-hint', 'oauth.organizationAccountLabel')\"\n [attr.aria-invalid]=\"(submitted() && labelMissing()) || serverInvalid('oauth.organizationAccountLabel') ? true : null\"\n (input)=\"organizationAccountLabel.set(value($event)); touch('oauth.organizationAccountLabel')\" />\n <p class=\"hint\" [id]=\"id + '-account-label-hint'\">\n <span [class.error-text]=\"submitted() && labelMissing()\">\n {{ (submitted() && labelMissing() ? 'nh-assistant.admin.server-editor.organization-account-label-required' : 'nh-assistant.admin.server-editor.organization-account-label-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.organizationAccountLabel')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.organizationAccountLabel')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.organizationAccountLabel') | nhAssistantTranslate }}</p>\n }\n }\n\n <div class=\"meta\">\n @if (server()?.authorization; as confirmed) {\n @if (!needsConfirmation()) {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.confirmed-authorization' | translate: { issuer: confirmed.issuer } }}</span>\n }\n }\n <button class=\"secondary\" type=\"button\" [disabled]=\"discovering() || urlInvalid()\" (click)=\"discover()\">\n <nh-assistant-icon name=\"link\" />{{ (discovering() ? 'nh-assistant.admin.server-editor.discovering' : 'nh-assistant.admin.server-editor.discover') | translate }}\n </button>\n </div>\n @if (discoveryError(); as failure) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ discoveryErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n @if (discovery(); as found) {\n <div class=\"discovery\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.discovery-title' | translate\">\n <dl>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-issuer' | translate }}</dt>\n <dd class=\"mono\">{{ found.issuer }}</dd>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-resource' | translate }}</dt>\n <dd class=\"mono\">{{ found.resource }}</dd>\n @if (found.scopesSupported.length > 0) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-scopes' | translate }}</dt>\n <dd class=\"mono\">{{ found.scopesSupported.join(' ') }}</dd>\n }\n @if (authMode() === 'oauth' && registration(); as kind) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-registration' | translate }}</dt>\n <dd>{{ 'nh-assistant.admin.server-editor.registration-' + kind | translate }}</dd>\n }\n </dl>\n @if (pkceMissing()) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.pkce-missing' | translate }}</p>\n } @else {\n <label class=\"check\">\n <input\n type=\"checkbox\"\n [checked]=\"confirmAuthorization()\"\n [attr.aria-describedby]=\"describedBy(id + '-confirm-hint', 'oauth.confirmAuthorization')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.confirmAuthorization') ? true : null\"\n (change)=\"confirmAuthorization.set(checked($event)); touch('oauth.confirmAuthorization')\" />\n <span>{{ 'nh-assistant.admin.server-editor.confirm-authorization' | translate }}</span>\n </label>\n <p class=\"hint\" [id]=\"id + '-confirm-hint'\">{{ 'nh-assistant.admin.server-editor.confirm-authorization-hint' | translate }}</p>\n }\n </div>\n }\n @if (submitted() && confirmMissing()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</span></p>\n } @else if (serverInvalid('oauth.confirmAuthorization')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.confirmAuthorization')\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</p>\n }\n\n <label [for]=\"id + '-scopes'\">{{ 'nh-assistant.admin.server-editor.scopes' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-scopes'\"\n [maxLength]=\"limits.scopes\"\n [value]=\"oauthScopes()\"\n [attr.aria-describedby]=\"describedBy(id + '-scopes-hint', 'oauth.scopes')\"\n [attr.aria-invalid]=\"(submitted() && scopesInvalid()) || serverInvalid('oauth.scopes') ? true : null\"\n (input)=\"oauthScopes.set(value($event)); touch('oauth.scopes')\" />\n <p class=\"hint\" [id]=\"id + '-scopes-hint'\">\n <span [class.error-text]=\"submitted() && scopesInvalid()\">\n {{ (submitted() && scopesInvalid() ? 'nh-assistant.admin.server-editor.scopes-invalid' : 'nh-assistant.admin.server-editor.scopes-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.scopes')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.scopes')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.scopes') | nhAssistantTranslate }}</p>\n }\n\n <label [for]=\"id + '-client-id'\">{{ 'nh-assistant.admin.server-editor.client-id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-client-id'\"\n [maxLength]=\"limits.clientId\"\n [value]=\"oauthClientId()\"\n [attr.aria-describedby]=\"describedBy(id + '-client-id-hint', 'oauth.clientId')\"\n [attr.aria-invalid]=\"(submitted() && clientIdMissing()) || serverInvalid('oauth.clientId') ? true : null\"\n (input)=\"oauthClientId.set(value($event)); touch('oauth.clientId')\" />\n <p class=\"hint\" [id]=\"id + '-client-id-hint'\">\n <span [class.error-text]=\"submitted() && clientIdMissing()\">\n {{ (submitted() && clientIdMissing() ? 'nh-assistant.admin.server-editor.client-id-required' : 'nh-assistant.admin.server-editor.client-id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.clientId')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientId')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientId') | nhAssistantTranslate }}</p>\n }\n\n @if (oauthClientId().trim().length > 0) {\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.client-secret' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-oauth-secret-source'\"\n [value]=\"source\"\n [checked]=\"oauthSecretSource() === source\"\n (change)=\"setOAuthSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesOAuthReference()) {\n <label [for]=\"id + '-oauth-reference'\">{{ 'nh-assistant.admin.server-editor.client-secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-client-secret\"\n [id]=\"id + '-oauth-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"oauthSecretReference()\"\n [attr.aria-describedby]=\"describedBy(null, 'oauth.clientSecretReference')\"\n [attr.aria-invalid]=\"(submitted() && oauthReferenceInvalid()) || serverInvalid('oauth.clientSecretReference') ? true : null\"\n (input)=\"oauthSecretReference.set(value($event)); touch('oauth.clientSecretReference')\" />\n @if (submitted() && oauthReferenceInvalid()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.secret-reference-invalid' | translate }}</span></p>\n }\n @if (serverInvalid('oauth.clientSecretReference')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecretReference') | nhAssistantTranslate }}</p>\n }\n } @else {\n @if (hasOAuthSecret() && oauthSecretAction() === 'keep') {\n <div class=\"meta secret-state\">\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"oauthSecretAction.set('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n </div>\n }\n @if (showOAuthSecretInput()) {\n <label [for]=\"id + '-oauth-secret'\">{{ 'nh-assistant.admin.server-editor.client-secret' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-oauth-secret'\"\n [maxLength]=\"limits.clientSecret\"\n [attr.aria-describedby]=\"describedBy(id + '-oauth-secret-hint', 'oauth.clientSecret')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.clientSecret') ? true : null\"\n [value]=\"oauthSecret()\"\n (input)=\"onOAuthSecretInput($event); touch('oauth.clientSecret')\" />\n }\n <p class=\"hint\" [id]=\"id + '-oauth-secret-hint'\">{{ 'nh-assistant.admin.server-editor.client-secret-hint' | translate }}</p>\n }\n }\n @if (serverInvalid('oauth.clientSecret')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n @if (usesSecret()) {\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.server-editor.secret' | translate }}</legend>\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.secret-source' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-secret-source'\"\n [value]=\"source\"\n [checked]=\"secretSource() === source\"\n (change)=\"setSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesReference()) {\n <label [for]=\"id + '-secret-reference'\">{{ 'nh-assistant.admin.server-editor.secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-token\"\n [id]=\"id + '-secret-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"secretReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-reference-hint', 'secretReference')\"\n [attr.aria-invalid]=\"(submitted() && secretReferenceInvalid()) || serverInvalid('secretReference') ? true : null\"\n (input)=\"secretReference.set(value($event)); touch('secretReference')\" />\n <p class=\"hint\" [id]=\"id + '-secret-reference-hint'\">\n <span [class.error-text]=\"submitted() && secretReferenceInvalid()\">\n {{ (submitted() && secretReferenceInvalid() ? 'nh-assistant.admin.server-editor.secret-reference-invalid' : 'nh-assistant.admin.server-editor.secret-reference-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('secretReference')) {\n <p class=\"field-error\" [id]=\"errorId('secretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secretReference') | nhAssistantTranslate }}</p>\n }\n } @else if (hasSecret()) {\n <div class=\"meta secret-state\">\n @switch (secretAction()) {\n @case ('clear') {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.server-editor.secret-will-clear' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @case ('replace') {\n <span class=\"badge\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @default {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <!-- A mode with a secret always needs one: it is replaced, or removed by choosing a reference or another mode. -->\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n }\n }\n </div>\n } @else {\n <p class=\"muted\">{{ 'nh-assistant.admin.server-editor.secret-none' | translate }}</p>\n }\n @if (showSecretInput()) {\n <label class=\"visually-hidden\" [for]=\"id + '-secret'\">{{ 'nh-assistant.admin.server-editor.secret-new' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-secret'\"\n [maxLength]=\"limits.secret\"\n [attr.placeholder]=\"'nh-assistant.admin.server-editor.secret-new' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-hint', 'secret')\"\n [attr.aria-invalid]=\"serverInvalid('secret') ? true : null\"\n [value]=\"secret()\"\n (input)=\"onSecretInput($event); touch('secret')\" />\n }\n @if (!usesReference()) {\n <p class=\"hint\" [id]=\"id + '-secret-hint'\">{{ 'nh-assistant.admin.server-editor.secret-hint' | translate }}</p>\n }\n @if (serverInvalid('secret')) {\n <p class=\"field-error\" [id]=\"errorId('secret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-certificate'\">{{ 'nh-assistant.admin.server-editor.client-certificate' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-certificate'\"\n [maxLength]=\"limits.clientCertificateReference\"\n [value]=\"clientCertificateReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-certificate-hint', 'clientCertificateReference')\"\n [attr.aria-invalid]=\"(submitted() && certificateInvalid()) || serverInvalid('clientCertificateReference') ? true : null\"\n (input)=\"clientCertificateReference.set(value($event)); touch('clientCertificateReference')\" />\n <p class=\"hint\" [id]=\"id + '-certificate-hint'\">\n <span [class.error-text]=\"submitted() && certificateInvalid()\">\n {{ (submitted() && certificateInvalid() ? 'nh-assistant.admin.server-editor.client-certificate-invalid' : 'nh-assistant.admin.server-editor.client-certificate-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('clientCertificateReference')) {\n <p class=\"field-error\" [id]=\"errorId('clientCertificateReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('clientCertificateReference') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-transport'\">{{ 'nh-assistant.admin.server-editor.transport' | translate }}</label>\n <select\n [id]=\"id + '-transport'\"\n [attr.aria-describedby]=\"describedBy(id + '-transport-hint', 'transport')\"\n [attr.aria-invalid]=\"serverInvalid('transport') ? true : null\"\n (change)=\"transport.set($any(value($event))); touch('transport')\">\n @for (option of transports; track option) {\n <option [value]=\"option\" [selected]=\"transport() === option\">{{ 'nh-assistant.admin.mcp.transport.' + option | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-transport-hint'\">{{ 'nh-assistant.admin.server-editor.transport-hint' | translate }}</p>\n @if (serverInvalid('transport')) {\n <p class=\"field-error\" [id]=\"errorId('transport')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('transport') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.server-editor.required-policy' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-policy'\"\n [maxLength]=\"limits.requiredPolicy\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"describedBy(id + '-policy-hint', 'requiredPolicy')\"\n [attr.aria-invalid]=\"serverInvalid('requiredPolicy') ? true : null\"\n (input)=\"requiredPolicy.set(value($event)); touch('requiredPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.server-editor.required-policy-hint' | translate }}</p>\n @if (serverInvalid('requiredPolicy')) {\n <p class=\"field-error\" [id]=\"errorId('requiredPolicy')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('requiredPolicy') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-headless'\">{{ 'nh-assistant.admin.server-editor.headless-use' | translate }}</label>\n <select\n [id]=\"id + '-headless'\"\n [attr.aria-describedby]=\"describedBy(id + '-headless-hint', 'headlessUse')\"\n [attr.aria-invalid]=\"serverInvalid('headlessUse') ? true : null\"\n (change)=\"headlessUse.set($any(value($event))); touch('headlessUse')\">\n @for (use of headlessUses(); track use) {\n <option [value]=\"use\" [selected]=\"effectiveHeadlessUse() === use\">{{ 'nh-assistant.admin.mcp.headless.' + use | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-headless-hint'\">\n {{ (personalCredential() ? 'nh-assistant.admin.server-editor.headless-use-personal' : 'nh-assistant.admin.server-editor.headless-use-hint') | translate }}\n </p>\n @if (serverInvalid('headlessUse')) {\n <p class=\"field-error\" [id]=\"errorId('headlessUse')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headlessUse') | nhAssistantTranslate }}</p>\n }\n </div>\n\n @if (!isNew()) {\n <fieldset class=\"field readers\">\n <legend>{{ 'nh-assistant.admin.server-editor.reader.title' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.server-editor.reader.hint' | translate }}</p>\n @if (serverInvalid('readers')) {\n <p class=\"field-error\" [id]=\"errorId('readers')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('readers') | nhAssistantTranslate }}</p>\n }\n\n @for (reader of readers(); track reader.key; let index = $index) {\n <fieldset class=\"subsection reader\" [attr.data-reader]=\"index\">\n <legend class=\"reader-title\">{{ 'nh-assistant.admin.server-editor.reader.item' | translate: { number: index + 1 } }}</legend>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-reader-tool-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.tool' | translate }}</label>\n <select\n [id]=\"id + '-reader-tool-' + reader.key\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-tool-hint-' + reader.key, readerField(index, 'toolName'))\"\n [attr.aria-invalid]=\"(submitted() && (readerProblems()[index].tool || readerProblems()[index].duplicate)) || serverInvalid(readerField(index, 'toolName')) ? true : null\"\n (change)=\"updateReader(index, 'toolName', value($event))\">\n <option value=\"\" [selected]=\"reader.toolName === ''\">{{ 'nh-assistant.admin.server-editor.reader.tool-choose' | translate }}</option>\n @for (name of readerToolNames(); track name) {\n <option [value]=\"name\" [selected]=\"reader.toolName === name\">{{ name }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-reader-tool-hint-' + reader.key\">\n @if (submitted() && readerProblems()[index].tool) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n } @else if (submitted() && readerProblems()[index].duplicate) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.reader.tool-duplicate' | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.server-editor.reader.tool-hint' | translate }}\n }\n </p>\n @if (serverInvalid(readerField(index, 'toolName'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'toolName'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'toolName')) | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-reader-classification-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.max-classification' | translate }}</label>\n <select\n [id]=\"id + '-reader-classification-' + reader.key\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-classification-hint-' + reader.key, readerField(index, 'maxClassification'))\"\n [attr.aria-invalid]=\"(submitted() && readerProblems()[index].classification) || serverInvalid(readerField(index, 'maxClassification')) ? true : null\"\n (change)=\"updateReader(index, 'maxClassification', value($event))\">\n <option value=\"\" [selected]=\"reader.maxClassification === ''\">{{ 'nh-assistant.admin.server-editor.reader.max-classification-choose' | translate }}</option>\n @for (classification of classifications; track classification) {\n <option [value]=\"classification\" [selected]=\"reader.maxClassification === classification\">\n {{ 'nh-assistant.admin.run-config.skills.classification.' + classification | translate }}\n </option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-reader-classification-hint-' + reader.key\">\n @if (submitted() && readerProblems()[index].classification) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.server-editor.reader.max-classification-hint' | translate }}\n }\n </p>\n @if (serverInvalid(readerField(index, 'maxClassification'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'maxClassification'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'maxClassification')) | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-reader-types-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.media-types' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-reader-types-' + reader.key\"\n [value]=\"reader.mediaTypes\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-types-hint-' + reader.key, readerField(index, 'mediaTypes'))\"\n [attr.aria-invalid]=\"(submitted() && readerProblems()[index].types) || serverInvalid(readerField(index, 'mediaTypes')) ? true : null\"\n (input)=\"updateReader(index, 'mediaTypes', value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reader-types-hint-' + reader.key\">\n <span [class.error-text]=\"submitted() && readerProblems()[index].types\">\n {{ (submitted() && readerProblems()[index].types ? 'nh-assistant.admin.server-editor.reader.media-types-invalid' : 'nh-assistant.admin.server-editor.reader.media-types-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid(readerField(index, 'mediaTypes'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'mediaTypes'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'mediaTypes')) | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-reader-priority-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.priority' | translate }}</label>\n <input\n type=\"number\"\n inputmode=\"numeric\"\n step=\"1\"\n [min]=\"readerPriority.min\"\n [max]=\"readerPriority.max\"\n [id]=\"id + '-reader-priority-' + reader.key\"\n [value]=\"reader.priority\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-priority-hint-' + reader.key, readerField(index, 'priority'))\"\n [attr.aria-invalid]=\"(submitted() && readerProblems()[index].priority) || serverInvalid(readerField(index, 'priority')) ? true : null\"\n (input)=\"updateReader(index, 'priority', value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reader-priority-hint-' + reader.key\">\n <span [class.error-text]=\"submitted() && readerProblems()[index].priority\">\n {{ (submitted() && readerProblems()[index].priority ? 'nh-assistant.admin.server-editor.reader.priority-invalid' : 'nh-assistant.admin.server-editor.reader.priority-hint') | translate: readerPriority }}\n </span>\n </p>\n @if (serverInvalid(readerField(index, 'priority'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'priority'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'priority')) | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"inline\">\n <button\n type=\"button\"\n class=\"secondary\"\n [attr.aria-label]=\"'nh-assistant.admin.server-editor.reader.remove-label' | translate: { number: index + 1 }\"\n (click)=\"removeReader(index)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.server-editor.reader.remove' | translate }}\n </button>\n </div>\n </fieldset>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.server-editor.reader.empty' | translate }}</p>\n }\n\n <div class=\"inline\">\n <button\n type=\"button\"\n class=\"secondary\"\n [id]=\"id + '-reader-add'\"\n [disabled]=\"readers().length >= maxReaders || readerToolNames().length === 0\"\n [attr.aria-describedby]=\"id + '-reader-add-hint'\"\n (click)=\"addReader()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.server-editor.reader.add' | translate }}\n </button>\n </div>\n <p class=\"hint\" [id]=\"id + '-reader-add-hint'\">{{ readerAddHint() | translate: { max: maxReaders } }}</p>\n @if (readers().length > 0) {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.reader.leaves-application' | translate }}</p>\n }\n </fieldset>\n }\n\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"isEnabled()\" (change)=\"isEnabled.set(checked($event))\" />\n <span>{{ 'nh-assistant.admin.server-editor.enabled' | translate }}</span>\n </label>\n\n @if (error(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-server-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <span>{{ errorKeys() | nhAssistantTranslate: failure.code }}</span>\n @if (otherServerErrors().length > 0) {\n <ul>\n @for (other of otherServerErrors(); track other.field) {\n <li><code class=\"mono\">{{ other.field }}</code>: {{ other.keys | nhAssistantTranslate }}</li>\n }\n </ul>\n }\n </div>\n </div>\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()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\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: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: _NhAssistantTranslatePipe, name: "nhAssistantTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4448
4837
  }
4449
4838
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: NhAssistantAdminMcpServerEditorComponent, decorators: [{
4450
4839
  type: Component,
4451
- args: [{ selector: 'nh-assistant-admin-mcp-server-editor', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" autocomplete=\"off\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (server(); as current) {\n {{ 'nh-assistant.admin.server-editor.edit-title' | translate: { name: current.displayName } }}\n } @else {\n {{ 'nh-assistant.admin.server-editor.new-title' | translate }}\n }\n </h3>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.server-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-id'\"\n [maxLength]=\"limits.id\"\n [value]=\"serverId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id')\"\n [attr.aria-invalid]=\"(submitted() && idInvalid()) || serverInvalid('id') ? true : null\"\n (input)=\"serverId.set(value($event)); touch('id')\" />\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.server-editor.id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('id')) {\n <p class=\"field-error\" [id]=\"errorId('id')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('id') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.server-editor.display-name' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [maxLength]=\"limits.displayName\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"(submitted() && nameMissing()) || serverInvalid('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-name-hint', 'displayName')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\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 @if (serverInvalid('displayName')) {\n <p class=\"field-error\" [id]=\"errorId('displayName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('displayName') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-url'\">{{ 'nh-assistant.admin.server-editor.url' | translate }}</label>\n <input\n type=\"url\"\n class=\"mono\"\n inputmode=\"url\"\n [id]=\"id + '-url'\"\n [maxLength]=\"limits.url\"\n [value]=\"url()\"\n [attr.aria-describedby]=\"describedBy(id + '-url-hint', 'url')\"\n [attr.aria-invalid]=\"(submitted() && urlInvalid()) || serverInvalid('url') ? true : null\"\n (input)=\"onUrlInput($event); touch('url')\" />\n <p class=\"hint\" [id]=\"id + '-url-hint'\">\n <span [class.error-text]=\"submitted() && urlInvalid()\">\n {{ (submitted() && urlInvalid() ? 'nh-assistant.admin.server-editor.url-invalid' : 'nh-assistant.admin.server-editor.url-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('url')) {\n <p class=\"field-error\" [id]=\"errorId('url')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('url') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-auth'\">{{ 'nh-assistant.admin.server-editor.auth-mode' | translate }}</label>\n <select\n [id]=\"id + '-auth'\"\n [attr.aria-describedby]=\"describedBy(null, 'authMode')\"\n [attr.aria-invalid]=\"serverInvalid('authMode') ? true : null\"\n (change)=\"authMode.set($any(value($event))); touch('authMode')\">\n @for (mode of authModes(); track mode) {\n <option [value]=\"mode\" [selected]=\"authMode() === mode\">{{ ['nh-assistant.admin.mcp.auth.' + mode] | nhAssistantTranslate: mode }}</option>\n }\n </select>\n @if (customOwnership(); as ownership) {\n <p class=\"hint\" data-custom-auth-mode>{{ 'nh-assistant.admin.server-editor.custom-auth.' + ownership | translate }}</p>\n }\n @if (serverInvalid('authMode')) {\n <p class=\"field-error\" [id]=\"errorId('authMode')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('authMode') | nhAssistantTranslate }}</p>\n }\n </div>\n\n @if (authMode() === 'api-key') {\n <div class=\"field\">\n <label [for]=\"id + '-header'\">{{ 'nh-assistant.admin.server-editor.header-name' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n placeholder=\"X-Api-Key\"\n [id]=\"id + '-header'\"\n [maxLength]=\"limits.headerName\"\n [value]=\"headerName()\"\n [attr.aria-describedby]=\"describedBy(id + '-header-hint', 'headerName')\"\n [attr.aria-invalid]=\"(submitted() && headerNameInvalid()) || serverInvalid('headerName') ? true : null\"\n (input)=\"headerName.set(value($event)); touch('headerName')\" />\n <p class=\"hint\" [id]=\"id + '-header-hint'\">\n <span [class.error-text]=\"submitted() && headerNameInvalid()\">\n {{ (submitted() && headerNameInvalid() ? 'nh-assistant.admin.server-editor.header-name-invalid' : 'nh-assistant.admin.server-editor.header-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('headerName')) {\n <p class=\"field-error\" [id]=\"errorId('headerName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headerName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n\n @if (authMode() === 'basic') {\n <div class=\"field\">\n <label [for]=\"id + '-user'\">{{ 'nh-assistant.admin.server-editor.user-name' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [id]=\"id + '-user'\"\n [maxLength]=\"limits.userName\"\n [value]=\"userName()\"\n [attr.aria-describedby]=\"describedBy(id + '-user-hint', 'userName')\"\n [attr.aria-invalid]=\"(submitted() && userNameInvalid()) || serverInvalid('userName') ? true : null\"\n (input)=\"userName.set(value($event)); touch('userName')\" />\n <p class=\"hint\" [id]=\"id + '-user-hint'\">\n <span [class.error-text]=\"submitted() && userNameInvalid()\">\n {{ (submitted() && userNameInvalid() ? 'nh-assistant.admin.server-editor.user-name-invalid' : 'nh-assistant.admin.server-editor.user-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('userName')) {\n <p class=\"field-error\" [id]=\"errorId('userName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('userName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n </div>\n\n @if (authMode() === 'forward-user-token') {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.forward-warning' | translate }}</p>\n }\n\n @if (isOAuth()) {\n <fieldset class=\"field\">\n <legend>OAuth</legend>\n\n @if (authMode() === 'oauth') {\n <div\n class=\"inline\"\n role=\"radiogroup\"\n [attr.aria-label]=\"'nh-assistant.admin.server-editor.connection-scope' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-scope-hint', 'connectionScope')\">\n @for (scope of connectionScopes; track scope) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-connection-scope'\"\n [value]=\"scope\"\n [checked]=\"connectionScope() === scope\"\n [attr.aria-invalid]=\"serverInvalid('connectionScope') ? true : null\"\n (change)=\"connectionScope.set(scope); touch('connectionScope')\" />\n <span>{{ 'nh-assistant.admin.mcp.connection-scope.' + scope | translate }}</span>\n </label>\n }\n </div>\n <p class=\"hint\" [id]=\"id + '-scope-hint'\">{{ 'nh-assistant.admin.server-editor.connection-scope-hint' | translate }}</p>\n @if (serverInvalid('connectionScope')) {\n <p class=\"field-error\" [id]=\"errorId('connectionScope')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('connectionScope') | nhAssistantTranslate }}</p>\n }\n }\n\n @if (isOrganizationOAuth()) {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.oauth-warning' | translate }}</p>\n <label [for]=\"id + '-account-label'\">{{ 'nh-assistant.admin.server-editor.organization-account-label' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-account-label'\"\n [maxLength]=\"limits.organizationAccountLabel\"\n [value]=\"organizationAccountLabel()\"\n [attr.aria-describedby]=\"describedBy(id + '-account-label-hint', 'oauth.organizationAccountLabel')\"\n [attr.aria-invalid]=\"(submitted() && labelMissing()) || serverInvalid('oauth.organizationAccountLabel') ? true : null\"\n (input)=\"organizationAccountLabel.set(value($event)); touch('oauth.organizationAccountLabel')\" />\n <p class=\"hint\" [id]=\"id + '-account-label-hint'\">\n <span [class.error-text]=\"submitted() && labelMissing()\">\n {{ (submitted() && labelMissing() ? 'nh-assistant.admin.server-editor.organization-account-label-required' : 'nh-assistant.admin.server-editor.organization-account-label-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.organizationAccountLabel')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.organizationAccountLabel')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.organizationAccountLabel') | nhAssistantTranslate }}</p>\n }\n }\n\n <div class=\"meta\">\n @if (server()?.authorization; as confirmed) {\n @if (!needsConfirmation()) {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.confirmed-authorization' | translate: { issuer: confirmed.issuer } }}</span>\n }\n }\n <button class=\"secondary\" type=\"button\" [disabled]=\"discovering() || urlInvalid()\" (click)=\"discover()\">\n <nh-assistant-icon name=\"link\" />{{ (discovering() ? 'nh-assistant.admin.server-editor.discovering' : 'nh-assistant.admin.server-editor.discover') | translate }}\n </button>\n </div>\n @if (discoveryError(); as failure) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ discoveryErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n @if (discovery(); as found) {\n <div class=\"discovery\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.discovery-title' | translate\">\n <dl>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-issuer' | translate }}</dt>\n <dd class=\"mono\">{{ found.issuer }}</dd>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-resource' | translate }}</dt>\n <dd class=\"mono\">{{ found.resource }}</dd>\n @if (found.scopesSupported.length > 0) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-scopes' | translate }}</dt>\n <dd class=\"mono\">{{ found.scopesSupported.join(' ') }}</dd>\n }\n @if (authMode() === 'oauth' && registration(); as kind) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-registration' | translate }}</dt>\n <dd>{{ 'nh-assistant.admin.server-editor.registration-' + kind | translate }}</dd>\n }\n </dl>\n @if (pkceMissing()) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.pkce-missing' | translate }}</p>\n } @else {\n <label class=\"check\">\n <input\n type=\"checkbox\"\n [checked]=\"confirmAuthorization()\"\n [attr.aria-describedby]=\"describedBy(id + '-confirm-hint', 'oauth.confirmAuthorization')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.confirmAuthorization') ? true : null\"\n (change)=\"confirmAuthorization.set(checked($event)); touch('oauth.confirmAuthorization')\" />\n <span>{{ 'nh-assistant.admin.server-editor.confirm-authorization' | translate }}</span>\n </label>\n <p class=\"hint\" [id]=\"id + '-confirm-hint'\">{{ 'nh-assistant.admin.server-editor.confirm-authorization-hint' | translate }}</p>\n }\n </div>\n }\n @if (submitted() && confirmMissing()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</span></p>\n } @else if (serverInvalid('oauth.confirmAuthorization')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.confirmAuthorization')\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</p>\n }\n\n <label [for]=\"id + '-scopes'\">{{ 'nh-assistant.admin.server-editor.scopes' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-scopes'\"\n [maxLength]=\"limits.scopes\"\n [value]=\"oauthScopes()\"\n [attr.aria-describedby]=\"describedBy(id + '-scopes-hint', 'oauth.scopes')\"\n [attr.aria-invalid]=\"(submitted() && scopesInvalid()) || serverInvalid('oauth.scopes') ? true : null\"\n (input)=\"oauthScopes.set(value($event)); touch('oauth.scopes')\" />\n <p class=\"hint\" [id]=\"id + '-scopes-hint'\">\n <span [class.error-text]=\"submitted() && scopesInvalid()\">\n {{ (submitted() && scopesInvalid() ? 'nh-assistant.admin.server-editor.scopes-invalid' : 'nh-assistant.admin.server-editor.scopes-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.scopes')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.scopes')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.scopes') | nhAssistantTranslate }}</p>\n }\n\n <label [for]=\"id + '-client-id'\">{{ 'nh-assistant.admin.server-editor.client-id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-client-id'\"\n [maxLength]=\"limits.clientId\"\n [value]=\"oauthClientId()\"\n [attr.aria-describedby]=\"describedBy(id + '-client-id-hint', 'oauth.clientId')\"\n [attr.aria-invalid]=\"(submitted() && clientIdMissing()) || serverInvalid('oauth.clientId') ? true : null\"\n (input)=\"oauthClientId.set(value($event)); touch('oauth.clientId')\" />\n <p class=\"hint\" [id]=\"id + '-client-id-hint'\">\n <span [class.error-text]=\"submitted() && clientIdMissing()\">\n {{ (submitted() && clientIdMissing() ? 'nh-assistant.admin.server-editor.client-id-required' : 'nh-assistant.admin.server-editor.client-id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.clientId')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientId')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientId') | nhAssistantTranslate }}</p>\n }\n\n @if (oauthClientId().trim().length > 0) {\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.client-secret' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-oauth-secret-source'\"\n [value]=\"source\"\n [checked]=\"oauthSecretSource() === source\"\n (change)=\"setOAuthSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesOAuthReference()) {\n <label [for]=\"id + '-oauth-reference'\">{{ 'nh-assistant.admin.server-editor.client-secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-client-secret\"\n [id]=\"id + '-oauth-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"oauthSecretReference()\"\n [attr.aria-describedby]=\"describedBy(null, 'oauth.clientSecretReference')\"\n [attr.aria-invalid]=\"(submitted() && oauthReferenceInvalid()) || serverInvalid('oauth.clientSecretReference') ? true : null\"\n (input)=\"oauthSecretReference.set(value($event)); touch('oauth.clientSecretReference')\" />\n @if (submitted() && oauthReferenceInvalid()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.secret-reference-invalid' | translate }}</span></p>\n }\n @if (serverInvalid('oauth.clientSecretReference')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecretReference') | nhAssistantTranslate }}</p>\n }\n } @else {\n @if (hasOAuthSecret() && oauthSecretAction() === 'keep') {\n <div class=\"meta secret-state\">\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"oauthSecretAction.set('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n </div>\n }\n @if (showOAuthSecretInput()) {\n <label [for]=\"id + '-oauth-secret'\">{{ 'nh-assistant.admin.server-editor.client-secret' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-oauth-secret'\"\n [maxLength]=\"limits.clientSecret\"\n [attr.aria-describedby]=\"describedBy(id + '-oauth-secret-hint', 'oauth.clientSecret')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.clientSecret') ? true : null\"\n [value]=\"oauthSecret()\"\n (input)=\"onOAuthSecretInput($event); touch('oauth.clientSecret')\" />\n }\n <p class=\"hint\" [id]=\"id + '-oauth-secret-hint'\">{{ 'nh-assistant.admin.server-editor.client-secret-hint' | translate }}</p>\n }\n }\n @if (serverInvalid('oauth.clientSecret')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n @if (usesSecret()) {\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.server-editor.secret' | translate }}</legend>\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.secret-source' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-secret-source'\"\n [value]=\"source\"\n [checked]=\"secretSource() === source\"\n (change)=\"setSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesReference()) {\n <label [for]=\"id + '-secret-reference'\">{{ 'nh-assistant.admin.server-editor.secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-token\"\n [id]=\"id + '-secret-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"secretReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-reference-hint', 'secretReference')\"\n [attr.aria-invalid]=\"(submitted() && secretReferenceInvalid()) || serverInvalid('secretReference') ? true : null\"\n (input)=\"secretReference.set(value($event)); touch('secretReference')\" />\n <p class=\"hint\" [id]=\"id + '-secret-reference-hint'\">\n <span [class.error-text]=\"submitted() && secretReferenceInvalid()\">\n {{ (submitted() && secretReferenceInvalid() ? 'nh-assistant.admin.server-editor.secret-reference-invalid' : 'nh-assistant.admin.server-editor.secret-reference-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('secretReference')) {\n <p class=\"field-error\" [id]=\"errorId('secretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secretReference') | nhAssistantTranslate }}</p>\n }\n } @else if (hasSecret()) {\n <div class=\"meta secret-state\">\n @switch (secretAction()) {\n @case ('clear') {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.server-editor.secret-will-clear' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @case ('replace') {\n <span class=\"badge\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @default {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <!-- A mode with a secret always needs one: it is replaced, or removed by choosing a reference or another mode. -->\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n }\n }\n </div>\n } @else {\n <p class=\"muted\">{{ 'nh-assistant.admin.server-editor.secret-none' | translate }}</p>\n }\n @if (showSecretInput()) {\n <label class=\"visually-hidden\" [for]=\"id + '-secret'\">{{ 'nh-assistant.admin.server-editor.secret-new' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-secret'\"\n [maxLength]=\"limits.secret\"\n [attr.placeholder]=\"'nh-assistant.admin.server-editor.secret-new' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-hint', 'secret')\"\n [attr.aria-invalid]=\"serverInvalid('secret') ? true : null\"\n [value]=\"secret()\"\n (input)=\"onSecretInput($event); touch('secret')\" />\n }\n @if (!usesReference()) {\n <p class=\"hint\" [id]=\"id + '-secret-hint'\">{{ 'nh-assistant.admin.server-editor.secret-hint' | translate }}</p>\n }\n @if (serverInvalid('secret')) {\n <p class=\"field-error\" [id]=\"errorId('secret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-certificate'\">{{ 'nh-assistant.admin.server-editor.client-certificate' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-certificate'\"\n [maxLength]=\"limits.clientCertificateReference\"\n [value]=\"clientCertificateReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-certificate-hint', 'clientCertificateReference')\"\n [attr.aria-invalid]=\"(submitted() && certificateInvalid()) || serverInvalid('clientCertificateReference') ? true : null\"\n (input)=\"clientCertificateReference.set(value($event)); touch('clientCertificateReference')\" />\n <p class=\"hint\" [id]=\"id + '-certificate-hint'\">\n <span [class.error-text]=\"submitted() && certificateInvalid()\">\n {{ (submitted() && certificateInvalid() ? 'nh-assistant.admin.server-editor.client-certificate-invalid' : 'nh-assistant.admin.server-editor.client-certificate-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('clientCertificateReference')) {\n <p class=\"field-error\" [id]=\"errorId('clientCertificateReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('clientCertificateReference') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-transport'\">{{ 'nh-assistant.admin.server-editor.transport' | translate }}</label>\n <select\n [id]=\"id + '-transport'\"\n [attr.aria-describedby]=\"describedBy(id + '-transport-hint', 'transport')\"\n [attr.aria-invalid]=\"serverInvalid('transport') ? true : null\"\n (change)=\"transport.set($any(value($event))); touch('transport')\">\n @for (option of transports; track option) {\n <option [value]=\"option\" [selected]=\"transport() === option\">{{ 'nh-assistant.admin.mcp.transport.' + option | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-transport-hint'\">{{ 'nh-assistant.admin.server-editor.transport-hint' | translate }}</p>\n @if (serverInvalid('transport')) {\n <p class=\"field-error\" [id]=\"errorId('transport')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('transport') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.server-editor.required-policy' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-policy'\"\n [maxLength]=\"limits.requiredPolicy\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"describedBy(id + '-policy-hint', 'requiredPolicy')\"\n [attr.aria-invalid]=\"serverInvalid('requiredPolicy') ? true : null\"\n (input)=\"requiredPolicy.set(value($event)); touch('requiredPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.server-editor.required-policy-hint' | translate }}</p>\n @if (serverInvalid('requiredPolicy')) {\n <p class=\"field-error\" [id]=\"errorId('requiredPolicy')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('requiredPolicy') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-headless'\">{{ 'nh-assistant.admin.server-editor.headless-use' | translate }}</label>\n <select\n [id]=\"id + '-headless'\"\n [attr.aria-describedby]=\"describedBy(id + '-headless-hint', 'headlessUse')\"\n [attr.aria-invalid]=\"serverInvalid('headlessUse') ? true : null\"\n (change)=\"headlessUse.set($any(value($event))); touch('headlessUse')\">\n @for (use of headlessUses(); track use) {\n <option [value]=\"use\" [selected]=\"effectiveHeadlessUse() === use\">{{ 'nh-assistant.admin.mcp.headless.' + use | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-headless-hint'\">\n {{ (personalCredential() ? 'nh-assistant.admin.server-editor.headless-use-personal' : 'nh-assistant.admin.server-editor.headless-use-hint') | translate }}\n </p>\n @if (serverInvalid('headlessUse')) {\n <p class=\"field-error\" [id]=\"errorId('headlessUse')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headlessUse') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"isEnabled()\" (change)=\"isEnabled.set(checked($event))\" />\n <span>{{ 'nh-assistant.admin.server-editor.enabled' | translate }}</span>\n </label>\n\n @if (error(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-server-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <span>{{ errorKeys() | nhAssistantTranslate: failure.code }}</span>\n @if (otherServerErrors().length > 0) {\n <ul>\n @for (other of otherServerErrors(); track other.field) {\n <li><code class=\"mono\">{{ other.field }}</code>: {{ other.keys | nhAssistantTranslate }}</li>\n }\n </ul>\n }\n </div>\n </div>\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()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\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"] }]
4840
+ args: [{ selector: 'nh-assistant-admin-mcp-server-editor', standalone: true, imports: [TranslatePipe, _NhAssistantTranslatePipe, _NhAssistantIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"section card\" [attr.aria-labelledby]=\"id + '-title'\" [attr.aria-busy]=\"saving()\" autocomplete=\"off\" (submit)=\"$event.preventDefault(); save()\">\n <h3 [id]=\"id + '-title'\">\n @if (server(); as current) {\n {{ 'nh-assistant.admin.server-editor.edit-title' | translate: { name: current.displayName } }}\n } @else {\n {{ 'nh-assistant.admin.server-editor.new-title' | translate }}\n }\n </h3>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-id'\">{{ 'nh-assistant.admin.server-editor.id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-id'\"\n [maxLength]=\"limits.id\"\n [value]=\"serverId()\"\n [disabled]=\"!isNew()\"\n [attr.aria-describedby]=\"describedBy(id + '-id-hint', 'id')\"\n [attr.aria-invalid]=\"(submitted() && idInvalid()) || serverInvalid('id') ? true : null\"\n (input)=\"serverId.set(value($event)); touch('id')\" />\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.server-editor.id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('id')) {\n <p class=\"field-error\" [id]=\"errorId('id')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('id') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-name'\">{{ 'nh-assistant.admin.server-editor.display-name' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-name'\"\n [maxLength]=\"limits.displayName\"\n [value]=\"displayName()\"\n [attr.aria-invalid]=\"(submitted() && nameMissing()) || serverInvalid('displayName') ? true : null\"\n [attr.aria-describedby]=\"describedBy(id + '-name-hint', 'displayName')\"\n (input)=\"displayName.set(value($event)); touch('displayName')\" />\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 @if (serverInvalid('displayName')) {\n <p class=\"field-error\" [id]=\"errorId('displayName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('displayName') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-url'\">{{ 'nh-assistant.admin.server-editor.url' | translate }}</label>\n <input\n type=\"url\"\n class=\"mono\"\n inputmode=\"url\"\n [id]=\"id + '-url'\"\n [maxLength]=\"limits.url\"\n [value]=\"url()\"\n [attr.aria-describedby]=\"describedBy(id + '-url-hint', 'url')\"\n [attr.aria-invalid]=\"(submitted() && urlInvalid()) || serverInvalid('url') ? true : null\"\n (input)=\"onUrlInput($event); touch('url')\" />\n <p class=\"hint\" [id]=\"id + '-url-hint'\">\n <span [class.error-text]=\"submitted() && urlInvalid()\">\n {{ (submitted() && urlInvalid() ? 'nh-assistant.admin.server-editor.url-invalid' : 'nh-assistant.admin.server-editor.url-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('url')) {\n <p class=\"field-error\" [id]=\"errorId('url')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('url') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-auth'\">{{ 'nh-assistant.admin.server-editor.auth-mode' | translate }}</label>\n <select\n [id]=\"id + '-auth'\"\n [attr.aria-describedby]=\"describedBy(null, 'authMode')\"\n [attr.aria-invalid]=\"serverInvalid('authMode') ? true : null\"\n (change)=\"authMode.set($any(value($event))); touch('authMode')\">\n @for (mode of authModes(); track mode) {\n <option [value]=\"mode\" [selected]=\"authMode() === mode\">{{ ['nh-assistant.admin.mcp.auth.' + mode] | nhAssistantTranslate: mode }}</option>\n }\n </select>\n @if (customOwnership(); as ownership) {\n <p class=\"hint\" data-custom-auth-mode>{{ 'nh-assistant.admin.server-editor.custom-auth.' + ownership | translate }}</p>\n }\n @if (serverInvalid('authMode')) {\n <p class=\"field-error\" [id]=\"errorId('authMode')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('authMode') | nhAssistantTranslate }}</p>\n }\n </div>\n\n @if (authMode() === 'api-key') {\n <div class=\"field\">\n <label [for]=\"id + '-header'\">{{ 'nh-assistant.admin.server-editor.header-name' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n placeholder=\"X-Api-Key\"\n [id]=\"id + '-header'\"\n [maxLength]=\"limits.headerName\"\n [value]=\"headerName()\"\n [attr.aria-describedby]=\"describedBy(id + '-header-hint', 'headerName')\"\n [attr.aria-invalid]=\"(submitted() && headerNameInvalid()) || serverInvalid('headerName') ? true : null\"\n (input)=\"headerName.set(value($event)); touch('headerName')\" />\n <p class=\"hint\" [id]=\"id + '-header-hint'\">\n <span [class.error-text]=\"submitted() && headerNameInvalid()\">\n {{ (submitted() && headerNameInvalid() ? 'nh-assistant.admin.server-editor.header-name-invalid' : 'nh-assistant.admin.server-editor.header-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('headerName')) {\n <p class=\"field-error\" [id]=\"errorId('headerName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headerName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n\n @if (authMode() === 'basic') {\n <div class=\"field\">\n <label [for]=\"id + '-user'\">{{ 'nh-assistant.admin.server-editor.user-name' | translate }}</label>\n <input\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [id]=\"id + '-user'\"\n [maxLength]=\"limits.userName\"\n [value]=\"userName()\"\n [attr.aria-describedby]=\"describedBy(id + '-user-hint', 'userName')\"\n [attr.aria-invalid]=\"(submitted() && userNameInvalid()) || serverInvalid('userName') ? true : null\"\n (input)=\"userName.set(value($event)); touch('userName')\" />\n <p class=\"hint\" [id]=\"id + '-user-hint'\">\n <span [class.error-text]=\"submitted() && userNameInvalid()\">\n {{ (submitted() && userNameInvalid() ? 'nh-assistant.admin.server-editor.user-name-invalid' : 'nh-assistant.admin.server-editor.user-name-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('userName')) {\n <p class=\"field-error\" [id]=\"errorId('userName')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('userName') | nhAssistantTranslate }}</p>\n }\n </div>\n }\n </div>\n\n @if (authMode() === 'forward-user-token') {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.forward-warning' | translate }}</p>\n }\n\n @if (isOAuth()) {\n <fieldset class=\"field\">\n <legend>OAuth</legend>\n\n @if (authMode() === 'oauth') {\n <div\n class=\"inline\"\n role=\"radiogroup\"\n [attr.aria-label]=\"'nh-assistant.admin.server-editor.connection-scope' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-scope-hint', 'connectionScope')\">\n @for (scope of connectionScopes; track scope) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-connection-scope'\"\n [value]=\"scope\"\n [checked]=\"connectionScope() === scope\"\n [attr.aria-invalid]=\"serverInvalid('connectionScope') ? true : null\"\n (change)=\"connectionScope.set(scope); touch('connectionScope')\" />\n <span>{{ 'nh-assistant.admin.mcp.connection-scope.' + scope | translate }}</span>\n </label>\n }\n </div>\n <p class=\"hint\" [id]=\"id + '-scope-hint'\">{{ 'nh-assistant.admin.server-editor.connection-scope-hint' | translate }}</p>\n @if (serverInvalid('connectionScope')) {\n <p class=\"field-error\" [id]=\"errorId('connectionScope')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('connectionScope') | nhAssistantTranslate }}</p>\n }\n }\n\n @if (isOrganizationOAuth()) {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.oauth-warning' | translate }}</p>\n <label [for]=\"id + '-account-label'\">{{ 'nh-assistant.admin.server-editor.organization-account-label' | translate }}</label>\n <input\n type=\"text\"\n [id]=\"id + '-account-label'\"\n [maxLength]=\"limits.organizationAccountLabel\"\n [value]=\"organizationAccountLabel()\"\n [attr.aria-describedby]=\"describedBy(id + '-account-label-hint', 'oauth.organizationAccountLabel')\"\n [attr.aria-invalid]=\"(submitted() && labelMissing()) || serverInvalid('oauth.organizationAccountLabel') ? true : null\"\n (input)=\"organizationAccountLabel.set(value($event)); touch('oauth.organizationAccountLabel')\" />\n <p class=\"hint\" [id]=\"id + '-account-label-hint'\">\n <span [class.error-text]=\"submitted() && labelMissing()\">\n {{ (submitted() && labelMissing() ? 'nh-assistant.admin.server-editor.organization-account-label-required' : 'nh-assistant.admin.server-editor.organization-account-label-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.organizationAccountLabel')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.organizationAccountLabel')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.organizationAccountLabel') | nhAssistantTranslate }}</p>\n }\n }\n\n <div class=\"meta\">\n @if (server()?.authorization; as confirmed) {\n @if (!needsConfirmation()) {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.confirmed-authorization' | translate: { issuer: confirmed.issuer } }}</span>\n }\n }\n <button class=\"secondary\" type=\"button\" [disabled]=\"discovering() || urlInvalid()\" (click)=\"discover()\">\n <nh-assistant-icon name=\"link\" />{{ (discovering() ? 'nh-assistant.admin.server-editor.discovering' : 'nh-assistant.admin.server-editor.discover') | translate }}\n </button>\n </div>\n @if (discoveryError(); as failure) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ discoveryErrorKeys() | nhAssistantTranslate: failure.code }}</p>\n }\n @if (discovery(); as found) {\n <div class=\"discovery\" role=\"group\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.discovery-title' | translate\">\n <dl>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-issuer' | translate }}</dt>\n <dd class=\"mono\">{{ found.issuer }}</dd>\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-resource' | translate }}</dt>\n <dd class=\"mono\">{{ found.resource }}</dd>\n @if (found.scopesSupported.length > 0) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-scopes' | translate }}</dt>\n <dd class=\"mono\">{{ found.scopesSupported.join(' ') }}</dd>\n }\n @if (authMode() === 'oauth' && registration(); as kind) {\n <dt>{{ 'nh-assistant.admin.server-editor.discovery-registration' | translate }}</dt>\n <dd>{{ 'nh-assistant.admin.server-editor.registration-' + kind | translate }}</dd>\n }\n </dl>\n @if (pkceMissing()) {\n <p class=\"message error\" role=\"alert\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.pkce-missing' | translate }}</p>\n } @else {\n <label class=\"check\">\n <input\n type=\"checkbox\"\n [checked]=\"confirmAuthorization()\"\n [attr.aria-describedby]=\"describedBy(id + '-confirm-hint', 'oauth.confirmAuthorization')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.confirmAuthorization') ? true : null\"\n (change)=\"confirmAuthorization.set(checked($event)); touch('oauth.confirmAuthorization')\" />\n <span>{{ 'nh-assistant.admin.server-editor.confirm-authorization' | translate }}</span>\n </label>\n <p class=\"hint\" [id]=\"id + '-confirm-hint'\">{{ 'nh-assistant.admin.server-editor.confirm-authorization-hint' | translate }}</p>\n }\n </div>\n }\n @if (submitted() && confirmMissing()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</span></p>\n } @else if (serverInvalid('oauth.confirmAuthorization')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.confirmAuthorization')\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.confirm-required' | translate }}</p>\n }\n\n <label [for]=\"id + '-scopes'\">{{ 'nh-assistant.admin.server-editor.scopes' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-scopes'\"\n [maxLength]=\"limits.scopes\"\n [value]=\"oauthScopes()\"\n [attr.aria-describedby]=\"describedBy(id + '-scopes-hint', 'oauth.scopes')\"\n [attr.aria-invalid]=\"(submitted() && scopesInvalid()) || serverInvalid('oauth.scopes') ? true : null\"\n (input)=\"oauthScopes.set(value($event)); touch('oauth.scopes')\" />\n <p class=\"hint\" [id]=\"id + '-scopes-hint'\">\n <span [class.error-text]=\"submitted() && scopesInvalid()\">\n {{ (submitted() && scopesInvalid() ? 'nh-assistant.admin.server-editor.scopes-invalid' : 'nh-assistant.admin.server-editor.scopes-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.scopes')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.scopes')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.scopes') | nhAssistantTranslate }}</p>\n }\n\n <label [for]=\"id + '-client-id'\">{{ 'nh-assistant.admin.server-editor.client-id' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-client-id'\"\n [maxLength]=\"limits.clientId\"\n [value]=\"oauthClientId()\"\n [attr.aria-describedby]=\"describedBy(id + '-client-id-hint', 'oauth.clientId')\"\n [attr.aria-invalid]=\"(submitted() && clientIdMissing()) || serverInvalid('oauth.clientId') ? true : null\"\n (input)=\"oauthClientId.set(value($event)); touch('oauth.clientId')\" />\n <p class=\"hint\" [id]=\"id + '-client-id-hint'\">\n <span [class.error-text]=\"submitted() && clientIdMissing()\">\n {{ (submitted() && clientIdMissing() ? 'nh-assistant.admin.server-editor.client-id-required' : 'nh-assistant.admin.server-editor.client-id-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('oauth.clientId')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientId')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientId') | nhAssistantTranslate }}</p>\n }\n\n @if (oauthClientId().trim().length > 0) {\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.client-secret' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-oauth-secret-source'\"\n [value]=\"source\"\n [checked]=\"oauthSecretSource() === source\"\n (change)=\"setOAuthSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesOAuthReference()) {\n <label [for]=\"id + '-oauth-reference'\">{{ 'nh-assistant.admin.server-editor.client-secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-client-secret\"\n [id]=\"id + '-oauth-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"oauthSecretReference()\"\n [attr.aria-describedby]=\"describedBy(null, 'oauth.clientSecretReference')\"\n [attr.aria-invalid]=\"(submitted() && oauthReferenceInvalid()) || serverInvalid('oauth.clientSecretReference') ? true : null\"\n (input)=\"oauthSecretReference.set(value($event)); touch('oauth.clientSecretReference')\" />\n @if (submitted() && oauthReferenceInvalid()) {\n <p class=\"hint\"><span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.secret-reference-invalid' | translate }}</span></p>\n }\n @if (serverInvalid('oauth.clientSecretReference')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecretReference') | nhAssistantTranslate }}</p>\n }\n } @else {\n @if (hasOAuthSecret() && oauthSecretAction() === 'keep') {\n <div class=\"meta secret-state\">\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"oauthSecretAction.set('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n </div>\n }\n @if (showOAuthSecretInput()) {\n <label [for]=\"id + '-oauth-secret'\">{{ 'nh-assistant.admin.server-editor.client-secret' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-oauth-secret'\"\n [maxLength]=\"limits.clientSecret\"\n [attr.aria-describedby]=\"describedBy(id + '-oauth-secret-hint', 'oauth.clientSecret')\"\n [attr.aria-invalid]=\"serverInvalid('oauth.clientSecret') ? true : null\"\n [value]=\"oauthSecret()\"\n (input)=\"onOAuthSecretInput($event); touch('oauth.clientSecret')\" />\n }\n <p class=\"hint\" [id]=\"id + '-oauth-secret-hint'\">{{ 'nh-assistant.admin.server-editor.client-secret-hint' | translate }}</p>\n }\n }\n @if (serverInvalid('oauth.clientSecret')) {\n <p class=\"field-error\" [id]=\"errorId('oauth.clientSecret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('oauth.clientSecret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n @if (usesSecret()) {\n <fieldset class=\"field\">\n <legend>{{ 'nh-assistant.admin.server-editor.secret' | translate }}</legend>\n <div class=\"inline\" role=\"radiogroup\" [attr.aria-label]=\"'nh-assistant.admin.server-editor.secret-source' | translate\">\n @for (source of secretSources; track source) {\n <label class=\"check\">\n <input\n type=\"radio\"\n [name]=\"id + '-secret-source'\"\n [value]=\"source\"\n [checked]=\"secretSource() === source\"\n (change)=\"setSecretSource(source)\" />\n <span>{{ 'nh-assistant.admin.server-editor.secret-source-' + source | translate }}</span>\n </label>\n }\n </div>\n @if (usesReference()) {\n <label [for]=\"id + '-secret-reference'\">{{ 'nh-assistant.admin.server-editor.secret-reference' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n placeholder=\"config:planning-token\"\n [id]=\"id + '-secret-reference'\"\n [maxLength]=\"limits.secretReference\"\n [value]=\"secretReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-reference-hint', 'secretReference')\"\n [attr.aria-invalid]=\"(submitted() && secretReferenceInvalid()) || serverInvalid('secretReference') ? true : null\"\n (input)=\"secretReference.set(value($event)); touch('secretReference')\" />\n <p class=\"hint\" [id]=\"id + '-secret-reference-hint'\">\n <span [class.error-text]=\"submitted() && secretReferenceInvalid()\">\n {{ (submitted() && secretReferenceInvalid() ? 'nh-assistant.admin.server-editor.secret-reference-invalid' : 'nh-assistant.admin.server-editor.secret-reference-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('secretReference')) {\n <p class=\"field-error\" [id]=\"errorId('secretReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secretReference') | nhAssistantTranslate }}</p>\n }\n } @else if (hasSecret()) {\n <div class=\"meta secret-state\">\n @switch (secretAction()) {\n @case ('clear') {\n <span class=\"badge warning\">{{ 'nh-assistant.admin.server-editor.secret-will-clear' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @case ('replace') {\n <span class=\"badge\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('keep')\">{{ 'nh-assistant.admin.server-editor.secret-undo' | translate }}</button>\n }\n @default {\n <span class=\"badge success\">{{ 'nh-assistant.admin.server-editor.secret-set' | translate }}</span>\n <!-- A mode with a secret always needs one: it is replaced, or removed by choosing a reference or another mode. -->\n <button class=\"secondary\" type=\"button\" (click)=\"setSecretAction('replace')\">{{ 'nh-assistant.admin.server-editor.secret-replace' | translate }}</button>\n }\n }\n </div>\n } @else {\n <p class=\"muted\">{{ 'nh-assistant.admin.server-editor.secret-none' | translate }}</p>\n }\n @if (showSecretInput()) {\n <label class=\"visually-hidden\" [for]=\"id + '-secret'\">{{ 'nh-assistant.admin.server-editor.secret-new' | translate }}</label>\n <input\n type=\"password\"\n class=\"mono\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [id]=\"id + '-secret'\"\n [maxLength]=\"limits.secret\"\n [attr.placeholder]=\"'nh-assistant.admin.server-editor.secret-new' | translate\"\n [attr.aria-describedby]=\"describedBy(id + '-secret-hint', 'secret')\"\n [attr.aria-invalid]=\"serverInvalid('secret') ? true : null\"\n [value]=\"secret()\"\n (input)=\"onSecretInput($event); touch('secret')\" />\n }\n @if (!usesReference()) {\n <p class=\"hint\" [id]=\"id + '-secret-hint'\">{{ 'nh-assistant.admin.server-editor.secret-hint' | translate }}</p>\n }\n @if (serverInvalid('secret')) {\n <p class=\"field-error\" [id]=\"errorId('secret')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('secret') | nhAssistantTranslate }}</p>\n }\n </fieldset>\n }\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-certificate'\">{{ 'nh-assistant.admin.server-editor.client-certificate' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-certificate'\"\n [maxLength]=\"limits.clientCertificateReference\"\n [value]=\"clientCertificateReference()\"\n [attr.aria-describedby]=\"describedBy(id + '-certificate-hint', 'clientCertificateReference')\"\n [attr.aria-invalid]=\"(submitted() && certificateInvalid()) || serverInvalid('clientCertificateReference') ? true : null\"\n (input)=\"clientCertificateReference.set(value($event)); touch('clientCertificateReference')\" />\n <p class=\"hint\" [id]=\"id + '-certificate-hint'\">\n <span [class.error-text]=\"submitted() && certificateInvalid()\">\n {{ (submitted() && certificateInvalid() ? 'nh-assistant.admin.server-editor.client-certificate-invalid' : 'nh-assistant.admin.server-editor.client-certificate-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid('clientCertificateReference')) {\n <p class=\"field-error\" [id]=\"errorId('clientCertificateReference')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('clientCertificateReference') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-transport'\">{{ 'nh-assistant.admin.server-editor.transport' | translate }}</label>\n <select\n [id]=\"id + '-transport'\"\n [attr.aria-describedby]=\"describedBy(id + '-transport-hint', 'transport')\"\n [attr.aria-invalid]=\"serverInvalid('transport') ? true : null\"\n (change)=\"transport.set($any(value($event))); touch('transport')\">\n @for (option of transports; track option) {\n <option [value]=\"option\" [selected]=\"transport() === option\">{{ 'nh-assistant.admin.mcp.transport.' + option | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-transport-hint'\">{{ 'nh-assistant.admin.server-editor.transport-hint' | translate }}</p>\n @if (serverInvalid('transport')) {\n <p class=\"field-error\" [id]=\"errorId('transport')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('transport') | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-policy'\">{{ 'nh-assistant.admin.server-editor.required-policy' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n [id]=\"id + '-policy'\"\n [maxLength]=\"limits.requiredPolicy\"\n [value]=\"requiredPolicy()\"\n [attr.aria-describedby]=\"describedBy(id + '-policy-hint', 'requiredPolicy')\"\n [attr.aria-invalid]=\"serverInvalid('requiredPolicy') ? true : null\"\n (input)=\"requiredPolicy.set(value($event)); touch('requiredPolicy')\" />\n <p class=\"hint\" [id]=\"id + '-policy-hint'\">{{ 'nh-assistant.admin.server-editor.required-policy-hint' | translate }}</p>\n @if (serverInvalid('requiredPolicy')) {\n <p class=\"field-error\" [id]=\"errorId('requiredPolicy')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('requiredPolicy') | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-headless'\">{{ 'nh-assistant.admin.server-editor.headless-use' | translate }}</label>\n <select\n [id]=\"id + '-headless'\"\n [attr.aria-describedby]=\"describedBy(id + '-headless-hint', 'headlessUse')\"\n [attr.aria-invalid]=\"serverInvalid('headlessUse') ? true : null\"\n (change)=\"headlessUse.set($any(value($event))); touch('headlessUse')\">\n @for (use of headlessUses(); track use) {\n <option [value]=\"use\" [selected]=\"effectiveHeadlessUse() === use\">{{ 'nh-assistant.admin.mcp.headless.' + use | translate }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-headless-hint'\">\n {{ (personalCredential() ? 'nh-assistant.admin.server-editor.headless-use-personal' : 'nh-assistant.admin.server-editor.headless-use-hint') | translate }}\n </p>\n @if (serverInvalid('headlessUse')) {\n <p class=\"field-error\" [id]=\"errorId('headlessUse')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('headlessUse') | nhAssistantTranslate }}</p>\n }\n </div>\n\n @if (!isNew()) {\n <fieldset class=\"field readers\">\n <legend>{{ 'nh-assistant.admin.server-editor.reader.title' | translate }}</legend>\n <p class=\"hint\">{{ 'nh-assistant.admin.server-editor.reader.hint' | translate }}</p>\n @if (serverInvalid('readers')) {\n <p class=\"field-error\" [id]=\"errorId('readers')\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys('readers') | nhAssistantTranslate }}</p>\n }\n\n @for (reader of readers(); track reader.key; let index = $index) {\n <fieldset class=\"subsection reader\" [attr.data-reader]=\"index\">\n <legend class=\"reader-title\">{{ 'nh-assistant.admin.server-editor.reader.item' | translate: { number: index + 1 } }}</legend>\n\n <div class=\"grid\">\n <div class=\"field\">\n <label [for]=\"id + '-reader-tool-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.tool' | translate }}</label>\n <select\n [id]=\"id + '-reader-tool-' + reader.key\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-tool-hint-' + reader.key, readerField(index, 'toolName'))\"\n [attr.aria-invalid]=\"(submitted() && (readerProblems()[index].tool || readerProblems()[index].duplicate)) || serverInvalid(readerField(index, 'toolName')) ? true : null\"\n (change)=\"updateReader(index, 'toolName', value($event))\">\n <option value=\"\" [selected]=\"reader.toolName === ''\">{{ 'nh-assistant.admin.server-editor.reader.tool-choose' | translate }}</option>\n @for (name of readerToolNames(); track name) {\n <option [value]=\"name\" [selected]=\"reader.toolName === name\">{{ name }}</option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-reader-tool-hint-' + reader.key\">\n @if (submitted() && readerProblems()[index].tool) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n } @else if (submitted() && readerProblems()[index].duplicate) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.server-editor.reader.tool-duplicate' | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.server-editor.reader.tool-hint' | translate }}\n }\n </p>\n @if (serverInvalid(readerField(index, 'toolName'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'toolName'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'toolName')) | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-reader-classification-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.max-classification' | translate }}</label>\n <select\n [id]=\"id + '-reader-classification-' + reader.key\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-classification-hint-' + reader.key, readerField(index, 'maxClassification'))\"\n [attr.aria-invalid]=\"(submitted() && readerProblems()[index].classification) || serverInvalid(readerField(index, 'maxClassification')) ? true : null\"\n (change)=\"updateReader(index, 'maxClassification', value($event))\">\n <option value=\"\" [selected]=\"reader.maxClassification === ''\">{{ 'nh-assistant.admin.server-editor.reader.max-classification-choose' | translate }}</option>\n @for (classification of classifications; track classification) {\n <option [value]=\"classification\" [selected]=\"reader.maxClassification === classification\">\n {{ 'nh-assistant.admin.run-config.skills.classification.' + classification | translate }}\n </option>\n }\n </select>\n <p class=\"hint\" [id]=\"id + '-reader-classification-hint-' + reader.key\">\n @if (submitted() && readerProblems()[index].classification) {\n <span class=\"error-text\">{{ 'nh-assistant.admin.required' | translate }}</span>\n } @else {\n {{ 'nh-assistant.admin.server-editor.reader.max-classification-hint' | translate }}\n }\n </p>\n @if (serverInvalid(readerField(index, 'maxClassification'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'maxClassification'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'maxClassification')) | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-reader-types-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.media-types' | translate }}</label>\n <input\n type=\"text\"\n class=\"mono\"\n spellcheck=\"false\"\n [id]=\"id + '-reader-types-' + reader.key\"\n [value]=\"reader.mediaTypes\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-types-hint-' + reader.key, readerField(index, 'mediaTypes'))\"\n [attr.aria-invalid]=\"(submitted() && readerProblems()[index].types) || serverInvalid(readerField(index, 'mediaTypes')) ? true : null\"\n (input)=\"updateReader(index, 'mediaTypes', value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reader-types-hint-' + reader.key\">\n <span [class.error-text]=\"submitted() && readerProblems()[index].types\">\n {{ (submitted() && readerProblems()[index].types ? 'nh-assistant.admin.server-editor.reader.media-types-invalid' : 'nh-assistant.admin.server-editor.reader.media-types-hint') | translate }}\n </span>\n </p>\n @if (serverInvalid(readerField(index, 'mediaTypes'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'mediaTypes'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'mediaTypes')) | nhAssistantTranslate }}</p>\n }\n </div>\n\n <div class=\"field\">\n <label [for]=\"id + '-reader-priority-' + reader.key\">{{ 'nh-assistant.admin.server-editor.reader.priority' | translate }}</label>\n <input\n type=\"number\"\n inputmode=\"numeric\"\n step=\"1\"\n [min]=\"readerPriority.min\"\n [max]=\"readerPriority.max\"\n [id]=\"id + '-reader-priority-' + reader.key\"\n [value]=\"reader.priority\"\n [attr.aria-describedby]=\"describedBy(id + '-reader-priority-hint-' + reader.key, readerField(index, 'priority'))\"\n [attr.aria-invalid]=\"(submitted() && readerProblems()[index].priority) || serverInvalid(readerField(index, 'priority')) ? true : null\"\n (input)=\"updateReader(index, 'priority', value($event))\" />\n <p class=\"hint\" [id]=\"id + '-reader-priority-hint-' + reader.key\">\n <span [class.error-text]=\"submitted() && readerProblems()[index].priority\">\n {{ (submitted() && readerProblems()[index].priority ? 'nh-assistant.admin.server-editor.reader.priority-invalid' : 'nh-assistant.admin.server-editor.reader.priority-hint') | translate: readerPriority }}\n </span>\n </p>\n @if (serverInvalid(readerField(index, 'priority'))) {\n <p class=\"field-error\" [id]=\"errorId(readerField(index, 'priority'))\"><nh-assistant-icon name=\"warning\" />{{ serverErrorKeys(readerField(index, 'priority')) | nhAssistantTranslate }}</p>\n }\n </div>\n </div>\n\n <div class=\"inline\">\n <button\n type=\"button\"\n class=\"secondary\"\n [attr.aria-label]=\"'nh-assistant.admin.server-editor.reader.remove-label' | translate: { number: index + 1 }\"\n (click)=\"removeReader(index)\">\n <nh-assistant-icon name=\"trash\" />{{ 'nh-assistant.admin.server-editor.reader.remove' | translate }}\n </button>\n </div>\n </fieldset>\n } @empty {\n <p class=\"muted\">{{ 'nh-assistant.admin.server-editor.reader.empty' | translate }}</p>\n }\n\n <div class=\"inline\">\n <button\n type=\"button\"\n class=\"secondary\"\n [id]=\"id + '-reader-add'\"\n [disabled]=\"readers().length >= maxReaders || readerToolNames().length === 0\"\n [attr.aria-describedby]=\"id + '-reader-add-hint'\"\n (click)=\"addReader()\">\n <nh-assistant-icon name=\"plus\" />{{ 'nh-assistant.admin.server-editor.reader.add' | translate }}\n </button>\n </div>\n <p class=\"hint\" [id]=\"id + '-reader-add-hint'\">{{ readerAddHint() | translate: { max: maxReaders } }}</p>\n @if (readers().length > 0) {\n <p class=\"message warning\" role=\"note\"><nh-assistant-icon name=\"warning\" />{{ 'nh-assistant.admin.server-editor.reader.leaves-application' | translate }}</p>\n }\n </fieldset>\n }\n\n <label class=\"check\">\n <input type=\"checkbox\" [checked]=\"isEnabled()\" (change)=\"isEnabled.set(checked($event))\" />\n <span>{{ 'nh-assistant.admin.server-editor.enabled' | translate }}</span>\n </label>\n\n @if (error(); as failure) {\n <div class=\"form-error\" role=\"alert\" data-server-error>\n <nh-assistant-icon name=\"warning\" />\n <div>\n <span>{{ errorKeys() | nhAssistantTranslate: failure.code }}</span>\n @if (otherServerErrors().length > 0) {\n <ul>\n @for (other of otherServerErrors(); track other.field) {\n <li><code class=\"mono\">{{ other.field }}</code>: {{ other.keys | nhAssistantTranslate }}</li>\n }\n </ul>\n }\n </div>\n </div>\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()\">\n {{ (saving() ? 'nh-assistant.admin.saving' : 'nh-assistant.admin.save') | translate }}\n </button>\n </div>\n</form>\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"] }]
4452
4841
  }], ctorParameters: () => [], propDecorators: { server: [{ type: i0.Input, args: [{ isSignal: true, alias: "server", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
4453
4842
  function isSecretReference(value) {
4454
4843
  return secretReferencePattern.test(value) && !value.includes('..');
4455
4844
  }
4845
+ /** The media types an administrator typed, separated by commas, spaces or new lines. */
4846
+ function splitMediaTypes(value) {
4847
+ return value.split(/[\s,]+/).map(item => item.trim()).filter(item => item.length > 0);
4848
+ }
4849
+ /**
4850
+ * The priority a reader's field holds: a whole number from -1000 to 1000, empty for 0, or `null` when
4851
+ * the server would refuse it.
4852
+ */
4853
+ function parsePriority(value) {
4854
+ const trimmed = value.trim();
4855
+ if (trimmed.length === 0) {
4856
+ return 0;
4857
+ }
4858
+ const priority = Number(trimmed);
4859
+ return Number.isInteger(priority) && priority >= readerPriority.min && priority <= readerPriority.max ? priority : null;
4860
+ }
4861
+ /** Whether a value is a media type the server accepts: `type/subtype`, optionally with parameters. */
4862
+ function isMediaType(value) {
4863
+ const essence = value.split(';')[0].trim().toLowerCase();
4864
+ return essence.length <= 128 && mediaTypePattern.test(essence);
4865
+ }
4456
4866
  function isAllowedUrl(value) {
4457
4867
  try {
4458
4868
  const url = new URL(value);