@microsoft/agents-a365-observability package

Classes

Agent365ExporterOptions

Nombre maximal d’étendues par lot d’exportation.

BaggageBuilder

Par générateur de bagages de demande pour la propagation du contexte OpenTelemetry.

Cette classe fournit une API Fluent pour définir les valeurs de bagages qui seront propagées dans le contexte OpenTelemetry.

Exemple

const scope = new BaggageBuilder()
  .tenantId("tenant-123")
  .agentId("agent-456")
  .build();

scope.enter();
// Baggage is set in this context
// ... do work ...
scope.exit();
// Baggage is restored after exiting the context
BaggageScope

Gestionnaire de contexte pour l’étendue des bagages.

Cette classe gère le cycle de vie des valeurs de bagages, en les définissant sur entrée et en restaurant le contexte précédent lors de la sortie.

Builder

Générateur de configuration de l’agent 365 avec le suivi OpenTelemetry

ExecuteToolScope

Fournit l’étendue de suivi OpenTelemetry pour les opérations d’exécution d’outils IA.

InferenceScope

Fournit l’étendue de suivi OpenTelemetry pour les opérations d’inférence IA génératives.

InvokeAgentScope

Fournit l’étendue de suivi OpenTelemetry pour les opérations d’appel d’agent IA.

ObservabilityConfiguration

Configuration du package d’observabilité. Hérite des paramètres d’exécution et ajoute des paramètres spécifiques à l’observabilité.

ObservabilityManager

Point d’entrée principal de l’agent 365 fournissant le suivi OpenTelemetry pour les agents et outils IA

OpenTelemetryConstants

Constantes OpenTelemetry pour Agent 365

OpenTelemetryScope

Classe de base pour les étendues de suivi OpenTelemetry

OutputScope

Fournit l’étendue de suivi OpenTelemetry pour le suivi des messages de sortie avec la liaison d’étendue parente.

PerRequestSpanProcessorConfiguration

Configuration de PerRequestSpanProcessor. Hérite des paramètres d’exécution (clusterCategory, isNodeEnvDevelopment) et ajoute des garde-fous de processeur par requête.

Cela est séparé de ObservabilityConfiguration, car PerRequestSpanProcessor est utilisé uniquement dans des scénarios spécifiques et ces paramètres ne doivent pas être exposés dans la common ObservabilityConfiguration.

Interfaces

AgentDetails

Détails sur un agent IA

BlobPart

Données binaires inline (encodées en base64).

BuilderOptions

Options de configuration pour Agent 365 Observability Builder

CallerDetails

Détails de l’appelant pour la création de l’étendue. Prend en charge les appelants humains, les appelants d’agent ou les deux (A2A avec un humain dans la chaîne).

Remarque sur la migration : Dans v1, le nom CallerDetails fait référence à l’identité de l’appelant humain (maintenant UserDetails). Dans la version 2, elle a été réaffectée en tant que wrapper qui regroupe les informations de l’appelant humain et de l’agent.

Voir UserDetails — Identité de l’appelant humain (précédemment CallerDetails) Voir CHANGELOG.md — section changements cassants pour obtenir des conseils sur la migration

Channel

Représente le canal d’un appel

ChatMessage

Message d’entrée envoyé à un modèle (conventions sémantiques TELLI gen-ai).

FilePart

Référence à un fichier préchargement chargé.

GenericPart

Partie extensible pour les types personnalisés/ futurs.

GenericServerToolCall

Détails de l’appel de l’outil serveur extensible avec un discriminateur de type.

GenericServerToolCallResponse

Réponse d’appel de l’outil serveur extensible avec un discriminateur de type.

ILogger

Interface d’enregistreur d’événements personnalisé pour l’observabilité Agent 365 Implémenter cette interface pour prendre en charge la journalisation des back-ends

InferenceDetails

Détails d’un appel d’inférence

InferenceResponse

Détails de l’enregistrement de la réponse à partir d’un appel d’inférence

InputMessages
InvokeAgentScopeDetails

Détails de l’appel de l’étendue de l’agent.

OutputMessage

Message de sortie généré par un modèle (conventions sémantiques TELLI gen-ai).

OutputMessages
OutputResponse

Représente une réponse contenant des messages de sortie d’un agent. Utilisé avec OutputScope pour le suivi des messages de sortie. Accepte des chaînes simples, des objets OutputMessage ISTO structurés ou une dictée brute (traitée comme un résultat d’appel d’outil par spécification EAP).

ParentSpanRef

Référence à une étendue parente pour la liaison parent-enfant explicite entre les limites asynchrones. Utilisé lorsque la propagation automatique du contexte échoue (par exemple, rappels WebSocket, gestionnaires d’événements externes).

ReasoningPart

Raisonnement du modèle / contenu chaîné de pensée.

Request

Représente une requête avec le contexte de télémétrie. Utilisé dans tous les types d’étendue pour le suivi des canaux et des conversations.

ServerToolCallPart

Appel de l’outil côté serveur.

ServerToolCallResponsePart

Réponse de l’outil côté serveur.

ServiceEndpoint

Représente un point de terminaison pour l’appel d’agent

SpanDetails

Étendez les détails de configuration pour la création de l’étendue. Regroupe les options d’étendue OpenTelemetry dans un seul objet afin que la signature de la méthode d’étendue reste stable à mesure que de nouvelles options sont ajoutées.

TextPart

Contenu en texte brut.

ToolCallDetails

Détails d’un appel d’outil effectué par un agent

ToolCallRequestPart

Un appel d’outil demandé par le modèle.

ToolCallResponsePart

Résultat d’un appel d’outil.

UriPart

Référence d’URI externe.

UserDetails

Détails sur l’appelant d’utilisateur humain.

Alias de type

EnhancedAgentDetails
HeadersCarrier

Type de transporteur pour les en-têtes HTTP utilisés dans la propagation du contexte de trace. Compatible avec Node.js IncomingHttpHeaders et les mappages de chaînes simples.

InputMessagesParam

Entrée acceptée pour recordInputMessages. Prend en charge une seule chaîne, un tableau de chaînes (compat descendant) ou le wrapper avec version.

MessagePart

Union de tous les types de parties de message par conventions sémantiques AUTHENTIFICATION gen-ai.

Remarque : GenericPart agit comme un catch-all pour la compatibilité ascendante avec les types de composants personnalisés ou futurs. Étant donné qu’il type est string (pas un littéral), exhaustifcaseswitch/sur part.type ne produit pas d’erreurs au moment de la compilation pour les cas non gérés.

ObservabilityConfigurationOptions

Options de configuration de l’observabilité : étend les options d’exécution. Toutes les substitutions sont des fonctions appelées sur chaque accès aux propriétés.

Hérité de RuntimeConfigurationOptions :

  • clusterCategory
  • isNodeEnvDevelopment

Remarque : isDevelopmentEnvironment est un getter dérivé sur la classe de configuration (basé sur clusterCategory), et non une option substituable.

OutputMessagesParam

Entrée acceptée pour recordOutputMessages. Prend en charge une seule chaîne, un tableau de chaînes (compat descendant) ou le wrapper avec version.

ParentContext

Contexte parent pour la création d’étendues. Accepte soit :

PerRequestSpanProcessorConfigurationOptions

Options de configuration pour PerRequestSpanProcessor : étend les options d’exécution. Toutes les substitutions sont des fonctions appelées sur chaque accès aux propriétés.

Hérité de RuntimeConfigurationOptions :

  • clusterCategory, isNodeEnvDevelopment
ResponseMessagesParam

Entrée acceptée pour OutputResponse.messages. Prend en charge les chaînes simples, les OutputMessages structurés ou une dictée brute (traitée comme un résultat d’appel d’outil par spécification EAP et sérialisée directement via JSON.stringify).

Énumérations

ExporterEventNames

Noms d’événements utilisés par Agent365Exporter pour la journalisation et la surveillance. Il s’agit de types d’événements de faible cardinalité pour garantir une surveillance et une agrégation efficaces.

FinishReason

Raison pour laquelle un modèle a cessé de générer par conventions sémantiques gen-ai TELLI.

InferenceOperationType

Représente une opération différente pour les types pour l’inférence de modèle

InvocationRole

Représente différents rôles qui peuvent appeler un agent

MessageRole

Rôle d’un participant au message par conventions sémantiques TELLI gen-ai.

Modality

Modalité multimédia pour les parties blob, fichier et URI.

Functions

createContextWithParentSpanRef(Context, ParentSpanRef)

Crée un contexte avec une référence d’étendue parente explicite. Cela permet aux étendues enfants d’être correctement parentées même lorsque le contexte asynchrone est rompu.

extractContextFromHeaders(HeadersCarrier, Context)

Extrait le contexte de trace des en-têtes HTTP entrants à l’aide du propagateur W3C enregistré globalement. Retourne un OTel ParentContext qui peut être passé aux classes d’étendue en tant que ParentContext.

Exemple

const parentCtx = extractContextFromHeaders(req.headers);
const scope = InvokeAgentScope.start(request, scopeDetails, agentDetails, undefined, { parentContext: parentCtx });
formatError(unknown)

Format d’objet d’erreur pour la journalisation avec la trace de message et de pile

getExportToken(Context)

Récupérez le jeton d’exportation par requête à partir d’un contexte OTel donné (ou actif).

getLogger()

Obtenir l’instance d’enregistreur d’événements actuel

injectContextToHeaders(Record<string, string>, Context)

Injecte le contexte de trace actuel (traceparent/tracestate en-têtes) dans l’objet d’en-têtes fourni à l’aide du propageur W3C enregistré globalement.

Exemple

const headers: Record<string, string> = {};
injectContextToHeaders(headers);
await fetch('http://service-b/process', { headers });
isPerRequestExportEnabled(IConfigurationProvider<PerRequestSpanProcessorConfiguration>)

Vérifiez si l’exportation par demande est activée. Priorité : variable d’environnement du fournisseur > de configuration de remplacement > interne. Lorsqu’il est activé, perRequestSpanProcessor est utilisé au lieu de BatchSpanProcessor. Le jeton est transmis via OTel Context (stockage local asynchrone) au moment de l’exportation.

normalizeInputMessages(InputMessagesParam)

Normalise un InputMessagesParam wrapper avec version.InputMessages

  • string / string[]→ converties en wrapper et encapsulées ChatMessage[]
  • InputMessages → retourné as-is
normalizeOutputMessages(OutputMessagesParam)

Normalise un OutputMessagesParam wrapper avec version.OutputMessages

  • string / string[]→ converties en wrapper et encapsulées OutputMessage[]
  • OutputMessages → retourné as-is
resetLogger()

Rétablir l’enregistreur d’événements de console par défaut (principalement pour les tests)

runWithExportToken<T>(string, () => T)

Exécutez une fonction dans un contexte qui contient le jeton d’exportation par requête. Cela conserve le jeton uniquement dans OTel Context (ALS), jamais dans un registre.

Le jeton peut être mis à jour ultérieurement avant updateExportToken() le vidage de la trace . Utile lorsque le rappel est long et que le jeton d’origine peut expirer avant l’exportation.

runWithExtractedTraceContext<T>(HeadersCarrier, () => T)

Extrait le contexte de trace des en-têtes HTTP entrants et exécute le rappel dans ce contexte. Toutes les étendues créées à l’intérieur du rappel sont parentées de la trace extraite.

Exemple

runWithExtractedTraceContext(req.headers, () => {
  const scope = InvokeAgentScope.start(request, scopeDetails, agentDetails);
  scope.dispose();
});
runWithParentSpanRef<T>(ParentSpanRef, () => T)

Exécute une fonction de rappel dans un contexte qui a une référence d’étendue parente explicite. Cela est utile pour créer des étendues enfants dans des rappels asynchrones où la propagation du contexte est interrompue.

safeSerializeToJson(string | Record<string, unknown>, string)

Garantit que la valeur est toujours une chaîne d’analyse JSON.

  • Les objets sont sérialisés via JSON.stringify.
  • Les chaînes qui sont déjà des objets/tableaux JSON valides sont passées.
  • Toutes les autres chaînes (y compris les primitives JSON nues) sont encapsulées : { [key]: value }.
serializeMessages(InputMessages | OutputMessages)

Sérialise un wrapper de message versionné au format JSON.

La sortie est l’objet wrapper complet : {"version":"0.1.0","messages":[...]}.

La méthode try/catch garantit que l’enregistrement de télémétrie n’est pas levée même si les parties de message contiennent des valeurs non-JSON sérialisables (par exemple, BigInt, refs circulaires).

setLogger(ILogger)

Définir une implémentation d’enregistreur d’événements personnalisée pour le Kit de développement logiciel (SDK) observabilité

Exemple avec Winston :

import * as winston from 'winston';
import { setLogger } from '@microsoft/agents-a365-observability';

const winstonLogger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

setLogger({
  info: (msg, ...args) => winstonLogger.info(msg, ...args),
  warn: (msg, ...args) => winstonLogger.warn(msg, ...args),
  error: (msg, ...args) => winstonLogger.error(msg, ...args),
  event: (eventType, isSuccess, durationMs, message, details) => {
    // eventType is ExporterEventNames enum value
    winstonLogger.log({ level: isSuccess ? 'info' : 'error', eventType, isSuccess, durationMs, message, ...details });
  }
});
truncateValue(string)

Tronquer une valeur de chaîne pour MAX_ATTRIBUTE_LENGTH caractères. Si la valeur dépasse la limite, elle est rognée et un suffixe de troncation est ajouté, avec la longueur totale limitée à exactement MAX_ATTRIBUTE_LENGTH.

updateExportToken(string)

Mettez à jour le jeton d’exportation dans le contexte OTel actif. Appelez-le pour actualiser le jeton avant de mettre fin à l’étendue racine lorsque le jeton d’origine a expiré pendant une demande de longue durée.

Doit être appelé dans le même contexte asynchrone créé par runWithExportToken.

Variables

A365_MESSAGE_SCHEMA_VERSION
MAX_ATTRIBUTE_LENGTH

Longueur maximale pour les valeurs d’attribut d’étendue. Les valeurs dépassant cette limite sont tronquées avec un suffixe.

defaultObservabilityConfigurationProvider

Fournisseur par défaut partagé pour ObservabilityConfiguration.

defaultPerRequestSpanProcessorConfigurationProvider

Fournisseur par défaut partagé pour PerRequestSpanProcessorConfiguration.

logger

Instance d’enregistreur d’événements par défaut pour la compatibilité descendante. Délégués à l’enregistreur d’événements global qui peuvent être remplacés via setLogger().

Informations relatives à la fonction

createContextWithParentSpanRef(Context, ParentSpanRef)

Crée un contexte avec une référence d’étendue parente explicite. Cela permet aux étendues enfants d’être correctement parentées même lorsque le contexte asynchrone est rompu.

function createContextWithParentSpanRef(base: Context, parent: ParentSpanRef): Context

Paramètres

base

Context

Contexte de base à étendre (généralement context.active())

parent
ParentSpanRef

Référence d’étendue parent contenant traceId et spanId

Retours

Context

Nouveau contexte avec le jeu d’étendues parent

extractContextFromHeaders(HeadersCarrier, Context)

Extrait le contexte de trace des en-têtes HTTP entrants à l’aide du propagateur W3C enregistré globalement. Retourne un OTel ParentContext qui peut être passé aux classes d’étendue en tant que ParentContext.

Exemple

const parentCtx = extractContextFromHeaders(req.headers);
const scope = InvokeAgentScope.start(request, scopeDetails, agentDetails, undefined, { parentContext: parentCtx });
function extractContextFromHeaders(headers: HeadersCarrier, baseCtx?: Context): Context

Paramètres

headers
HeadersCarrier

En-têtes de requête HTTP entrants contenant traceparent/tracestate.

baseCtx

Context

Contexte de base facultatif à étendre. La valeur par défaut est le contexte actif.

Retours

Context

Contexte OTel contenant les informations de trace extraites.

formatError(unknown)

Format d’objet d’erreur pour la journalisation avec la trace de message et de pile

function formatError(error: unknown): string

Paramètres

error

unknown

Retours

string

getExportToken(Context)

Récupérez le jeton d’exportation par requête à partir d’un contexte OTel donné (ou actif).

function getExportToken(ctx?: Context): string | undefined

Paramètres

ctx

Context

Retours

string | undefined

getLogger()

Obtenir l’instance d’enregistreur d’événements actuel

function getLogger(): ILogger

Retours

injectContextToHeaders(Record<string, string>, Context)

Injecte le contexte de trace actuel (traceparent/tracestate en-têtes) dans l’objet d’en-têtes fourni à l’aide du propageur W3C enregistré globalement.

Exemple

const headers: Record<string, string> = {};
injectContextToHeaders(headers);
await fetch('http://service-b/process', { headers });
function injectContextToHeaders(headers: Record<string, string>, ctx?: Context): Record<string, string>

Paramètres

headers

Record<string, string>

Objet mutable dans lequel les en-têtes de contexte de trace sont écrits.

ctx

Context

Contexte OTel facultatif à partir duquel injecter. La valeur par défaut est le contexte actif.

Retours

Record<string, string>

Le même headers objet, pour le chaînage pratique.

isPerRequestExportEnabled(IConfigurationProvider<PerRequestSpanProcessorConfiguration>)

Vérifiez si l’exportation par demande est activée. Priorité : variable d’environnement du fournisseur > de configuration de remplacement > interne. Lorsqu’il est activé, perRequestSpanProcessor est utilisé au lieu de BatchSpanProcessor. Le jeton est transmis via OTel Context (stockage local asynchrone) au moment de l’exportation.

function isPerRequestExportEnabled(configProvider?: IConfigurationProvider<PerRequestSpanProcessorConfiguration>): boolean

Paramètres

configProvider

IConfigurationProvider<PerRequestSpanProcessorConfiguration>

Fournisseur de configuration facultatif. La valeur par défaut est defaultPerRequestSpanProcessorConfigurationProvider si elle n’est pas spécifiée.

Retours

boolean

normalizeInputMessages(InputMessagesParam)

Normalise un InputMessagesParam wrapper avec version.InputMessages

  • string / string[]→ converties en wrapper et encapsulées ChatMessage[]
  • InputMessages → retourné as-is
function normalizeInputMessages(param: InputMessagesParam): InputMessages

Paramètres

Retours

normalizeOutputMessages(OutputMessagesParam)

Normalise un OutputMessagesParam wrapper avec version.OutputMessages

  • string / string[]→ converties en wrapper et encapsulées OutputMessage[]
  • OutputMessages → retourné as-is
function normalizeOutputMessages(param: OutputMessagesParam): OutputMessages

Paramètres

Retours

resetLogger()

Rétablir l’enregistreur d’événements de console par défaut (principalement pour les tests)

function resetLogger()

runWithExportToken<T>(string, () => T)

Exécutez une fonction dans un contexte qui contient le jeton d’exportation par requête. Cela conserve le jeton uniquement dans OTel Context (ALS), jamais dans un registre.

Le jeton peut être mis à jour ultérieurement avant updateExportToken() le vidage de la trace . Utile lorsque le rappel est long et que le jeton d’origine peut expirer avant l’exportation.

function runWithExportToken<T>(token: string, fn: () => T): T

Paramètres

token

string

fn

() => T

Retours

T

runWithExtractedTraceContext<T>(HeadersCarrier, () => T)

Extrait le contexte de trace des en-têtes HTTP entrants et exécute le rappel dans ce contexte. Toutes les étendues créées à l’intérieur du rappel sont parentées de la trace extraite.

Exemple

runWithExtractedTraceContext(req.headers, () => {
  const scope = InvokeAgentScope.start(request, scopeDetails, agentDetails);
  scope.dispose();
});
function runWithExtractedTraceContext<T>(headers: HeadersCarrier, callback: () => T): T

Paramètres

headers
HeadersCarrier

En-têtes de requête HTTP entrants contenant traceparent/tracestate.

callback

() => T

Fonction à exécuter dans le contexte extrait.

Retours

T

Résultat du rappel.

runWithParentSpanRef<T>(ParentSpanRef, () => T)

Exécute une fonction de rappel dans un contexte qui a une référence d’étendue parente explicite. Cela est utile pour créer des étendues enfants dans des rappels asynchrones où la propagation du contexte est interrompue.

function runWithParentSpanRef<T>(parent: ParentSpanRef, callback: () => T): T

Paramètres

parent
ParentSpanRef

Référence de l’étendue parente

callback

() => T

Fonction à exécuter avec le contexte parent

Retours

T

Résultat du rappel

safeSerializeToJson(string | Record<string, unknown>, string)

Garantit que la valeur est toujours une chaîne d’analyse JSON.

  • Les objets sont sérialisés via JSON.stringify.
  • Les chaînes qui sont déjà des objets/tableaux JSON valides sont passées.
  • Toutes les autres chaînes (y compris les primitives JSON nues) sont encapsulées : { [key]: value }.
function safeSerializeToJson(value: string | Record<string, unknown>, key: string): string

Paramètres

value

string | Record<string, unknown>

Valeur à sérialiser.

key

string

Clé à utiliser lors de l’habillage d’une chaîne simple.

Retours

string

serializeMessages(InputMessages | OutputMessages)

Sérialise un wrapper de message versionné au format JSON.

La sortie est l’objet wrapper complet : {"version":"0.1.0","messages":[...]}.

La méthode try/catch garantit que l’enregistrement de télémétrie n’est pas levée même si les parties de message contiennent des valeurs non-JSON sérialisables (par exemple, BigInt, refs circulaires).

function serializeMessages(wrapper: InputMessages | OutputMessages): string

Paramètres

Retours

string

setLogger(ILogger)

Définir une implémentation d’enregistreur d’événements personnalisée pour le Kit de développement logiciel (SDK) observabilité

Exemple avec Winston :

import * as winston from 'winston';
import { setLogger } from '@microsoft/agents-a365-observability';

const winstonLogger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

setLogger({
  info: (msg, ...args) => winstonLogger.info(msg, ...args),
  warn: (msg, ...args) => winstonLogger.warn(msg, ...args),
  error: (msg, ...args) => winstonLogger.error(msg, ...args),
  event: (eventType, isSuccess, durationMs, message, details) => {
    // eventType is ExporterEventNames enum value
    winstonLogger.log({ level: isSuccess ? 'info' : 'error', eventType, isSuccess, durationMs, message, ...details });
  }
});
function setLogger(customLogger: ILogger)

Paramètres

customLogger
ILogger

Implémentation de l’enregistreur d’événements personnalisé

truncateValue(string)

Tronquer une valeur de chaîne pour MAX_ATTRIBUTE_LENGTH caractères. Si la valeur dépasse la limite, elle est rognée et un suffixe de troncation est ajouté, avec la longueur totale limitée à exactement MAX_ATTRIBUTE_LENGTH.

function truncateValue(value: string): string

Paramètres

value

string

Chaîne à tronquer

Retours

string

Chaîne d’origine si dans les limites, sinon la chaîne tronquée

updateExportToken(string)

Mettez à jour le jeton d’exportation dans le contexte OTel actif. Appelez-le pour actualiser le jeton avant de mettre fin à l’étendue racine lorsque le jeton d’origine a expiré pendant une demande de longue durée.

Doit être appelé dans le même contexte asynchrone créé par runWithExportToken.

function updateExportToken(token: string): boolean

Paramètres

token

string

Nouveau jeton à utiliser pour l’exportation.

Retours

boolean

true si le jeton a été mis à jour avec succès, false si aucun titulaire de jeton n’a été trouvé.

Détails de variable

A365_MESSAGE_SCHEMA_VERSION

A365_MESSAGE_SCHEMA_VERSION: "0.1.0"

Type

string

MAX_ATTRIBUTE_LENGTH

Longueur maximale pour les valeurs d’attribut d’étendue. Les valeurs dépassant cette limite sont tronquées avec un suffixe.

MAX_ATTRIBUTE_LENGTH: 8192

Type

8192

defaultObservabilityConfigurationProvider

Fournisseur par défaut partagé pour ObservabilityConfiguration.

defaultObservabilityConfigurationProvider: DefaultConfigurationProvider<ObservabilityConfiguration>

Type

defaultPerRequestSpanProcessorConfigurationProvider

Fournisseur par défaut partagé pour PerRequestSpanProcessorConfiguration.

defaultPerRequestSpanProcessorConfigurationProvider: DefaultConfigurationProvider<PerRequestSpanProcessorConfiguration>

Type

logger

Instance d’enregistreur d’événements par défaut pour la compatibilité descendante. Délégués à l’enregistreur d’événements global qui peuvent être remplacés via setLogger().

logger: ILogger

Type