mcpField
E
elevenlabs:sdk-migration

elevenlabs:sdk-migration

github.com/elevenlabs開発11899 回インストール2 日前に更新
リポジトリ

elevenlabs:sdk-migration について

ElevenLabs の client、React、React Native パッケージを次のメジャーバージョンへ移行する開発者向けスキルです。破壊的な API 変更と、任意のフック再構成を扱います。

主な機能

  1. 01段階的なパッケージ移行
  2. 02ConversationProvider の設定
  3. 03Conversation API の更新
  4. 04粒度の細かい会話フック
  5. 05React クライアントツールの登録

活用シーン

  1. 01アプリを次の SDK メジャーバージョンへ更新
  2. 02削除されたエクスポートの置き換えとインポート更新
  3. 03React の状態管理を細粒度フックへ再構成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/elevenlabs/packages --skill elevenlabs:sdk-migration

インストール後、Claude Code で/elevenlabs:sdk-migrationを入力して読み込まれたか確認します。

詳細

SDK 移行ガイド(次のメジャーバージョン)

次のメジャーリリースで予定されている @elevenlabs/client、@elevenlabs/react、@elevenlabs/react-native の破壊的変更に関する移行ガイドです。

移行の順序

以下の手順を順番に進めてください。各手順は前の手順を前提としています。

  1. インストール — 新しいパッケージをインストールします。
  2. インポートを修正 — 削除されたエクスポート(Input、Output、DeviceFormatConfig、DeviceInputConfig、ElevenLabsProvider)を削除し、後継に置き換えます。
  3. ConversationProvider でラップ — すべての useConversation 呼び出しで、祖先にプロバイダーが必要になりました。
  4. API 呼び出しを更新 — 変更されたシグネチャに対応します(React では startSession が同期処理に、Conversation はクラスではなくなるなど)。
  5. 粒度の細かいフックで最適化 (任意) — ローカル状態を useConversationStatus、useConversationMode などに置き換えることで、レンダリングパフォーマンスを向上させます。

インストール

npm install @elevenlabs/client@next @elevenlabs/react@next @elevenlabs/react-native@next

@elevenlabs/client

instanceof Conversation によるチェックを置き換える

Conversation はプレーンな名前空間オブジェクトとなり、TextConversation | VoiceConversation の型エイリアスになりました。これによりツリーシェイキングが可能になり、内部アーキテクチャがシンプルになります。instanceof Conversation はコンパイルできなくなり、サブクラス化もできません。

代わりに、ダックタイピングで型を絞り込みます。

変更前:

import { Conversation } from "@elevenlabs/client";

if (session instanceof Conversation) {
  /* ... */
}
class MyConversation extends Conversation {
  /* ... */
}

変更後:

import { Conversation } from "@elevenlabs/client";

// startSession call is unchanged
const session: Conversation = await Conversation.startSession(options);

// Narrow using duck-typing instead of instanceof
if ("changeInputDevice" in session) {
  // session is VoiceConversation
}
Input と Output の使用を会話メソッドに置き換える

Input クラスと Output クラスは、内部のオーディオノードへ直接アクセスすることで実装の詳細との結合が強くなるため、エクスポートされなくなりました。VoiceConversation の input フィールドと output フィールドは、非公開になりました。すべてのオーディオ操作は、会話インスタンス自体のメソッドになりました。

変更前:

import { Input, Output } from "@elevenlabs/client";

const input: Input = conversation.input;
input.analyser.getByteFrequencyData(data);
input.setMuted(true);

const output: Output = conversation.output;
output.gain.gain.value = 0.5;
output.analyser.getByteFrequencyData(data);

const newInput: Input = await conversation.changeInputDevice(config);

変更後:

conversation.getInputByteFrequencyData(); // replaces input.analyser.getByteFrequencyData
conversation.setMicMuted(true); // replaces input.setMuted
conversation.setVolume({ volume: 0.5 }); // replaces output.gain.gain.value
conversation.getOutputByteFrequencyData(); // replaces output.analyser.getByteFrequencyData

await conversation.changeInputDevice(config); // return value dropped
await conversation.changeOutputDevice(config); // return value dropped
wakeLock への直接アクセスを削除する

誤った干渉を防ぐため、wake lock のライフサイクルは自動的に管理されるようになり、wakeLock フィールドは非公開になりました。無効にするには useWakeLock: false を指定します。

const conversation = await Conversation.startSession({
  // ...
  useWakeLock: false,
});

@elevenlabs/react

useConversation を ConversationProvider でラップする

useConversation では、祖先に ConversationProvider が必要になりました。プロバイダーは、複数のフックがそれぞれ独立して購読できる共有セッション状態を保持します。これにより、新しい粒度の細かいフックシステムと、より優れたレンダリングパフォーマンスが実現します。

このフックは以前と同じオプションを受け取り、同じ形の値を返します。また、新しいフィールドとして isMuted、setMuted、isListening、mode、message が追加されています。

複数のコンポーネントで useConversation を使用しているコードベースを移行する場合は、次のどちらを希望するかユーザーに確認してください。

  1. すべての会話コンポーネントをツリー上位の単一の ConversationProvider でラップする(すべてのコンポーネントで1つのセッションを共有する)、または
  2. 各コンポーネントを個別の ConversationProvider でラップする(各コンポーネントが独立したセッションを管理する)。

この選択は、セッションの共有、状態の分離、コンポーネントのアーキテクチャに影響します。決めつけず、作業を進める前に確認してください。

変更前:

import { useConversation } from "@elevenlabs/react";

function App() {
  const { status, isSpeaking, startSession, endSession } = useConversation({
    agentId: "your-agent-id",
    onMessage: message => console.log(message),
    onError: error => console.error(error),
  });

  return (
    <div>
      <p>Status: {status}</p>
      <p>{isSpeaking ? "Agent is speaking" : "Agent is listening"}</p>
      <button onClick={() => startSession()}>Start</button>
      <button onClick={() => endSession()}>Stop</button>
    </div>
  );
}

変更後:

import { ConversationProvider, useConversation } from "@elevenlabs/react";

function App() {
  return (
    <ConversationProvider>
      <Conversation />
    </ConversationProvider>
  );
}

function Conversation() {
  const { status, isSpeaking, startSession, endSession } = useConversation({
    agentId: "your-agent-id",
    onMessage: message => console.log(message),
    onError: error => console.error(error),
  });

  return (
    <div>
      <p>Status: {status}</p>
      <p>{isSpeaking ? "Agent is speaking" : "Agent is listening"}</p>
      <button onClick={() => startSession()}>Start</button>
      <button onClick={() => endSession()}>Stop</button>
    </div>
  );
}
startSession から await を削除する

useConversation(React)を使用する場合、startSession は同期処理になり、void を返します。セッションのライフサイクルはプロバイダーが管理し、エラーは例外としてスローされるプロミスではなく、コールバックを通じて通知されます。

移行時には、次の対応を行います。

  • startSession() の呼び出しから await を削除します。
  • startSession() が関数内で唯一の await 対象だった場合は、関数から async キーワードを削除します。
  • 接続エラーへの対処として startSession() の前後を try/catch で囲んでいた場合は、エラー処理を onError コールバックまたは useConversationStatus フックに移します。同期呼び出しでは、セッションの失敗時に例外がスローされなくなりました。

変更前:

const startConversation = async () => {
  try {
    await conversation.startSession({ agentId: "..." });
  } catch (error) {
    console.error("Failed to start:", error);
    setStatus("disconnected");
  }
};

変更後:

// onError handles failures instead of try/catch
const conversation = useConversation({
  onError: (error) => {
    console.error("Failed to start:", error);
    setStatus("disconnected");
  },
});

const startConversation = () => {
  conversation.startSession({ agentId: "..." });
};
削除された型インポートを更新する
  • DeviceFormatConfig を @elevenlabs/client の FormatConfig に置き換えます。
  • DeviceInputConfig を @elevenlabs/client の InputDeviceConfig に置き換えます。
再エクスポートの変更

@elevenlabs/react は、従来の選択的な再エクスポートに代わり、export * を通じて @elevenlabs/client のすべてを再エクスポートするようになりました。

粒度の細かい会話フックを導入する(任意)

新しいフックは会話状態の独立した部分を購読するため、モードしか読み取らないコンポーネントはステータスが変化しても再レンダリングされません。これがConversationProviderアーキテクチャの主なメリットです。状態を共有することで、粒度の細かい購読が可能になります。

初回の移行がコンパイルできたら、コンポーネントがローカルの接続状態(例:agentState、isMuted、isSpeaking用のuseState)を保持していて、これらのフックが提供する状態と重複していないか確認してください。重複している場合は、ローカル状態を粒度の細かいフックに置き換えるかユーザーに尋ねてください。

  • useConversationStatus()は、onStatusChangeコールバックを介して管理されるローカルのagentState/status状態を置き換えます。
  • useConversationInput()は、手動の切り替えで管理されるローカルのisMuted状態を置き換えます。
  • useConversationMode()は、ローカルのisSpeaking/isListening状態を置き換えます。
  • useConversationControls()は、再レンダリングを引き起こさない安定したアクション参照(startSession、endSession、sendUserMessage、getInputVolume、getOutputVolumeなど)を提供します。

粒度の細かいフックにリファクタリングする場合:

  • コンポーネントのローカル状態へのアクセスが不要なイベントコールバック(onConnect、onDisconnect、onError、onMessage)は、ConversationProviderのpropsに移動します。
  • コンポーネントのローカル状態を参照するコールバック(例:ローカルのmessages配列を更新するもの)にはuseConversationを維持します。ただし、ステータス/モード/入力状態の読み取りには粒度の細かいフックを使用してください。
  • ステータスはuseConversationStatus()を介してリアクティブに取得できるため、startSessionのオプションからonStatusChangeを削除します。
フック戻り値
useConversationControls()安定したアクションメソッド:startSession、endSession、sendUserMessage、setVolume、changeInputDevice、changeOutputDeviceなど。再レンダリングを引き起こしません。
useConversationStatus()status("disconnected"/"connecting"/"connected"/"error")と省略可能なmessage。
useConversationInput()isMuted状態とsetMutedアクション。
useConversationMode()mode("speaking"/"listening")、isSpeaking、isListening。
useConversationFeedback()canSendFeedback状態とsendFeedback(like: boolean)アクション。
useRawConversation()生のConversationインスタンス、またはnull(エスケープハッチ)。

すべてのフックには、祖先としてConversationProviderが必要です。

useConversationからの対応関係:

useConversationの戻り値粒度の細かいフック
status、messageuseConversationStatus()
isSpeaking、isListening、modeuseConversationMode()
canSendFeedback、sendFeedbackuseConversationFeedback()
isMuted、setMuteduseConversationInput()
startSession、endSession、setVolume、...useConversationControls()

例 — 各コンポーネントは、特定の状態が変化したときにのみ再レンダリングされます:

import {
  ConversationProvider,
  useConversationStatus,
  useConversationMode,
  useConversationControls,
  useConversationInput,
  useConversationFeedback,
} from "@elevenlabs/react";

function App() {
  return (
    <ConversationProvider agentId="your-agent-id">
      <StatusBadge />
      <Controls />
      <MuteButton />
      <FeedbackButtons />
      <ModeIndicator />
    </ConversationProvider>
  );
}

/** Only re-renders when status changes. */
function StatusBadge() {
  const { status } = useConversationStatus();
  return <span className={`badge badge-${status}`}>{status}</span>;
}

/** Never re-renders — controls are stable references. */
function Controls() {
  const { startSession, endSession } = useConversationControls();
  return (
    <div>
      <button onClick={() => startSession()}>Start</button>
      <button onClick={() => endSession()}>Stop</button>
    </div>
  );
}

/** Only re-renders when mute state changes. */
function MuteButton() {
  const { isMuted, setMuted } = useConversationInput();
  return (
    <button onClick={() => setMuted(!isMuted)}>
      {isMuted ? "Unmute" : "Mute"}
    </button>
  );
}

/** Only re-renders when feedback availability changes. */
function FeedbackButtons() {
  const { canSendFeedback, sendFeedback } = useConversationFeedback();
  if (!canSendFeedback) return null;
  return (
    <div>
      <button onClick={() => sendFeedback(true)}>👍</button>
      <button onClick={() => sendFeedback(false)}>👎</button>
    </div>
  );
}

/** Only re-renders when mode changes. */
function ModeIndicator() {
  const { isSpeaking, isListening } = useConversationMode();
  return (
    <p>
      {isSpeaking ? "Agent is speaking..." : isListening ? "Listening..." : ""}
    </p>
  );
}
useConversationClientToolでクライアントツールを登録する

React コンポーネントからクライアントツールを動的に登録する新しいフックです。セッション開始後に追加または削除したツールは、すぐに表示されます。ツール名が重複している場合はエラーが発生します。

import { useConversationClientTool } from "@elevenlabs/react";

// Untyped — parameters are Record<string, unknown>
useConversationClientTool("get_weather", params => {
  const city = params["city"];
  return `Weather in ${city} is sunny.`;
});

// Type-safe — tool names are constrained, params and return types are inferred
type Tools = {
  get_weather: (params: { city: string }) => string;
  set_volume: (params: { level: number }) => void;
};

useConversationClientTool<Tools>("get_weather", params => {
  return `Weather in ${params.city} is sunny.`;
});

@elevenlabs/react-native

ElevenLabsProviderをConversationProviderに置き換える

LiveKit ベースのカスタム実装(ElevenLabsProvider、useConversation)は完全に削除されました。このパッケージは@elevenlabs/reactから再エクスポートするようになり、ConversationProviderと同じ細分化されたフックを使用して、Web とモバイルの API が統一されます。

React Native では、パッケージのインポート時に副作用が実行されます。WebRTC グローバルのポリフィル、ネイティブの AudioSession の設定、プラットフォーム固有の音声セッション戦略の登録が行われます。Web では、副作用なしで再エクスポートされます。

変更前:

import { ElevenLabsProvider, useConversation } from "@elevenlabs/react-native";

function App() {
  return (
    <ElevenLabsProvider>
      <Conversation />
    </ElevenLabsProvider>
  );
}

function Conversation() {
  const conversation = useConversation({
    onConnect: ({ conversationId }) => console.log("Connected", conversationId),
    onError: message => console.error(message),
  });

  return (
    <Button
      onPress={() => conversation.startSession({ agentId: "your-agent-id" })}
    />
  );
}

変更後:

import {
  ConversationProvider,
  useConversationControls,
  useConversationStatus,
} from "@elevenlabs/react-native";

function App() {
  return (
    <ConversationProvider
      onConnect={({ conversationId }) =>
        console.log("Connected", conversationId)
      }
      onError={message => console.error(message)}
    >
      <Conversation />
    </ConversationProvider>
  );
}

function Conversation() {
  const { startSession } = useConversationControls();
  const { status } = useConversationStatus();

  return <Button onPress={() => startSession({ agentId: "your-agent-id" })} />;
}

コメント