mcpField
T
threads

threads

github.com/tambo-ai開発11.2k103 回インストール3 週間前に更新
リポジトリ

threads について

Tambo Reactで会話インターフェースを構築するためのスキルです。スレッド状態、入力、提案、音声文字起こし、画像添付に加え、スレッド取得やユーザーごとの分離も扱います。

主な機能

  1. 01スレッドとストリーミング状態の参照
  2. 02メッセージ入力の送信と管理
  3. 03提案の生成と受け入れ
  4. 04音声入力の文字起こし
  5. 05画像の添付と管理
  6. 06スレッド取得と会話一覧

活用シーン

  1. 01ストリーミング状態を表示するチャット画面の構築
  2. 02ユーザーが次の提案を送信できる仕組みの追加
  3. 03会話への音声・画像入力の追加
  4. 04スレッド履歴や特定スレッドの表示

MCP 対応

メッセージ内のMCPリソースコンテンツブロックを説明します。MCPサーバーへの接続や管理については記載されていません。

インストール

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

$npx skills add https://github.com/tambo-ai/tambo --skill threads

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

詳細

スレッドと入力

会話、提案、音声入力、画像添付を管理します。

クイックスタート

import { useTambo, useTamboThreadInput } from "@tambo-ai/react";

const { thread, messages, isIdle } = useTambo();
const { value, setValue, submit } = useTamboThreadInput();

await submit(); // sends current input value

スレッド管理

useTambo() と useTamboThreadInput() を使って、現在のスレッドにアクセスし、管理します。

import {
  useTambo,
  useTamboThreadInput,
  ComponentRenderer,
} from "@tambo-ai/react";

function Chat() {
  const {
    thread, // Current thread state
    messages, // Messages with computed properties
    isIdle, // True when not generating
    isStreaming, // True when streaming response
    isWaiting, // True when waiting for server
    currentThreadId, // Active thread ID
    switchThread, // Switch to different thread
    startNewThread, // Create new thread, returns ID
    cancelRun, // Cancel active generation
  } = useTambo();

  const {
    value, // Current input value
    setValue, // Update input
    submit, // Send message
    isPending, // Submission in progress
    images, // Staged image files
    addImage, // Add single image
    removeImage, // Remove image by ID
  } = useTamboThreadInput();

  const handleSend = async () => {
    await submit();
  };

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          {msg.content.map((block) => {
            switch (block.type) {
              case "text":
                return <p key={`${msg.id}:text`}>{block.text}</p>;
              case "component":
                return (
                  <ComponentRenderer
                    key={block.id}
                    content={block}
                    threadId={currentThreadId}
                    messageId={msg.id}
                  />
                );
              case "tool_use":
                return (
                  <div key={block.id}>
                    {block.statusMessage ?? `Running ${block.name}...`}
                  </div>
                );
              default:
                return null;
            }
          })}
        </div>
      ))}
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <button onClick={handleSend} disabled={!isIdle || isPending}>
        Send
      </button>
    </div>
  );
}
ストリーミング状態
プロパティ型説明
isIdleboolean生成していません
isWaitingbooleanサーバーの応答を待っています
isStreamingboolean応答をストリーミング中です

streamingState オブジェクトで、詳細を確認できます。

const { streamingState } = useTambo();
// streamingState.status: "idle" | "waiting" | "streaming"
// streamingState.runId: current run ID
// streamingState.error: { message, code } if error occurred
コンテンツブロックの種類

メッセージには、コンテンツブロックの配列が含まれます。各種類を処理してください。

種類説明主なフィールド
textプレーンテキストtext
componentAI が生成したコンポーネントid、name、props
tool_useツールの呼び出しid、name、input
tool_resultツールの応答toolUseId、content
resourceMCP リソースuri、name、text
送信オプション
const { submit } = useTamboThreadInput();

await submit({
  toolChoice: "auto", // "auto" | "required" | "none" | { name: "toolName" }
  debug: true, // Enable debug logging for the stream
});

ID によるスレッドの取得

特定のスレッドを取得するには(詳細画面など)、useTamboThread(threadId) を使います。

import { useTamboThread } from "@tambo-ai/react";

function ThreadView({ threadId }: { threadId: string }) {
  const { data: thread, isLoading, isError } = useTamboThread(threadId);

  if (isLoading) return <Skeleton />;
  if (isError) return <div>Failed to load thread</div>;

  return <div>{thread.name}</div>;
}

これは React Query のフックです。有効な会話ではなく、読み取り専用のスレッド取得に使用してください。

スレッドリスト

複数の会話を管理します。

import { useTambo, useTamboThreadList } from "@tambo-ai/react";

function ThreadSidebar() {
  const { data, isLoading } = useTamboThreadList();
  const { currentThreadId, switchThread, startNewThread } = useTambo();

  if (isLoading) return <Skeleton />;

  return (
    <div>
      <button onClick={() => startNewThread()}>New Thread</button>
      <ul>
        {data?.threads.map((t) => (
          <li key={t.id}>
            <button
              onClick={() => switchThread(t.id)}
              className={currentThreadId === t.id ? "active" : ""}
            >
              {t.name || "Untitled"}
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}
スレッドリストのオプション
const { data } = useTamboThreadList({
  userKey: "user_123", // Filter by user (defaults to provider's userKey)
  limit: 20, // Max results
  cursor: nextCursor, // Pagination cursor
});

// data.threads: TamboThread[]
// data.hasMore: boolean
// data.nextCursor: string

提案

アシスタントの各メッセージの後に生成される、AI によるフォローアップの提案です。

import { useTamboSuggestions } from "@tambo-ai/react";

function Suggestions() {
  const { suggestions, isLoading, accept, isAccepting } = useTamboSuggestions({
    maxSuggestions: 3, // 1-10, default 3
    autoGenerate: true, // Auto-generate after assistant message
  });

  if (isLoading) return <Skeleton />;

  return (
    <div className="suggestions">
      {suggestions.map((s) => (
        <button
          key={s.id}
          onClick={() => accept({ suggestion: s })}
          disabled={isAccepting}
        >
          {s.title}
        </button>
      ))}
    </div>
  );
}
提案の自動送信
// Accept and immediately submit as a message
accept({ suggestion: s, shouldSubmit: true });
手動生成
const { generate, isGenerating } = useTamboSuggestions({
  autoGenerate: false, // Disable auto-generation
});

<button onClick={() => generate()} disabled={isGenerating}>
  Get suggestions
</button>;

音声入力

音声をテキストに変換します。

import { useTamboVoice } from "@tambo-ai/react";

function VoiceButton() {
  const {
    startRecording,
    stopRecording,
    isRecording,
    isTranscribing,
    transcript,
    transcriptionError,
    mediaAccessError,
  } = useTamboVoice();

  return (
    <div>
      <button onClick={isRecording ? stopRecording : startRecording}>
        {isRecording ? "Stop" : "Record"}
      </button>
      {isTranscribing && <span>Transcribing...</span>}
      {transcript && <p>{transcript}</p>}
      {transcriptionError && <p className="error">{transcriptionError}</p>}
    </div>
  );
}
音声フックの戻り値
プロパティ型説明
startRecording() => void録音を開始し、文字起こしをリセットします
stopRecording() => void録音を停止し、文字起こしを開始します
isRecordingboolean録音中かどうか
isTranscribingboolean音声を処理中かどうか
transcriptstring | null文字起こしされたテキスト
transcriptionErrorstring | null文字起こしエラー
mediaAccessErrorstring | nullマイクへのアクセスエラー

画像添付

画像は useTamboThreadInput() を使って管理します。

import { useTamboThreadInput } from "@tambo-ai/react";

function ImageInput() {
  const { images, addImage, addImages, removeImage, clearImages } =
    useTamboThreadInput();

  const handleFiles = async (files: FileList) => {
    await addImages(Array.from(files));
  };

  return (
    <div>
      <input
        type="file"
        accept="image/*"
        multiple
        onChange={(e) => handleFiles(e.target.files!)}
      />
      {images.map((img) => (
        <div key={img.id}>
          <img src={img.dataUrl} alt={img.name} />
          <button onClick={() => removeImage(img.id)}>Remove</button>
        </div>
      ))}
    </div>
  );
}
StagedImage のプロパティ
プロパティ型説明
idstring一意の画像 ID
namestringファイル名
dataUrlstringBase64 データ URL
fileFile元の File オブジェクト
sizenumberファイルサイズ(バイト)
typestringMIME タイプ

ユーザー認証

ユーザーごとにスレッドを分離できるようにします。

import { TamboProvider } from "@tambo-ai/react";

function App() {
  return (
    <TamboProvider
      apiKey={apiKey}
      userKey="user_123" // Simple user identifier
    >
      <Chat />
    </TamboProvider>
  );
}

OAuth ベースの認証では、代わりに userToken を使用してください。

function App() {
  const userToken = useUserToken(); // From your auth provider

  return (
    <TamboProvider apiKey={apiKey} userToken={userToken}>
      <Chat />
    </TamboProvider>
  );
}

シンプルなユーザー識別には userKey を、OAuth JWT トークンには userToken を使用してください。両方を同時に使用しないでください。

コメント