0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

たった3行でAIエージェントを管理できる!Coding Agent Viewer SDKで開発が10倍速になった話

Last updated at Posted at 2025-10-16

はじめに

AIコーディングエージェント、使ってますか?

Claude Code、Codex、Cursor、Gemini...様々なAIエージェントツールが登場してるけど、こんな悩みを抱えてませんか。

筆者も最初、複数のAIエージェントを手動で切り替えるのが面倒すぎて、なんとかならないかと思ってました。

  • 複数のAIエージェントを切り替えて使いたいが、それぞれUIが違って面倒
  • 実行ログを一元管理したい
  • AIエージェントの実行を自分のアプリケーションに組み込みたいけど、どうすればいいかわからない
  • CI/CDパイプラインにAIエージェント組み込みたい

そんな悩みを解決するのが、今回紹介する Coding Agent Viewer SDK です。

スクリーンショット 2025-10-16 16.44.43.png

この記事では実際のコードを見ながら、SDKを使うといかに簡単にAIエージェントを操作できるかをステップバイステップで解説します。初心者の方でも実装できるよう丁寧に説明していくので、ぜひ最後まで読んでください。

Coding Agent Viewer SDKとは

Coding Agent Viewerは、複数のAIコーディングエージェントを統合管理するためのSDKとツールセットです。

主な特徴

マルチエージェント対応で、Claude Code、Codex、OpenCode、Cursor、Geminiなど複数のAIエージェントを統一APIで操作できます。

3つのコアモジュールがあります:

  • Execution Module: AIエージェントの実行管理
  • Log Module: セッションログの収集・正規化
  • API Module: REST API + SSE(Server-Sent Events)

用途に応じて4つの利用レベルで使い分けられます:

レベル 説明 用途
Level 1: Library SDKを直接インポート CLIツール、バッチ処理、組み込み
Level 2: API RESTful API + SSE カスタムフロント、マイクロサービス
Level 3: Full-stack 完成されたWebアプリ そのまま利用、カスタマイズ
Level 4: Custom Web Chat WebチャットUIサンプル 既存SaaSへの組み込み・PoC

ちなみに、筆者が個人的に好んで使っているのはLevel 1の方式です。SDKを直接使う方が最も柔軟で強力だと感じてる。

なぜこのSDKが必要なのか

通常、AIエージェントを自分のアプリケーションに組み込もうとすると、以下のような課題があります。

  1. 各エージェントの起動方法がバラバラ - コマンドライン引数や環境変数の設定が異なる
  2. ログ形式の違い - それぞれ独自のログ形式を持っており、統一的な処理が困難
  3. プロセス管理の複雑さ - 子プロセスの起動・監視・停止を適切に行う必要
  4. リアルタイム性 - ログをリアルタイムで取得・表示したい

Coding Agent Viewer SDKは、これらの課題をすべて解決してくれます。

余談だが、このSDKの開発中、LogSourceFactoryの命名については散々悩んだ。FactoryパターンかStrategyパターンか...実装的にはStrategy Patternに近いんだが、まあ、どっちでもいいと思う。本題に戻ると、SDKの使い方は驚くほど簡単です。

実際に使ってみよう - Level 1(ライブラリとして直接利用)

実際のコードを見ながら、SDKの使い方を学んでいきましょう。

インストール

まずはnpmでSDKをインストールします。

npm install @nogataka/coding-agent-viewer-sdk

たったこれだけで準備完了です。依存関係も自動的に解決されます。

基本的な使い方

1. プロジェクト一覧を取得する

まずは、AIエージェントで管理されているプロジェクトの一覧を取得してみます。

import { LogSourceFactory } from '@nogataka/coding-agent-viewer-sdk/services/logs';

// LogSourceFactoryのインスタンスを作成
const factory = new LogSourceFactory();

// Claude Codeのプロジェクト一覧を取得
// 最初これ書いたときエラーハンドリング忘れてた
const projects = await factory.getAllProjects('CLAUDE_CODE');

// プロジェクト情報を表示
projects.forEach(project => {
  console.log(`プロジェクト名: ${project.name}`);
  console.log(`ID: ${project.id}`);
  console.log(`作成日: ${project.created_at}`);
  console.log(`更新日: ${project.updated_at}`);
  console.log('---');
});

LogSourceFactoryは、各AIエージェントのログを統一的に扱うためのファクトリークラスです。getAllProjects()メソッドに、取得したいエージェントのタイプ(CLAUDE_CODECURSORGEMINIなど)を指定するだけで、そのエージェントで管理されているプロジェクトの一覧が取得できます。

実装の詳細はlogSourceStrategy.tsを見てもらえればわかりますが、各エージェントごとにStrategy Patternで実装を切り替えてる。

引数を省略すれば、全エージェントのプロジェクトを一度に取得することも可能です。

// 全エージェントのプロジェクトを取得
const allProjects = await factory.getAllProjects();

2. セッション一覧を取得する

次に、特定のプロジェクトのセッション(実行履歴)を取得してみましょう。

// プロジェクトIDを指定してセッション一覧を取得
const sessions = await factory.getSessionsForProject(project.id);

// セッション情報を表示
sessions.forEach(session => {
  console.log(`タイトル: ${session.title}`);
  console.log(`ステータス: ${session.status}`); // running, completed, failed
  console.log(`作成日時: ${session.createdAt}`);
  console.log(`更新日時: ${session.updatedAt}`);
  console.log('---');
});

getSessionsForProject()メソッドで、指定したプロジェクトの全セッションを取得できます。各セッションには、タイトル、ステータス(実行中、完了、失敗)、日時などの情報が含まれています。

過去にどんな作業をAIエージェントに依頼したかを一覧で確認できるので便利です。

3. AIエージェントを実行する

いよいよ、AIエージェントを実際に実行してみます。これが驚くほど簡単です。

import { ExecutionService } from '@nogataka/coding-agent-viewer-sdk/services/execution';

// ExecutionServiceのインスタンスを作成
const executor = new ExecutionService();

// 新しいチャットセッションを開始
const result = await executor.startNewChat({
  profileLabel: 'claude-code',           // 使用するエージェント
  workspacePath: '/path/to/your/project', // 作業ディレクトリ
  prompt: 'READMEファイルを作成してください' // AIへの指示
});

console.log('セッションID:', result.sessionId);
console.log('プロセスID:', result.processId);
console.log('開始時刻:', result.startedAt);

ExecutionServiceは、AIエージェントの実行を管理するクラスです。startNewChat()メソッドで新しいチャットセッションを開始します。

必要なパラメータは以下の3つだけです:

  • profileLabel - 使用するAIエージェント(claude-codecursorgeminiなど)
  • workspacePath - AIエージェントが作業するディレクトリのパス
  • prompt - AIエージェントへの指示内容

実行結果には、セッションID、プロセスID、開始時刻が含まれます。

4. ログをリアルタイムで取得する

実行中のAIエージェントのログをリアルタイムで取得してみましょう。

// セッションIDからログストリームを取得
const stream = await factory.getSessionStream(result.sessionId);

// ストリームからデータを読み取る
stream.on('data', (chunk) => {
  const text = chunk.toString();
  console.log('ログ:', text);
});

stream.on('end', () => {
  console.log('ログストリーム終了');
});

stream.on('error', (error) => {
  console.error('エラー:', error.message);
});

getSessionStream()メソッドで、指定したセッションのログストリームを取得できます。Node.jsの標準的なReadableストリームとして返されるため、on('data')でデータを受信できます。

リアルタイムでログが流れてくるので、AIエージェントが今何をしているかを即座に確認可能です。

完全な実装例 - インタラクティブCLI

ここまでの知識を組み合わせて、実際に動くインタラクティブCLIを作ってみます。

以下は、SDKのサンプルディレクトリに含まれているsimple-cli.jsの簡略版です。

import { LogSourceFactory } from '@nogataka/coding-agent-viewer-sdk/services/logs';
import { ExecutionService, getProfiles } from '@nogataka/coding-agent-viewer-sdk/services/execution';
import inquirer from 'inquirer';
import chalk from 'chalk';
import ora from 'ora';

class AgentCLI {
  constructor() {
    // ファクトリーとサービスのインスタンスを作成
    this.factory = new LogSourceFactory();
    this.executor = new ExecutionService();

    // 利用可能なプロファイル(エージェント)を取得
    this.profileCatalog = getProfiles().map((definition) => ({
      label: definition.label,
      displayName: definition.label.split('-').map(s =>
        s.charAt(0).toUpperCase() + s.slice(1)
      ).join(' '),
      variants: definition.variants?.map(v => v.label) ?? []
    }));
  }

  async start() {
    console.clear();
    console.log(chalk.blue.bold('\n🤖 Coding Agent Viewer CLI\n'));

    // メインメニューを表示
    const { action } = await inquirer.prompt([
      {
        type: 'list',
        name: 'action',
        message: '何を行いますか?',
        choices: [
          { name: '📂 プロジェクトをブラウズ', value: 'browse' },
          { name: '🚀 新しいセッションを開始', value: 'execute' },
          { name: '❌ 終了', value: 'exit' }
        ]
      }
    ]);

    switch (action) {
      case 'browse':
        await this.browseProjects();
        break;
      case 'execute':
        await this.quickExecute();
        break;
      case 'exit':
        console.log(chalk.blue('\n👋 さようなら!\n'));
        process.exit(0);
    }
  }

  async browseProjects() {
    // エージェントを選択
    const profileChoices = this.profileCatalog.map(profile => ({
      name: `${profile.displayName}`,
      value: profile
    }));

    const { selectedProfile } = await inquirer.prompt([
      {
        type: 'list',
        name: 'selectedProfile',
        message: 'エージェントを選択',
        choices: profileChoices
      }
    ]);

    // プロジェクト一覧を取得
    const spinner = ora(`${selectedProfile.displayName}のプロジェクトを読み込み中...`).start();
    const projects = await this.factory.getAllProjects(
      selectedProfile.label.toUpperCase().replace(/-/g, '_')
    );
    spinner.stop();

    if (projects.length === 0) {
      console.log(chalk.yellow(`\n⚠️  プロジェクトが見つからなかった`));
      return this.start();
    }

    console.log(chalk.green(`\n${projects.length}件のプロジェクトが見つかった\n`));
    projects.forEach((p, i) => {
      console.log(`${i + 1}. ${chalk.bold(p.name)}`);
      console.log(`   更新日: ${new Date(p.updated_at).toLocaleString()}`);
    });

    console.log();
    await this.start();
  }

  async quickExecute() {
    // エージェントを選択
    const { profile } = await inquirer.prompt([
      {
        type: 'list',
        name: 'profile',
        message: 'エージェントを選択',
        choices: this.profileCatalog.map(p => ({
          name: p.displayName,
          value: p
        }))
      }
    ]);

    // ワークスペースパスを入力
    const { workspace } = await inquirer.prompt([
      {
        type: 'input',
        name: 'workspace',
        message: 'ワークスペースパス',
        default: process.cwd()
      }
    ]);

    // プロンプトを入力
    const { prompt } = await inquirer.prompt([
      {
        type: 'input',
        name: 'prompt',
        message: 'AIへの指示を入力',
        validate: (input) => input.trim().length > 0 || 'プロンプトを入力してください'
      }
    ]);

    // 実行
    const spinner = ora('実行中...').start();

    try {
      const result = await this.executor.startNewChat({
        profileLabel: profile.label,
        executorType: profile.label.toUpperCase().replace(/-/g, '_'),
        projectId: `${profile.label.toUpperCase().replace(/-/g, '_')}:${Buffer.from(workspace).toString('base64url')}`,
        actualProjectId: Buffer.from(workspace).toString('base64url'),
        workspacePath: workspace,
        prompt
      });

      spinner.succeed('実行開始!');
      console.log(chalk.green(`\n   セッションID: ${result.sessionId}`));
      console.log(chalk.gray(`   プロセスID: ${result.processId}`));
      console.log();

      await this.start();

    } catch (error) {
      spinner.fail('実行失敗');
      console.error(chalk.red(`   ${error.message}`));
      await this.start();
    }
  }
}

// CLIを起動
const cli = new AgentCLI();
cli.start().catch(error => {
  console.error(chalk.red(`\n❌ エラー: ${error.message}\n`));
  process.exit(1);
});

このCLIでできること:

  1. プロジェクトのブラウズ - 各AIエージェントで管理されているプロジェクトを一覧表示
  2. 新規セッションの開始 - 対話形式で簡単にAIエージェントを実行
  3. エラーハンドリング - エラーが発生しても適切にユーザーに通知

実装のポイントは以下です:

  • inquirerを使用することで、ユーザーフレンドリーな対話型UIを実現
  • oraでスピナーを表示し、処理中であることを視覚的にフィードバック
  • chalkで色付きテキストを使用し、見やすいUIを提供

筆者はこのCLIツールを毎日使っていて、複数プロジェクトでのAIエージェント管理が劇的に楽になった。特にinquirerによるインタラクティブな選択UIが気に入ってる。

さらに高度な使い方

フォローアップメッセージの送信

すでに実行中のセッションに、追加の指示を送ることもできます。

// フォローアップメッセージを送信
const followUpResult = await executor.sendFollowUp({
  profileLabel: 'claude-code',
  sessionId: 'CLAUDE_CODE:...:uuid',  // 既存のセッションID
  workspacePath: '/path/to/your/project',
  message: 'テストも追加してください'
});

console.log('フォローアップ送信完了:', followUpResult.sessionId);

sendFollowUp()メソッドで、既存のセッションに追加の指示を送れます。セッションIDを指定することで、同じコンテキストで会話を続けられます。

ただし、CursorとGeminiのサポートはまだ開発途中で、フォローアップメッセージの挙動が不安定な部分がある。本番環境での使用は様子を見たほうが良いです。

実行中のプロセスを停止する

実行中のAIエージェントを停止することも簡単です。

// セッションを停止
const stopped = executor.stopExecution(sessionId);

if (stopped) {
  console.log('セッションを停止した');
} else {
  console.log('セッションが見つからないか、すでに停止している');
}

stopExecution()メソッドで、実行中のセッションを停止できます。返り値はbooleanで、停止に成功したかどうかがわかります。

バリアント(実行モード)の指定

一部のエージェント(例:Claude Code)では、実行モードを指定できます。

// プランモードで実行
const result = await executor.startNewChat({
  profileLabel: 'claude-code',
  variantLabel: 'plan',  // planモードを指定
  workspacePath: '/path/to/your/project',
  prompt: 'アーキテクチャを計画してください'
});

variantLabelパラメータで、実行モードを指定できます。Claude Codeの場合、planモードでは実装前の計画フェーズに特化した動作をします。Level 4のカスタムWebチャットでこの機能を試してみたいと思ってるけど、まだ試してない。

Level 2 - APIサーバーとして使う

SDKは、REST APIサーバーとしても利用できます。これにより、フロントエンドアプリケーションや他のサービスから簡単にAIエージェントを操作できます。

サーバーのセットアップ

import express from 'express';
import { setupRoutes } from '@nogataka/coding-agent-viewer-sdk/server/routes';

const app = express();
app.use(express.json());

// ルートをセットアップ
setupRoutes(app);

// サーバー起動
const PORT = 3001;
app.listen(PORT, () => {
  console.log(`サーバーが起動しました: http://localhost:${PORT}`);
});

setupRoutes()関数を呼ぶだけで、必要なAPIエンドポイントが全て設定されます。Express以外のフレームワークでも使用可能です。

提供されるAPIエンドポイント

セットアップするだけで、以下のAPIエンドポイントが利用可能になります。

エンドポイント メソッド 説明
/api/projects GET プロジェクト一覧を取得
/api/tasks?project_id=<id> GET セッション一覧を取得
/api/task-attempts POST AIエージェントを実行
/api/execution-processes/:id/normalized-logs GET ログをSSEでストリーミング

詳細なAPIスキーマはroutes.tsの実装を見てもらえれば、全体像がつかめると思う。

フロントエンドからの利用例

// プロジェクト一覧を取得
const response = await fetch('http://localhost:3001/api/projects');
const projects = await response.json();

// AIエージェントを実行
const executeResponse = await fetch('http://localhost:3001/api/task-attempts', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    projectId: 'CLAUDE_CODE:...',
    prompt: 'READMEを作成してください',
    profileLabel: 'claude-code'
  })
});
const result = await executeResponse.json();

// SSEでログをリアルタイム取得
const eventSource = new EventSource(
  `http://localhost:3001/api/execution-processes/${result.sessionId}/normalized-logs`
);

eventSource.addEventListener('json_patch', (event) => {
  const patches = JSON.parse(event.data);
  console.log('ログ更新:', patches);
});

REST APIなので、React、Vue、Angularなど、どのフロントエンドフレームワークからも利用可能です。Server-Sent Events(SSE)により、ログのリアルタイム更新ができます。モバイルアプリ(React Native、Flutter)からも利用できます。

Level 3 & 4 - すぐに使えるアプリケーション

SDKには、すぐに使える完成されたアプリケーションも付属しています。

Level 3: フルスタックアプリ

# npx経由で即起動
npx @nogataka/coding-agent-viewer

# または、リポジトリをクローンして起動
git clone https://github.com/nogataka/coding-agent-viewer
cd coding-agent-viewer
npm run install:all
npm run dev

ブラウザでhttp://localhost:3000を開くと、以下の機能を持つWebアプリが利用できます。

  • 美しいReact製のUI
  • プロジェクト・セッション管理
  • リアルタイムログビューア
  • 複数エージェントのサポート

Level 4: カスタムWebチャット

既存のWebアプリケーションにAIエージェント機能を組み込みたい場合は、Level 4のサンプルが参考になります。

cd samples/level4-custom
pnpm install
pnpm dev

このサンプルは、REST APIとSSEを直接呼び出す最小構成のWebチャットUIです。自社のSaaSやPoCに組み込む際の参考実装として活用できます。

大規模プロジェクトでのパフォーマンスは、まだ詳しく計測できてないけど、そのうち試してみたい。

実践的なユースケース

1. CI/CDパイプラインでの自動コードレビュー

// GitHub Actionsなどから実行
import { ExecutionService } from '@nogataka/coding-agent-viewer-sdk/services/execution';

const executor = new ExecutionService();

// Pull Requestのコードレビューを自動実行
const result = await executor.startNewChat({
  profileLabel: 'claude-code',
  workspacePath: process.env.GITHUB_WORKSPACE,
  prompt: 'このPull Requestのコードをレビューして、改善点を指摘してください'
});

console.log(`レビューセッション開始: ${result.sessionId}`);

2. Slackボットとの連携

import { App } from '@slack/bolt';
import { ExecutionService } from '@nogataka/coding-agent-viewer-sdk/services/execution';

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET
});
const executor = new ExecutionService();

app.command('/ai-agent', async ({ command, ack, respond }) => {
  await ack();

  const result = await executor.startNewChat({
    profileLabel: 'claude-code',
    workspacePath: '/path/to/project',
    prompt: command.text
  });

  await respond(`AIエージェントを実行しました: ${result.sessionId}`);
});

app.start(3000);

3. VS Code拡張機能

import * as vscode from 'vscode';
import { ExecutionService } from '@nogataka/coding-agent-viewer-sdk/services/execution';

export function activate(context: vscode.ExtensionContext) {
  const executor = new ExecutionService();

  let disposable = vscode.commands.registerCommand('extension.runAIAgent', async () => {
    const prompt = await vscode.window.showInputBox({
      placeHolder: 'AIエージェントへの指示を入力'
    });

    if (prompt) {
      const workspacePath = vscode.workspace.workspaceFolders?.[0].uri.fsPath;

      const result = await executor.startNewChat({
        profileLabel: 'claude-code',
        workspacePath: workspacePath!,
        prompt
      });

      vscode.window.showInformationMessage(`実行開始: ${result.sessionId}`);
    }
  });

  context.subscriptions.push(disposable);
}

パフォーマンスとベストプラクティス

メモリ管理

// ログストリームは使用後に必ずクリーンアップ
const stream = await factory.getSessionStream(sessionId);

stream.on('data', handleData);
stream.on('end', () => {
  stream.destroy(); // リソースを解放
});

// エラー時も忘れずにクリーンアップ
stream.on('error', (error) => {
  console.error(error);
  stream.destroy();
});

ストリームのクリーンアップを忘れると、メモリリークの原因になります。筆者も最初これ忘れてて、長時間実行するとメモリが増え続ける問題に遭遇しました。

プロジェクトキャッシュの活用

class ProjectCache {
  constructor() {
    this.cache = new Map();
    this.factory = new LogSourceFactory();
  }

  async getProjects(executorType, forceRefresh = false) {
    if (!forceRefresh && this.cache.has(executorType)) {
      return this.cache.get(executorType);
    }

    const projects = await this.factory.getAllProjects(executorType);
    this.cache.set(executorType, projects);
    return projects;
  }

  clear() {
    this.cache.clear();
  }
}

エラーハンドリング

async function safeExecute(executor, request) {
  try {
    const result = await executor.startNewChat(request);
    return { success: true, data: result };
  } catch (error) {
    if (error.message.includes('Workspace path does not exist')) {
      return { success: false, error: 'ワークスペースパスが存在しない' };
    } else if (error.message.includes('Profile config not found')) {
      return { success: false, error: 'プロファイルが見つからない' };
    } else {
      return { success: false, error: '予期しないエラーが発生した' };
    }
  }
}

まとめ

Coding Agent Viewer SDKを使えば、複雑なAIエージェントの管理が驚くほど簡単になります。

この記事で学んだこと:

  1. たった3行でAIエージェントを実行できる
  2. プロジェクトやセッションの一覧を簡単に取得できる
  3. ログをリアルタイムでストリーミング取得できる
  4. REST APIサーバーとしても利用できる
  5. 完成されたWebアプリもすぐに使える

SDKの魅力は以下です:

  • 導入が簡単 - npm installだけで使える
  • 統一API - 複数のAIエージェントを同じ方法で操作
  • 柔軟な利用方法 - ライブラリ、API、完成アプリの3段階
  • 実用的なサンプル - すぐに動くコード例が豊富

次のステップ:

  1. GitHubリポジトリをチェック
  2. サンプルコードを試してみる
  3. 自分のプロジェクトに組み込んでみる

AIエージェントを使った開発体験を、ぜひこのSDKで向上させてほしい。筆者自身も日々このSDKを使ってて、開発効率が10倍どころじゃなく上がった気がします(10倍は言い過ぎかもしれないですが・・・)。


参考リンク

この記事が役に立てば幸いです。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?