AI Connect/Reference/TypeScript
TypeScript
クライアント設定に型を付け、ケイパビリティの検索を明示的に保ち、2 つの実行結果を表現し、unknown からスローされる値を絞り込みます。
SDK には 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 は、オブジェクトがコンストラクターに渡される前に VinkiusOptions へ拡大されることなく、プロパティ名とコールバック引数を検証します。
公開契約をルートからインポートする
import {
Capability,
CapabilitySet,
ValidationError,
Vinkius,
VinkiusError,
} from '@vinkius/connect';
import type {
CapabilityQuery,
CapabilityResult,
ConnectorStatus,
CredentialSchema,
CredentialStatus,
ExecuteOptions,
JSONSchema,
RequestOptions,
} from '@vinkius/connect';クラスとエラーはランタイムの値であるため、new や instanceof を使用する場合は通常どおりインポートします。TypeScript の設定で imports が保持される場合は、インターフェースやエイリアスに import type を使用してください。
ランタイムのケイパビリティ検索を明示的に保つ
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}` },
);
}ケイパビリティの可用性はユーザーとサービスのレスポンスに依存するため、検索は Capability | undefined を返します。非 null アサーションでこの分岐を隠さないでください。
2 つの実行結果を表現する
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 };
}SDK の型では isError はブール値であり、判別用のリテラルではありません。後続のコードで網羅的な switch の恩恵を受けられる場合は、独自のユニオン型にマッピングしてください。
unknown からスローされる値を絞り込む
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;
}不明な値のための分岐を残してください。adapter のディスパッチャー、アプリケーションの hooks、一部のアボートのタイミングに関わるパスは、VinkiusError 階層外の値をスローすることがあります。
スキーマをランタイムの契約として扱う
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 は型付きのフィールド記述子を持ちます。JSONSchema はコネクタのスキーマが異なるため、意図的に Record<string, unknown> になっています。ツールの引数をドメイン固有の型として扱う前に、アプリケーションが選択した JSON Schema ライブラリで検証してください。モデルの任意の出力を直接キャストすることは避けてください:
// Avoid: the cast performs no runtime validation.
const issue = modelArgs as { owner: string; repo: string; title: string };代わりに、modelArgs を capability.inputSchema に対して検証し、その後に検証済みの値をアプリケーションの型へマッピングしてください。
リクエスト制御を別々に型付けする
const requestOptions: RequestOptions = {
signal: request.signal,
};
const executeOptions: ExecuteOptions = {
signal: request.signal,
idempotencyKey: `operation:${operationId}`,
};すべてのリクエストメソッドは signal を受け付けます。idempotencyKey を追加するのはケイパビリティの実行だけです。adapter のディスパッチヘルパーは、返されるまたはバインドされる実行関数が型付きであっても、ExecuteOptions を受け付けません。
adapter でファクトリの戻り値の型を保持する
ファクトリ adapter はジェネリックであり、注入されたファクトリが作成したものを返します:
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,
});この例は adapter の構造的契約のみを使用しています。実際のフレームワークのファクトリを、アプリケーションがインストールしたバージョンに対してテストしてください。
