AI Connect/Reference/TypeScript
TypeScript
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
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
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
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
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
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
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:
// 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
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:
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.
