AI Connect/Reference/TypeScript

TypeScript

Frag die KI über Vinkius

Typisieren Sie die Client-Konfiguration, halten Sie die Capability-Suche explizit, bilden Sie beide Ausführungsergebnisse ab und grenzen Sie geworfene Werte von unknown ein.

Das SDK liefert gebündelte TypeScript-Typen mit. Diese Muster sorgen dafür, dass das Typsystem für Sie arbeitet statt gegen Sie.

Client-Konfiguration vor der Konstruktion typisieren

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 prüft Eigenschaftsnamen und Callback-Argumente, ohne das Objekt zu VinkiusOptions zu erweitern, bevor es den Konstruktor erreicht.

Öffentliche Verträge aus dem Root importieren

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

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

Klassen und Errors sind Laufzeitwerte; importieren Sie sie daher normal, wenn Sie new oder instanceof verwenden. Interfaces und Aliase sollten import type verwenden, wenn Ihre TypeScript-Konfiguration Imports erhält.

Laufzeit-Capability-Suche explizit halten

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}` },
  );
}

Die Verfügbarkeit einer Capability hängt vom Benutzer und der Antwort des Dienstes ab, daher gibt die Suche Capability | undefined zurück. Verdecken Sie diesen Zweig nicht mit einer Non-Null-Assertion.

Die beiden Ausführungsergebnisse abbilden

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 ist im SDK-Typ ein boolescher Wert und kein diskriminierendes Literal. Bilden Sie es auf Ihre eigene Union ab, wenn nachgelagerter Code von erschöpfenden switch-Anweisungen profitiert.

Geworfene Werte von unknown eingrenzen

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;
}

Behalten Sie einen Zweig für unbekannte Werte bei. Adapter-Dispatcher, Anwendungs-Hooks und einige Abbruch-Timing-Pfade können Werte außerhalb der VinkiusError-Hierarchie werfen.

Schemas als Laufzeitverträge behandeln

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 besitzt typisierte Felddeskriptoren. JSONSchema ist bewusst ein Record<string, unknown>, da Connector-Schemas variieren. Validieren Sie es mit der von Ihrer Anwendung gewählten JSON-Schema-Bibliothek, bevor Sie Tool-Argumente als domänenspezifischen Typ behandeln. Vermeiden Sie es, beliebige Modellausgaben direkt zu casten:

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

Stattdessen validieren Sie modelArgs gegen capability.inputSchema und überführen anschließend den validierten Wert in Ihren Anwendungstyp.

Anfragesteuerungen separat typisieren

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

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

Jede Anfragemethode akzeptiert signal. Nur die Capability-Ausführung fügt idempotencyKey hinzu. Adapter-Dispatch-Helfer akzeptieren keine ExecuteOptions, auch wenn ihre zurückgegebenen oder gebundenen Ausführungsfunktionen typisiert sind.

Fabrik-Rückgabetypen in Adaptern erhalten

Fabrik-Adapter sind generisch und geben das zurück, was Ihre injizierte Fabrik erzeugt:

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,
});

Dieses Beispiel verwendet nur den strukturellen Vertrag des Adapters. Testen Sie eine echte Framework-Fabrik gegen die Version, die Ihre Anwendung installiert.

Nächste Schritte