ai/ai-chat/ai-chat-tool-call.component.ts

Metadata

Relationships

Depends on

@let _tool = tool();
@let isApprovalRequested = _tool.type === 'tool-approval-requested';
@let showDetails =
  showDefaultToolDetails() || toolDetailsComponent() || _tool.error || isApprovalRequested;
@let isToolExpanded = expanded();

<fieldset
  class="c8y-fieldset p-b-4 ai-tool-call__fieldset"
  [class.fit-w]="isApprovalRequested"
  [attr.aria-label]="getFieldsetLabel(_tool)"
>
  @if (isApprovalRequested) {
    <legend>
      <i
        class="icon-16 text-warning m-r-4"
        [c8yIcon]="'exclamation-triangle'"
        aria-hidden="true"
      ></i>
      {{ getFieldsetLabel(_tool) }}
    </legend>
  }

  <button
    class="btn-clean ai-tool-call__btn"
    [attr.aria-expanded]="showDetails ? isToolExpanded : null"
    [attr.aria-controls]="showDetails ? 'tool-call-' + _tool.toolCallId : null"
    type="button"
    [attr.data-cy]="'tool-call-' + _tool.toolName"
    [disabled]="!showDetails || null"
    (click)="toggleExpanded()"
  >
    @if (_tool.type === 'tool-approval-responded') {
      <i
        class="icon-16 m-r-4"
        [class.text-success]="_tool.approval?.approved"
        [class.text-muted]="!_tool.approval?.approved"
        [c8yIcon]="_tool.approval?.approved ? 'check' : 'ban'"
        aria-hidden="true"
      ></i>
    } @else if (isExecuting()) {
      <i
        class="icon-spin icon-16 text-primary m-r-4"
        c8yIcon="spinner"
        aria-hidden="true"
      ></i>
    } @else {
      <!-- Treat it as an error if a tool still thinks its executing when the message containing it is not -->
      @if (_tool.error || isExecuting()) {
        <i
          class="icon-16 text-danger m-r-4"
          [c8yIcon]="'exclamation-circle'"
          aria-hidden="true"
        ></i>
      } @else if (!isApprovalRequested) {
        <i
          class="icon-16 text-success m-r-4"
          [c8yIcon]="'check'"
          aria-hidden="true"
        ></i>
      }
    }
    @if (showDetails) {
      <i
        class="m-r-4"
        [c8yIcon]="isToolExpanded ? 'expand-arrow' : 'forward'"
        aria-hidden="true"
      ></i>
    }
    <span
      [class.small]="!isApprovalRequested"
      [class.flex-grow]="isApprovalRequested"
    >
      {{ getToolLabel(_tool) | translate }}
    </span>
  </button>
  <!-- If this is an artifact tool, render it - but do so lazily only on first open,
       since these components could be heavyweight (e.g. Monaco)
  -->
  @if (showDetails && (isToolExpanded || everExpanded())) {
    <div
      class="collapse tool-details m-t-8 p-8"
      [attr.aria-label]="'Tool details for message latest tool: ' + _tool.toolName"
      role="region"
      [collapse]="!isToolExpanded"
      [id]="'tool-call-' + _tool.toolCallId"
      [isAnimated]="true"
      data-cy="ai-tool-component"
    >
      @if (toolDetailsComponent()) {
        <ng-container
          [ngComponentOutlet]="toolDetailsComponent()"
          [ngComponentOutletInputs]="{ tool: _tool }"
        ></ng-container>
      } @else {
        @let noneLabel = '(no data)' | translate;
        <pre
          class="fit-w small text-pre-wrap text-break-word"
          [attr.data-label]="'Tool input' | translate"
          >{{ _tool.input || noneLabel | json }}</pre
        >

        @if (_tool.type === 'tool-result') {
          @if (
            typeof _tool.output === 'string' || _tool.output === undefined || _tool.output === null
          ) {
            <pre
              class="fit-w small text-pre-wrap text-break-word"
              [attr.data-label]="'Tool output' | translate"
              >{{ _tool.output || noneLabel }}</pre
            >
          } @else {
            <pre class="fit-w small text-pre-wrap text-break-word">{{ _tool.output | json }}</pre>
          }
        }
      }
    </div>
  }

  @if (isApprovalRequested && approvalEnabled()) {
    <div
      class="btn-toolbar m-l-0 m-t-8 m-b-8"
      [attr.aria-label]="'Tool approval actions' | translate"
      role="toolbar"
    >
      <button
        class="btn btn-danger btn-sm"
        type="button"
        [attr.data-cy]="'tool-deny-' + _tool.toolName"
        (click)="approvalResponse.emit({ approved: false })"
      >
        <i
          class="m-r-4"
          [c8yIcon]="'block'"
          aria-hidden="true"
        ></i>
        {{ 'Deny' | translate }}
      </button>
      @if (!rememberApprovalEnabled()) {
        <!-- Tools requiring explicit approval on every call get no "always approve" options -->
        <button
          class="btn btn-default btn-sm"
          type="button"
          [attr.data-cy]="'tool-approve-' + _tool.toolName"
          (click)="approvalResponse.emit({ approved: true })"
        >
          {{ 'Approve' | translate }}
        </button>
      } @else {
        <div
          class="btn-group"
          role="group"
        >
          <button
            class="btn btn-default btn-sm"
            type="button"
            [attr.data-cy]="'tool-approve-' + _tool.toolName"
            (click)="approvalResponse.emit({ approved: true })"
          >
            {{ 'Approve' | translate }}
          </button>
          <div
            class="btn-group"
            dropdown
            [container]="'body'"
            c8yDropdownFocusTrap
            #approveDropdown="bs-dropdown"
          >
            <button
              class="btn btn-default btn-sm dropdown-toggle"
              aria-label="{{ 'More approval options' | translate }}"
              aria-haspopup="true"
              [attr.aria-expanded]="approveDropdown.isOpen"
              type="button"
              dropdownToggle
              [attr.data-cy]="'tool-approve-options-' + _tool.toolName"
            >
              <i
                c8yIcon="caret-down"
                aria-hidden="true"
              ></i>
            </button>
            <ul
              class="dropdown-menu"
              role="menu"
              *dropdownMenu
            >
              <li>
                <button
                  class="a-i-start"
                  title="{{ 'Always approve this tool' | translate }}"
                  type="button"
                  [attr.data-cy]="'tool-approve-always-' + _tool.toolName"
                  (click)="approvalResponse.emit({ approved: true, remember: 'tool' })"
                >
                  <i
                    class="icon-16"
                    c8yIcon="ok"
                    aria-hidden="true"
                  ></i>
                  <span>
                    {{ 'Always approve this tool' | translate }}
                    <small class="d-block text-muted">
                      {{ 'For this conversation only' | translate }}
                    </small>
                  </span>
                </button>
              </li>
              <li>
                <button
                  class="a-i-start"
                  title="{{ 'Always approve all tools' | translate }}"
                  type="button"
                  [attr.data-cy]="'tool-approve-always-all-' + _tool.toolName"
                  (click)="approvalResponse.emit({ approved: true, remember: 'all' })"
                >
                  <i
                    class="icon-16"
                    c8yIcon="approval"
                    aria-hidden="true"
                  ></i>
                  <span>
                    {{ 'Always approve all tools' | translate }}
                    <small class="d-block text-muted">
                      {{
                        'For this conversation only, unlike the global auto-approve mode'
                          | translate
                      }}
                    </small>
                  </span>
                </button>
              </li>
            </ul>
          </div>
        </div>
      }
    </div>
  }
</fieldset>

results matching ""

    No results matching ""