AI Connect/Reference/TypeScript

TypeScript

Pregunta a la IA sobre Vinkius

Define los tipos de la configuración del cliente, mantén explícita la búsqueda de capacidades, representa los dos resultados de ejecución y acota los valores lanzados de unknown.

El SDK incluye tipos de TypeScript empaquetados. Estos patrones hacen que el sistema de tipos trabaje para ti en lugar de contra ti.

Define el tipo de la configuración del cliente antes de construirlo

typescript
import { Vinkius } from '@vinkius/connect';
import type { VinkiusOptions } from '@vinkius/connect';

const options = {
  appId: process.env.VINKIUS_APP_ID!,
  apiKey: process.env.VINKIUS_APP_KEY!,
  timeoutMs: 20_000,
  maxRetries: 2,
  hooks: {
    onResponse: ({ status, requestId }) => {
      console.debug({ status, requestId });
    },
  },
} satisfies VinkiusOptions;

export const vinkius = new Vinkius(options);

satisfies comprueba los nombres de las propiedades y los argumentos de las funciones de retorno sin ampliar el objeto a VinkiusOptions antes de que llegue al constructor.

Importa los contratos públicos desde la raíz

typescript
import {
  Capability,
  CapabilitySet,
  ValidationError,
  Vinkius,
  VinkiusError,
} from '@vinkius/connect';

import type {
  CapabilityQuery,
  CapabilityResult,
  ConnectorStatus,
  CredentialSchema,
  CredentialStatus,
  ExecuteOptions,
  JSONSchema,
  RequestOptions,
} from '@vinkius/connect';

Las clases y los errores son valores en tiempo de ejecución, así que impórtalos normalmente cuando uses new o instanceof. Las interfaces y los alias deben usar import type cuando tu configuración de TypeScript conserve las importaciones.

Mantén explícita la búsqueda de capacidades en tiempo de ejecución

typescript
import type { Capability, CapabilityResult } from '@vinkius/connect';

async function executeIssue(
  externalId: string,
  operationId: string,
): Promise<CapabilityResult> {
  const query = {
    include: ['github'],
  } satisfies CapabilityQuery;

  const capabilities = await vinkius.user(externalId).capabilities(query);
  const capability: Capability | undefined =
    capabilities.findCapability('github__create_issue');

  if (!capability) {
    throw new Error('GitHub create_issue is not available for this user');
  }

  return capability.execute(
    { owner: 'acme', repo: 'product', title: 'Document the SDK' },
    { idempotencyKey: `create-issue:${operationId}` },
  );
}

La disponibilidad de capacidades depende del usuario y de la respuesta del servicio, por lo que la búsqueda devuelve Capability | undefined. No ocultes esa rama con una aserción de valor no nulo.

Representa los dos resultados de ejecución

typescript
interface CompletedAction {
  kind: 'completed';
  text: string;
}

interface FailedAction {
  kind: 'capability-error';
  text: string;
}

type ActionOutcome = CompletedAction | FailedAction;

function mapResult(result: CapabilityResult): ActionOutcome {
  const text = result.content.map((part) => part.text).join('\n');
  return result.isError
    ? { kind: 'capability-error', text }
    : { kind: 'completed', text };
}

isError es un booleano y no un literal discriminante en el tipo del SDK, por lo que puedes asignarlo a tu propia unión cuando el código posterior se beneficie de una selección exhaustiva.

Acota los valores lanzados desde unknown

typescript
import {
  RateLimitError,
  ValidationError,
  VinkiusError,
} from '@vinkius/connect';

type RequestFailure =
  | { kind: 'validation'; fields: unknown }
  | { kind: 'rate-limit'; retryAfterMs?: number }
  | { kind: 'sdk'; code: string; status: number; requestId?: string };

function classifyFailure(error: unknown): RequestFailure | undefined {
  if (error instanceof ValidationError) {
    return { kind: 'validation', fields: error.errors };
  }

  if (error instanceof RateLimitError) {
    return {
      kind: 'rate-limit',
      ...(error.retryAfterMs !== undefined
        ? { retryAfterMs: error.retryAfterMs }
        : {}),
    };
  }

  if (error instanceof VinkiusError) {
    return {
      kind: 'sdk',
      code: error.code,
      status: error.status,
      ...(error.requestId ? { requestId: error.requestId } : {}),
    };
  }

  return undefined;
}

Mantén una rama para valores desconocidos. Los despachadores de adaptadores, los hooks de la aplicación y algunas rutas temporales de cancelación pueden lanzar valores ajenos a la jerarquía de VinkiusError.

Trata los esquemas como contratos en tiempo de ejecución

typescript
function requiredCredentialKeys(schema: CredentialSchema): string[] {
  return Object.entries(schema)
    .filter(([, field]) => field.required === true)
    .map(([key]) => key);
}

function capabilitySchema(capability: Capability): JSONSchema {
  return capability.inputSchema;
}

CredentialSchema tiene descriptores de campos tipados. JSONSchema es deliberadamente Record<string, unknown> porque los esquemas de los conectores varían. Valídalo con la biblioteca de JSON Schema elegida por tu aplicación antes de tratar los argumentos de una herramienta como un tipo específico del dominio. Evita convertir directamente una salida arbitraria del modelo:

typescript
// Avoid: the cast performs no runtime validation.
const issue = modelArgs as { owner: string; repo: string; title: string };

En su lugar, valida modelArgs con respecto a capability.inputSchema y después asigna el valor validado al tipo de tu aplicación.

Define por separado los tipos de los controles de solicitud

typescript
const requestOptions: RequestOptions = {
  signal: request.signal,
};

const executeOptions: ExecuteOptions = {
  signal: request.signal,
  idempotencyKey: `operation:${operationId}`,
};

Todos los métodos que realizan solicitudes aceptan signal. Solo la ejecución de capacidades añade idempotencyKey. Los auxiliares de despacho de adaptadores no aceptan ExecuteOptions, aunque sus funciones de ejecución devueltas o vinculadas estén tipadas.

Conserva los tipos devueltos por las fábricas en los adaptadores

Los adaptadores de fábrica son genéricos y devuelven lo que cree la fábrica proporcionada:

typescript
import { toLangChainTools } from '@vinkius/connect/langchain';
import type { JSONSchema } from '@vinkius/connect';

interface AppTool {
  name: string;
  run(input: Record<string, unknown>): Promise<string>;
}

const toolFactory = (
  fn: (input: Record<string, unknown>) => Promise<string>,
  config: { name: string; description: string; schema: JSONSchema },
): AppTool => ({
  name: config.name,
  run: fn,
});

const tools: AppTool[] = toLangChainTools(capabilities, {
  tool: toolFactory,
});

Este ejemplo usa únicamente el contrato estructural del adaptador. Prueba una fábrica real del framework con la versión instalada por tu aplicación.

Próximos pasos