{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "agent-tool-call",
  "title": "AgentToolCall",
  "description": "Compact display-only status row for a provider-neutral agent tool lifecycle with optional custom result and diagnostic disclosure surfaces.",
  "type": "registry:ui",
  "meta": {
    "library": "@ds-mo/ui",
    "distribution": "npm",
    "storybook": "https://zainadeel.github.io/compomo/?path=/story/agent-tool-call",
    "source": "src/wc/components/AgentToolCall/AgentToolCall.tsx",
    "intentStatus": "complete",
    "intent": {
      "audience": "specialized",
      "status": "experimental",
      "summary": "Compact display-only status row for a provider-neutral agent tool lifecycle with optional custom result and diagnostic disclosure surfaces.",
      "useWhen": [
        "An agent product needs to expose user-safe tool preparation, queueing, execution, participant wait, completion, failure, denial, or cancellation state."
      ],
      "avoidWhen": [
        "A participant must approve, deny, edit, retry, or execute the tool call; those product controls and consequences remain outside this component."
      ],
      "commonlyComposedWith": [
        "component:ds-agent-response",
        "component:ds-code-block",
        "component:ds-text"
      ],
      "patterns": [
        "pattern:agent-chat"
      ],
      "accessibility": [
        "Every lifecycle state remains visible as text and error or denied meaning does not depend on color.",
        "A disclosure is rendered only when details exist and uses native keyboard and expanded-state semantics.",
        "Structured input, output, and error details use the semantic code-family fallback and optional ligature override."
      ],
      "states": [
        "Applications normalize provider-specific tool states and may localize the visible status label before rendering.",
        "A custom summary replaces the generated name, a custom result owns the primary result surface, and custom details replace generic input, output, and error diagnostics.",
        "An ordinary text-only custom result inherits the body-medium interface-text baseline; structured result components retain ownership of their own layout and typography.",
        "Compose semantic links around ds-text when a custom result is navigational so anchor semantics and design-system typography each have one owner.",
        "Applications load font assets once at their root; tool details and results never fetch or package a font.",
        "This component presents state but never executes a tool or owns approval, retry, authorization, transport, or consequence policy."
      ],
      "responsiveBehavior": [
        "Long names and state labels wrap inside the compact row while custom results and structured diagnostics remain within the transcript lane without widening it."
      ],
      "references": [
        {
          "label": "Lifecycle and slot stories",
          "path": "src/wc/components/AgentToolCall/AgentToolCall.stories.ts"
        },
        {
          "label": "Font ownership and loading",
          "path": "docs/font-ownership.md"
        }
      ]
    },
    "api": {
      "props": {
        "error": {
          "type": "string",
          "resolvedType": "string | undefined",
          "attribute": "error",
          "required": false,
          "mutable": false
        },
        "input": {
          "type": "unknown",
          "resolvedType": "unknown",
          "required": false,
          "mutable": false
        },
        "label": {
          "type": "string",
          "resolvedType": "string",
          "attribute": "label",
          "default": "''",
          "required": false,
          "mutable": false
        },
        "name": {
          "type": "string",
          "resolvedType": "string",
          "attribute": "name",
          "default": "''",
          "required": false,
          "mutable": false
        },
        "open": {
          "type": "boolean",
          "resolvedType": "boolean",
          "attribute": "open",
          "default": "false",
          "required": false,
          "mutable": false
        },
        "output": {
          "type": "unknown",
          "resolvedType": "unknown",
          "required": false,
          "mutable": false
        },
        "state": {
          "type": "AgentToolState",
          "resolvedType": "\"canceled\" | \"denied\" | \"error\" | \"preparing\" | \"queued\" | \"running\" | \"success\" | \"waiting-for-user\"",
          "attribute": "state",
          "default": "'queued'",
          "required": false,
          "mutable": false
        },
        "statusLabel": {
          "type": "string",
          "resolvedType": "string | undefined",
          "attribute": "status-label",
          "required": false,
          "mutable": false
        }
      },
      "events": [
        {
          "name": "dsOpenChange",
          "detail": "{ open: boolean }",
          "bubbles": true,
          "cancelable": true,
          "composed": true
        }
      ],
      "methods": [],
      "slots": []
    },
    "props": {
      "error": {
        "type": "string",
        "resolvedType": "string | undefined",
        "attribute": "error",
        "required": false,
        "mutable": false
      },
      "input": {
        "type": "unknown",
        "resolvedType": "unknown",
        "required": false,
        "mutable": false
      },
      "label": {
        "type": "string",
        "resolvedType": "string",
        "attribute": "label",
        "default": "''",
        "required": false,
        "mutable": false
      },
      "name": {
        "type": "string",
        "resolvedType": "string",
        "attribute": "name",
        "default": "''",
        "required": false,
        "mutable": false
      },
      "open": {
        "type": "boolean",
        "resolvedType": "boolean",
        "attribute": "open",
        "default": "false",
        "required": false,
        "mutable": false
      },
      "output": {
        "type": "unknown",
        "resolvedType": "unknown",
        "required": false,
        "mutable": false
      },
      "state": {
        "type": "AgentToolState",
        "resolvedType": "\"canceled\" | \"denied\" | \"error\" | \"preparing\" | \"queued\" | \"running\" | \"success\" | \"waiting-for-user\"",
        "attribute": "state",
        "default": "'queued'",
        "required": false,
        "mutable": false
      },
      "statusLabel": {
        "type": "string",
        "resolvedType": "string | undefined",
        "attribute": "status-label",
        "required": false,
        "mutable": false
      }
    },
    "events": [
      {
        "name": "dsOpenChange",
        "detail": "{ open: boolean }",
        "bubbles": true,
        "cancelable": true,
        "composed": true
      }
    ],
    "methods": [],
    "slots": [],
    "exports": {
      "customElement": "ds-agent-tool-call",
      "react": "DsAgentToolCall",
      "vue": "DsAgentToolCall",
      "angular": "DsAgentToolCall"
    },
    "consumption": {
      "install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
      "cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
      "customElements": {
        "import": "import '@ds-mo/ui/dist/components/ds-agent-tool-call.js';",
        "example": "<ds-agent-tool-call></ds-agent-tool-call>"
      },
      "react": {
        "import": "import { DsAgentToolCall } from '@ds-mo/ui/react';",
        "example": "<DsAgentToolCall />"
      },
      "vue": {
        "import": "import { DsAgentToolCall } from '@ds-mo/ui/vue';",
        "example": "<DsAgentToolCall />"
      },
      "angular": {
        "import": "import { DsAgentToolCall } from '@ds-mo/ui/angular/ds-agent-tool-call';",
        "example": "<ds-agent-tool-call></ds-agent-tool-call>"
      },
      "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: input, output.",
      "peerDependencies": {
        "required": [
          "@ds-mo/tokens ^6.5.0",
          "@ds-mo/icons ^7.0.0"
        ],
        "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
      }
    }
  },
  "dependencies": [
    "@ds-mo/ui",
    "@ds-mo/tokens",
    "@ds-mo/icons"
  ],
  "registryDependencies": [
    "icon",
    "loader",
    "text"
  ],
  "files": [
    {
      "path": "src/wc/components/AgentToolCall/AgentToolCall.css",
      "content": "@import '../../utils/forced-colors.css';\n\n:host {\n  display: block;\n  min-width: 0;\n}\n\n.agent-tool {\n  min-width: 0;\n  color: var(--color-foreground-secondary);\n}\n\ndetails {\n  margin: 0;\n}\n\nsummary,\n.agent-tool__row {\n  min-width: 0;\n  padding: var(--dimension-space-050) 0;\n}\n\nsummary {\n  cursor: pointer;\n  list-style: none;\n}\n\nsummary::-webkit-details-marker {\n  display: none;\n}\n\n.agent-tool__summary-content {\n  display: grid;\n  align-items: center;\n  grid-template-columns: auto minmax(0, 1fr) auto;\n  gap: var(--dimension-space-075);\n  min-width: 0;\n}\n\n.agent-tool__status-icon {\n  display: flex;\n  align-items: center;\n  color: var(--color-foreground-faint-neutral);\n}\n\n.agent-tool--preparing .agent-tool__status-icon,\n.agent-tool--queued .agent-tool__status-icon,\n.agent-tool--running .agent-tool__status-icon {\n  color: var(--color-foreground-faint-brand);\n}\n\n.agent-tool--waiting-for-user .agent-tool__status-icon {\n  color: var(--color-foreground-bold-warning);\n}\n\n.agent-tool--error .agent-tool__status-icon,\n.agent-tool--denied .agent-tool__status-icon {\n  color: var(--color-foreground-bold-negative);\n}\n\n.agent-tool__title {\n  display: flex;\n  align-items: baseline;\n  flex-wrap: wrap;\n  gap: var(--dimension-space-025) var(--dimension-space-075);\n  min-width: 0;\n  overflow-wrap: anywhere;\n}\n\n.agent-tool__chevron {\n  transition: none;\n}\n\ndetails[open] .agent-tool__chevron {\n  transform: rotate(90deg);\n}\n\n.agent-tool__details,\n.agent-tool__diagnostics {\n  display: grid;\n  gap: var(--dimension-space-075);\n}\n\n.agent-tool__details {\n  padding: var(--dimension-space-050) 0 var(--dimension-space-100)\n    calc(var(--dimension-size-200) + var(--dimension-space-075));\n}\n\n.agent-tool__diagnostics section {\n  display: grid;\n  gap: var(--dimension-space-025);\n}\n\npre {\n  max-width: 100%;\n  margin: 0;\n  padding: var(--dimension-space-075);\n  overflow: auto;\n  border-radius: var(--dimension-radius-050);\n  background: var(--color-background-secondary);\n  color: var(--color-foreground-primary);\n  font-family: var(\n    --typography-font-family-code,\n    'Fira Code', ui-monospace, 'SFMono-Regular', 'Cascadia Code', 'Roboto Mono',\n    Menlo, Monaco, Consolas, 'Liberation Mono', monospace\n  );\n  font-variant-ligatures: var(--ds-code-font-variant-ligatures, normal);\n  font-weight: var(--typography-weight-regular);\n  white-space: pre-wrap;\n  overflow-wrap: anywhere;\n}\n\n.agent-tool__result {\n  min-width: 0;\n  padding-block: var(--dimension-space-050);\n}\n\n.agent-tool__result--plain-text {\n  font-family: var(--typography-font-family-ui);\n  font-size: var(--typography-fontsize-md);\n  font-weight: var(--typography-weight-regular);\n  line-height: var(--typography-lineheight-md);\n  letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\nsummary:focus-visible {\n  border-radius: var(--dimension-radius-025);\n  outline: var(--dimension-stroke-width-025) solid var(--color-border-bold-brand);\n  outline-offset: var(--dimension-space-025);\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  .agent-tool__chevron {\n    transition: transform var(--effect-motion-short-2);\n  }\n}\n\n@media (forced-colors: active) {\n  summary:focus-visible {\n    outline-color: var(--ds-forced-color-selected);\n  }\n\n  .agent-tool--error .agent-tool__summary-content,\n  .agent-tool--denied .agent-tool__summary-content {\n    border-inline-start: var(--dimension-stroke-width-025) solid\n      var(--ds-forced-color-content);\n    padding-inline-start: var(--dimension-space-050);\n  }\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "src/wc/components/AgentToolCall/AgentToolCall.tsx",
      "content": "import {\n  Component,\n  Element,\n  Event,\n  EventEmitter,\n  h,\n  Host,\n  Prop,\n  State,\n} from '@stencil/core';\nimport type { AgentToolState } from '../conversation-types';\n\nconst STATUS_LABELS: Record<AgentToolState, string> = {\n  preparing: 'Preparing',\n  queued: 'Queued',\n  running: 'Running',\n  'waiting-for-user': 'Waiting for your response',\n  success: 'Completed',\n  error: 'Failed',\n  denied: 'Permission denied',\n  canceled: 'Canceled',\n};\n\n@Component({ tag: 'ds-agent-tool-call', styleUrl: 'AgentToolCall.css', scoped: true })\nexport class AgentToolCall {\n  @Element() el!: HTMLElement;\n\n  @Prop() name: string = '';\n  @Prop() label: string = '';\n  @Prop() state: AgentToolState = 'queued';\n  @Prop() statusLabel?: string;\n  @Prop() input?: unknown;\n  @Prop() output?: unknown;\n  @Prop() error?: string;\n  @Prop() open: boolean = false;\n\n  @Event() dsOpenChange!: EventEmitter<{ open: boolean }>;\n\n  @State() private hasSummary = false;\n  @State() private hasResult = false;\n  @State() private hasPlainTextResult = false;\n  @State() private hasDetails = false;\n\n  private slotObserver?: MutationObserver;\n\n  componentWillLoad() {\n    this.syncSlots();\n  }\n\n  componentDidLoad() {\n    this.syncSlots();\n    this.slotObserver = new MutationObserver(() => this.syncSlots());\n    this.slotObserver.observe(this.el, {\n      childList: true,\n      subtree: false,\n      attributes: true,\n      attributeFilter: ['slot'],\n    });\n  }\n\n  disconnectedCallback() {\n    this.slotObserver?.disconnect();\n  }\n\n  private syncSlots() {\n    this.hasSummary = Boolean(this.el.querySelector('[slot=\"summary\"]'));\n    const result = this.el.querySelector<HTMLElement>('[slot=\"result\"]');\n    this.hasResult = Boolean(result);\n    this.hasPlainTextResult = Boolean(\n      result && result.childElementCount === 0 && result.textContent?.trim(),\n    );\n    this.hasDetails = Boolean(this.el.querySelector('[slot=\"details\"]'));\n  }\n\n  private serialize(value: unknown) {\n    if (value === undefined) return '';\n    if (typeof value === 'string') return value;\n    try {\n      return JSON.stringify(value, null, 2);\n    } catch {\n      return String(value);\n    }\n  }\n\n  private get active(): boolean {\n    return ['preparing', 'queued', 'running'].includes(this.state);\n  }\n\n  private get expandable(): boolean {\n    return (\n      this.hasDetails ||\n      this.input !== undefined ||\n      this.output !== undefined ||\n      Boolean(this.error)\n    );\n  }\n\n  private renderStatusIcon() {\n    if (this.active) return <ds-loader size=\"xs\" color=\"inherit\" />;\n    if (this.state === 'success') {\n      return <ds-icon name=\"Check\" size=\"xs\" color=\"inherit\" />;\n    }\n    if (this.state === 'waiting-for-user') {\n      return <ds-icon name=\"Clock\" size=\"xs\" color=\"inherit\" />;\n    }\n    return <ds-icon name=\"ErrorTriangle\" size=\"xs\" color=\"inherit\" />;\n  }\n\n  private renderSummary(expandable: boolean) {\n    return (\n      <span class=\"agent-tool__summary-content\">\n        <span class=\"agent-tool__status-icon\" aria-hidden=\"true\">\n          {this.renderStatusIcon()}\n        </span>\n        <span class=\"agent-tool__title\">\n          {this.hasSummary ? (\n            <slot name=\"summary\" />\n          ) : (\n            <ds-text as=\"span\" variant=\"text-body-small\" emphasis>\n              {this.label || this.name}\n            </ds-text>\n          )}\n          <ds-text\n            class=\"agent-tool__state-label\"\n            as=\"span\"\n            variant=\"text-caption\"\n            color={['error', 'denied'].includes(this.state) ? 'negative' : 'secondary'}\n          >\n            {this.statusLabel ?? STATUS_LABELS[this.state]}\n          </ds-text>\n        </span>\n        {expandable ? (\n          <ds-icon\n            class=\"agent-tool__chevron\"\n            name=\"ChevronRight\"\n            size=\"xs\"\n            color=\"inherit\"\n          />\n        ) : null}\n      </span>\n    );\n  }\n\n  private renderGenericDetails() {\n    return (\n      <div class=\"agent-tool__diagnostics\">\n        {this.input !== undefined ? (\n          <section>\n            <ds-text variant=\"text-caption\" emphasis>Input</ds-text>\n            <pre>{this.serialize(this.input)}</pre>\n          </section>\n        ) : null}\n        {this.output !== undefined ? (\n          <section>\n            <ds-text variant=\"text-caption\" emphasis>Output</ds-text>\n            <pre>{this.serialize(this.output)}</pre>\n          </section>\n        ) : null}\n        {this.error ? (\n          <section>\n            <ds-text variant=\"text-caption\" emphasis>Error</ds-text>\n            <pre>{this.error}</pre>\n          </section>\n        ) : null}\n      </div>\n    );\n  }\n\n  private handleToggle = (event: Event) => {\n    this.dsOpenChange.emit({ open: (event.currentTarget as HTMLDetailsElement).open });\n  };\n\n  render() {\n    const expandable = this.expandable;\n    return (\n      <Host>\n        <div class={`agent-tool agent-tool--${this.state}`}>\n          {expandable ? (\n            <details open={this.open} onToggle={this.handleToggle}>\n              <summary>{this.renderSummary(true)}</summary>\n              <div class=\"agent-tool__details\">\n                {this.hasDetails ? <slot name=\"details\" /> : this.renderGenericDetails()}\n              </div>\n            </details>\n          ) : (\n            <div class=\"agent-tool__row\">{this.renderSummary(false)}</div>\n          )}\n          {this.hasResult ? (\n            <div\n              class={{\n                'agent-tool__result': true,\n                'agent-tool__result--plain-text': this.hasPlainTextResult,\n              }}\n            >\n              <slot name=\"result\" />\n            </div>\n          ) : null}\n        </div>\n      </Host>\n    );\n  }\n}\n",
      "type": "registry:ui"
    }
  ]
}
