본문으로 건너뛰기
cccskills
무료GitHub에 공개

kb-frontend-sse

SSEストリーミング処理のナレッジ。基本パターン/タイムアウト/リトライ/モック/PDF生成等

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md6.8 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

SSEストリーミング処理

SSE(Server-Sent Events)を使ったフロントエンドのストリーミング処理パターンを記録する。

基本パターン

const reader = response.body?.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split('\n');
  buffer = lines.pop() || '';  // 不完全な行は次回に持ち越し

  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = line.slice(6);
      if (data === '[DONE]') return;
      try {
        const event = JSON.parse(data);
        handleEvent(event);
      } catch {
        // JSONパースエラーは無視
      }
    }
  }
}

イベントハンドリング

function handleEvent(event) {
  // APIによってcontent/dataのどちらかにペイロードが入る
  const textValue = event.content || event.data;

  switch (event.type) {
    case 'text':
      onText(textValue);
      break;
    case 'tool_use':
      onToolUse(textValue);  // ツール名が返る
      break;
    case 'markdown':
      onMarkdown(textValue);
      break;
    case 'error':
      onError(new Error(event.error || event.message || textValue));
      break;
  }
}

エラーハンドリング

// ストリーミング中のエラー
case 'error':
  if (event.error || event.message) {
    callbacks.onError(new Error(event.error || event.message));
  }
  break;

// HTTPエラー
const response = await fetch(url, options);
if (!response.ok) {
  throw new Error(`API Error: ${response.status} ${response.statusText}`);
}

アイドルタイムアウト(2段構成)

SSEストリームに2段階のタイムアウトを設定し、接続障害と推論ハングの両方を検知するパターン:

async function readSSEStream(
  reader: ReadableStreamDefaultReader<Uint8Array>,
  onEvent: (event: Record<string, unknown>) => void,
  idleTimeoutMs?: number,          // 初回イベント受信前(短め: 10秒)
  ongoingIdleTimeoutMs?: number    // イベント間(長め: 60秒)
): Promise<void> {
  let firstEventReceived = false;

  while (true) {
    // フェーズに応じてタイムアウト値を切り替え
    const currentTimeout = firstEventReceived ? ongoingIdleTimeoutMs : idleTimeoutMs;
    if (currentTimeout) {
      const timeoutPromise = new Promise<never>((_, reject) => {
        setTimeout(() => reject(new SSEIdleTimeoutError(currentTimeout)), currentTimeout);
      });
      readResult = await Promise.race([reader.read(), timeoutPromise]);
    } else {
      readResult = await reader.read();
    }
    // ... イベント処理後に firstEventReceived = true
  }
}
フェーズタイムアウト検知対象
初回イベント受信前短め(10秒)スロットリング、接続エラー
イベント間(初回受信後)長め(60秒)推論ハング、モデル無応答

設計ポイント:

  • 初回タイムアウトは短く → ユーザーを素早くエラーに気づかせる
  • イベント間タイムアウトは長めに → 正常な推論やツール実行を妨げない

モック実装(ローカル開発用)

※ モックは既定ではない。実物のバックエンドへつないで作る実装ファーストが原則で、これは AWS 認証が無い環境で UI だけ確認する等の限定用途。

export async function invokeAgentMock(prompt, callbacks) {
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

  const thinkingText = `${prompt}について考えています...`;
  for (const char of thinkingText) {
    callbacks.onText(char);
    await sleep(20);
  }

  callbacks.onStatus('生成中...');
  await sleep(1000);

  callbacks.onMarkdown('# 生成結果\n\n...');
  callbacks.onComplete();
}

// 環境変数で切り替え
const useMock = import.meta.env.VITE_USE_MOCK === 'true';
const invoke = useMock ? invokeAgentMock : invokeAgent;

エクスポートのリトライパターン(ネットワーク耐性)

SSE経由のファイルエクスポート(PDF/PPTX等)は、不安定なネットワークでストリームが切断されることがある:

export async function exportSlide(
  markdown: string,
  format: ExportFormat,
  theme: string = 'border'
): Promise<Blob> {
  const MAX_RETRIES = 1;
  let lastError: Error | null = null;

  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
    try {
      return await _exportSlideOnce(markdown, format, theme);
    } catch (e) {
      lastError = e as Error;
      if (attempt < MAX_RETRIES) {
        console.warn(`Export failed (attempt ${attempt + 1}), retrying...`, e);
        await new Promise(r => setTimeout(r, 1000));
      }
    }
  }
  throw lastError!;
}

ポイント:

  • SSE reader.read() が done: true を返しても resultBlob が null = ストリーム切断
  • リトライは1回(計2回)で十分
  • バックエンド側のkeep-alive(5秒ごとの progress イベント)と組み合わせるとさらに効果的

PDF生成(Base64デコード・ダウンロード)

export async function exportPdf(markdown: string): Promise<Blob> {
  const response = await fetch(url, {
    method: 'POST',
    headers: { /* 認証ヘッダー等 */ },
    body: JSON.stringify({ action: 'export_pdf', markdown }),
  });

  const reader = response.body?.getReader();
  const decoder = new TextDecoder();
  let buffer = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop() || '';

    for (const line of lines) {
      if (line.startsWith('data: ')) {
        const event = JSON.parse(line.slice(6));
        if (event.type === 'pdf' && event.data) {
          const binaryString = atob(event.data);
          const bytes = new Uint8Array(binaryString.length);
          for (let i = 0; i < binaryString.length; i++) {
            bytes[i] = binaryString.charCodeAt(i);
          }
          return new Blob([bytes], { type: 'application/pdf' });
        }
      }
    }
  }
  throw new Error('PDF生成に失敗しました');
}

// ダウンロード処理
const blob = await exportPdf(markdown);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'slide.pdf';
a.click();
URL.revokeObjectURL(url);

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Deploy, diff, bootstrap, inspect, roll back, or destroy AWS CDK applications with the community CDKD CLI while preserving safe production and state-management boundaries. Use when the user mentions cdkd or CDK Direct, asks for faster CDK deployments in development or test environments, or wants to evaluate whether an existing CDK app can use CDKD. Also use for CDKD import, export, state, events, and deployment troubleshooting. Prefer the upstream AWS CDK CLI for production and for existing CloudFormation-managed stacks unless the user explicitly approves a management migration.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

minorun365/agent-builder-skills412026년 10월 14일 업데이트

AIエージェントのWebアプリを「AWS CDK(デプロイはCDKD)+ S3 + CloudFront + AgentCore Runtime」で組むときの全体構成。画面は S3 から静的に配信し、サーバー側の処理が要るときだけ Lambda Web Adapter(または Lambda Web Functions)を足す判断基準。スタックの分け方、BucketDeployment での配置とキャッシュ指定、SPA の振り分け、runtime-config.json で環境値を渡す型、Lambda を足すときの Function URL と CloudFront OAC の権限、フロントから AgentCore を直接呼ぶ配線、ローカル開発、デプロイ前後の検証。新しくエージェントのWebアプリを作るとき、Amplify Hosting 以外の配信基盤を選ぶとき、画面の配信に Lambda が要るか迷ったとき、CloudFront 経由の Function URL が 403 になるときに読む。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

minorun365/agent-builder-skills412026년 10월 14일 업데이트

AgentCore CDK・デプロイ・ランタイム統合のナレッジ。Runtime作成、JWT認証、SSE、Dockerfile、コンテナ管理、Browser Tool等

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

minorun365/agent-builder-skills412026년 10월 14일 업데이트

AgentCore Identity(アウトバウンド認証)のナレッジ。3LO/M2M/デコレータ分離/callback等

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

minorun365/agent-builder-skills412026년 10월 14일 업데이트

AgentCore の Observability ナレッジ。OpenTelemetry 必須4点セット(OTEL_EXPORTER設定・StrandsTelemetry・traceable デコレータ・Langfuse連携)、EMF メトリクス、Jaeger/コンソールエクスポーターでのトレース確認、トレースが出ない・繋がらない場合のデバッグ手順等

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

minorun365/agent-builder-skills412026년 10월 14일 업데이트

デモアプリ・Webアプリの Cognito 認証のおすすめ構成。「Googleで続ける」か「メール+パスキー(パスワードも併用可)」の2経路をCDKとフロントでどう組むか、パスキーが動かない設定の罠、Google client secret の置き場、ログイン画面のUX規約、Googleの同意画面に出るアプリ名の扱い。新しくデモアプリを作るとき、既存アプリの認証を作り直すとき、パスキーやGoogleログインが動かないときに読む。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

minorun365/agent-builder-skills412026년 10월 14일 업데이트

minorun365의 스킬 모두 보기

이 스킬의 문제 신고