translate-agent-broker-old-to-new-project について
MuleSoft Agent Broker V1 の Agent Network プロジェクトを V2 に変換し、新しいプロジェクトフォルダーを作成するスキルです。元の指示文を保ち、各 V1 broker を単一のオーケストレーターノードを持つ Agent Script にします。
主な機能
- 01V1 プロジェクトファイルとスキーマの検証
- 02V2 agent-network.yaml の生成
- 03exchange.json と接続設定の変換
- 04broker ごとに単一ノードの Agent Script を作成
- 05元のオーケストレーションプロンプトを保持
活用シーン
- 01旧 Agent Network の V2 への移行
- 02V1 broker プロジェクトの V2 形式への変換
- 03変換後のファイルと構成の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mulesoft/ mulesoft-dx --skill translate-agent-broker-old-to-new-projectインストール後、Claude Code で/translate-agent-broker-old-to-new-projectを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/v1-example.mdv2-example.mdv2-template.agent詳細
MuleSoft Agent Broker V1 から V2 へのコンバーター
Agent Network V1 プロジェクト(スキーマ 1.0.0)を V2(スキーマ 2.0.0)に変換し、新しいプロジェクトフォルダーを作成します。変換は意図的にシンプルにしています。V1 のブローカーはすべて、オーケストレーターノードを 1 つだけ持つ Agent Script .agent ファイルを基盤とする V2 ブローカーになります。V1 では 1 つの LLM プロンプトに詰め込まれていたルーティング、分類、条件ロジックは、オーケストレーターの system.instructions 内に残ります。このアップグレードでは、プロンプトを複数のノードに分割しません。
ユーザーの表現をそのまま維持してください。元の指示を独自に解釈したり、「改善」したりしないでください。V1 ファイルを信頼できる情報源として扱い、V2 が実際に必要とする箇所だけを変更してください。
より高度な複数ノードのグラフ(決定論的なルーティングを router ノードに分割し、副作用を executor ノードに移し、低コストの要約処理を generator ノードに分離するなど)をユーザーが希望する場合は、次のステップとして自然な選択肢である build-agent-broker-project を案内してください。
使用する状況
- Agent Network または Agent Broker を V1 から V2 に変換/アップグレード/移行/移植する場合。
- ユーザーが
schemaVersion: 1.0.0に言及し、agentNetwork: 2.0.0を希望している場合。 - 作業フォルダーに V1 の
agent-network.yamlとexchange.jsonがある場合。
変換を伴わない一般的な V2 に関する質問では、代わりにビルダースキルを案内してください。
参照資料
references/v1-example.md— V1 の標準的な入力(customer-onboarding-v1)。references/v2-example.md— その入力に対する V2 の標準的な出力。書式に迷った場合は、これに合わせてください。references/v2-template.agent— Step 3c で入力するオーケストレーターテンプレート。
ワークフロー
- 入力を検証する — Step 1。
- 出力先を選択する — Step 2。
- ソースファイルをすべて読み込む — V1 の
agent-network.yamlとexchange.jsonを最初から最後まで読みます。 - 変換する — Step 3(サブステップ 3a/3b/3c)。
_v2_conversionのサフィックスを付けた出力フォルダーを書き込む — Step 4。- 新しいパスと変換内容を報告する — Step 5。
Step 1: 入力を検証する
作業フォルダーが実際に V1 の Agent Network プロジェクトであることを確認してください。間違ったフォルダーに対して変換を実行してはいけません。
- 作業フォルダーを特定します。不明な場合は確認してください。
- 次の両方のファイルが存在することを確認します:
agent-network.yaml(または.yml)とexchange.json。 - YAML を読み込みます。トップレベルに
schemaVersion: 1.0.0が必要です。(V2 ではagentNetwork: 2.0.0を使用します。) exchange.jsonを読み込みます。"classifier": "agent-network"が必要です。(V2 では"agentic-network"を使用します。)
いずれかの確認に失敗した場合は、変換を中止し、正しいフォルダーを指定するようユーザーに尋ねてください。
このフォルダーには V1 の Agent Network プロジェクトが見当たりません。
schemaVersion: 1.0.0を含むagent-network.yamlと、"classifier": "agent-network"を含むexchange.jsonを探しています。どのフォルダーを変換すればよいですか?
Step 2: 出力先を選択する
新しいフォルダー名は <original>_v2_conversion です。AskUserQuestion を使って、次の選択肢を提示します。
- ソースと同じ親ディレクトリ(デフォルト)。
- ユーザーが指定するパス。
黙って上書きしないでください。 出力先がすでに存在する場合は、上書きするか別の名前を選ぶか、ユーザーに確認してください。
Step 3: 変換する
変換では、同じ V1 ソースから 3 つの出力を生成します。
3a. V2 の agent-network.yaml を作成する
V2 には、トップレベルセクションとして agentNetwork、info、registry、context、brokers があります。V1 から V2 への対応は次のとおりです。
| V1 の場所 | V2 の場所 | 備考 |
|---|---|---|
schemaVersion: 1.0.0 | agentNetwork: 2.0.0 | 必須の文字列です。 |
label(トップレベル) | info.label | 必須です。 |
| (V1 にはなし) | info.version | 必須です。1.0.0 を使用します。 |
brokers.<id>.card.description | info.description | 存在する場合は、ブローカーの説明を info に移します。 |
agents.<id> | registry.agents.<id> | エージェントの変換を参照してください。 |
mcpServers.<id> | registry.mcps.<id> | V1 では mcpServers、V2 では mcps です。 |
llmProviders.<id> | registry.llms.<id> | カードのない LLM 情報を metadata の下に移します。 |
connections.<id> | context.connections.<id> | 接続の変換を参照してください。 |
brokers.<id> | brokers.<id> + ./brokers/<id>.agent | ブローカーの変換を参照してください。 |
エージェントの変換(agents → registry.agents)
V1 の各エージェントについて、次のようにします。
labelをinfo.labelに移します。metadata.platformはそのまま維持します。metadata.protocolは削除してください。GA ではこれがmetadata.interfacesに置き換わります。metadata.interfaces.a2a_v03.cardを作成します。V1 のエージェントは A2A v0.3 ベースのため、保守的な変換ではa2a_v03(後方互換)ブランチに配置します。カードでは、url: ${<refName>.url}、protocolVersion: 0.3.0、version: 1.0.0、capabilities.pushNotifications: false、およびmodes = [application/json, text/plain]を維持します。nameとdescriptionのデフォルト値には、エージェントの V1 のlabelを使用します。- ブローカー自体は A2A v1.0 を出力するため、
brokers.<id>.interfaces.a2aを維持します(a2a_v03ではありません)。 - エージェントごとに
skillsエントリを 1 つ作成します。idは<agentName>-<verb>(例:workday-create-record)とし、目的をnameとdescriptionにコピーします。
V1 で宣言されていない機能を追加しないでください。V1 に pushNotifications: true と記載されていない場合は、false のままにします。
MCP の変換(mcpServers → registry.mcps)
V1 の各 MCP サーバーについて、次のようにします。
labelをinfo.labelに移します。V1 のブローカーの指示から安全に導き出せる場合は、短いinfo.descriptionを追加します。metadata.transportはそのまま維持します。metadata.tools配列を追加します。V1 のブローカーが呼び出す各ツールについて(正規名はbrokers.tools[*].mcp.allowedを確認してください)、name、description、最小限のinputSchema(type: objectと、ブローカーの指示から確実に推測できる引数のproperties)を含むエントリを追加します。スキーマを特定できない場合は、捏造せずpropertiesを空のままにします。
LLM の変換(llmProviders → registry.llms)
V1 の各 LLM プロバイダーについて、次のようにします。
labelをinfo.labelに、descriptionをinfo.descriptionに移します。metadata.platformは維持します。metadata.modelsをリストとして追加します。V1 で実際に使用されるモデル(spec.llm.configuration.model)と、明らかに同系列のモデルを 1 つ含めます。推測に基づいてリストを増やさないでください。
接続の変換(connections → context.connections)
V1 のフラットな connections オブジェクトでは、各接続に kind、ref.name、spec.url、認証用の任意項目 spec.configuration があります。V2 でも基本的な考え方は同じですが、URL が spec の外に移動します。
# V1
WorkdayAgentTestConnection:
kind: agent
ref:
name: WorkdayAgentTest
spec:
url: https://...
次のようになります
# V2
workdayAgentConnection:
kind: a2a # V1 'agent' becomes V2 'a2a'
ref:
name: workdayAgent
url: ${workdayAgent.url}
マッピングルール:
kind: agent(V1)→kind: a2a(V2)。kind: mcpとkind: llmはそのままです。- LLM 接続の場合、認証情報をトップレベルの
authenticationブロックに移動します:kind: apiKey、apiKey: ${<llmName>.apiKey}。V1 のspec.configuration形式は使わないでください。 - ハードコードされた URL は
${<refName>.url}変数に置き換えます。実際の URL 値はexchange.jsonに記述します。 - 接続 ID は V2 スキーマで形式が制限されていません:
context.connections.<id>のキーには、有効な YAML 識別子であればどの形式でも使えます(camelCase、snake_case、kebab-case はすべて検証に通ります)。WorkdayAgentTestConnectionのような V1 の PascalCase は、わかりやすい ID に変換します。この変換ツールでは一貫性のため snake_case(workday_agent_connection)を使いますが、これは慣例であり、lint ルールではありません。必須条件は、ID が.agentのターゲット(a2a://<id>、mcp://<id>、llm://<id>)と完全に一致することです。 - レジストリの
ref.name値(agents/mcps/llms)は通常、V2 では camelCase になります(例:workdayAgent)。
ブローカーの変換
V1 では、ブローカーの A2A カードとオーケストレーターのプロンプト(spec.instructions)が 1 つのブロックにまとめられています。V2 では分割されます:
- A2A カードは
agent-network.yamlのbrokers.<broker-id>.interfaces.a2a.cardに残します。 - オーケストレーターのプロンプトは
./brokers/<broker-id>.agentに移動します。
V2 のブローカーエントリ(GA、A2A v1.0 — ブローカー自体がエンドポイントであるため、カードから url と protocolVersion を省略します):
brokers:
<broker-id>:
kind: AgentScript
implementation: ./brokers/<broker-id>.agent
interfaces:
a2a:
card:
name: <copied from V1 card.name>
description: <copied from V1 card.description>
version: 1.0.0
capabilities:
streaming: false
pushNotifications: <copied from V1 card.capabilities.pushNotifications, default false>
defaultInputModes: [application/json, text/plain]
defaultOutputModes: [application/json, text/plain]
skills:
- id: <copied, lowercased / kebab-cased>
name: <copied>
description: <copied>
tags: <copied>
examples: <copied if present>
inputModes: [application/json, text/plain]
outputModes: [application/json, text/plain]
ブローカー ID は V2 スキーマで形式が制限されていません:brokers: の下のキーには、有効な YAML 識別子であればどの形式でも使えます(snake_case、kebab-case、camelCase はすべて検証に通ります)。CustomerOnboardingBrokerTest のような V1 の PascalCase は、わかりやすい ID に変換します。この変換ツールでは一貫性のため snake_case(customer_onboarding)を使いますが、これは慣例であり、lint ルールではありません。.agent のファイル名は独立しています(例:./brokers/customer-onboarding.agent)。唯一の必須ルールは、トリガーの target: "brokers://<broker-id>/a2a" を YAML のブローカーキーと完全に一致させることです。
3b. V2 の exchange.json を作成する
V1 の exchange.json を使い、以下の変更を加えます:
"classifier": "agent-network"を"classifier": "agentic-network"に変更します。name、assetId、versionを V2 への変換を反映した値に更新します(例:-v2サフィックス)。descriptionフィールドを追加します。- V1 で外部 URL を参照する各接続について、
metadata.variables.<refName>.urlを追加し、URL をdefaultに指定します。これにより${<refName>.url}の参照を解決できるようになります。 - 既存の変数(例:
gemini.apiKey)は保持します。 - API キーには
"secret": trueを指定します。URL には"secret": falseを指定します。
3c. エージェントスクリプト <broker-id>.agent を作成する
構造のひな形として references/v2-template.agent を使用し、プレースホルダーを埋めます。命名と内容に関する重要なルール:
アクションの命名:
- 各 V1 のリンク済みエージェントに対して、
a2a:send_messageアクションを 1 つ作成します。エージェント名を snake_case に変換します(例:WorkdayAgentTest→workday_agent)。 brokers.tools[*].mcp.allowedに記載された各 V1 MCP ツールに対して、mcp:toolアクションを 1 つ作成します。ツールの目的を表す snake_case のアクション ID を選びます(例:SlackMcpServer.send_status_update→send_slack_status_update)。元のtool_nameは必ずそのまま保持してください。- MCP アクションに
inputs:を追加しないでください。 V1 にはツール入力スキーマがありません。V2 ランタイムはツールの引数を自動検出します。オーケストレーターの文章からinputs:を推測すると、根拠のない内容になり、誤ったスキーマが作成されます。 inputs:を追加するのは、後でwithを使って引数の値を修正またはデフォルト設定する場合のみです(例:channel_idを固定する)。変換時にこれを追加してはいけません。
推論アクションのエイリアス:
reasoning.actions内では、アクション ID をそのまま使わず、短く読みやすいエイリアス(例:workday、salesforce、slack_update)を使用します。これにより、オーケストレーターへの指示が読みやすくなります。
プロンプトの保持:
- V1 の
spec.instructionsを、オーケストレーターのsystem.instructionsにそのままコピーします。 - 機械的な編集のみ行います。
- プロンプトでドット区切りの MCP ツール名が使われている場合は、新しい V2 アクションのエイリアスに置き換えます。
- 明らかな誤記が混乱を招く場合に限り、最小限の修正を行います(例:「
this a long running task」→「this is a long running task」)。判断に迷う場合は、ユーザーの表現をそのまま残してください。
- プロンプトを複数のノードに分割しないでください。 ルーター、エグゼキューター、ジェネレーターを追加しないでください。明示的な制約により、オーケストレーション全体は 1 つのオーケストレーター内で実行されます。
Step 4: 出力を書き込む
<chosen_path>/<original_folder_name>_v2_conversion/
├── agent-network.yaml
├── exchange.json
└── brokers/
└── <broker-id>.agent
ディレクトリには mkdir -p を使用し、ファイルには Write を使用します。.mvn、.vscode、.cursor、target/ などの IDE フォルダーはプロジェクト仕様の一部ではないため、対象から除外します。保存先がすでに存在する場合は、上書きする前に確認してください。
書き込み後、作成したファイルを一覧表示します。
Step 5: 報告する
ユーザーに次の内容を伝えます。
- 新しいフォルダーの完全なパス。
- ブローカー名とオーケストレーターノード ID。
- 1 行の注記:これはオーケストレーターノードを 1 つ使用するシンプルな V1→V2 変換です。より複雑な複数ノードのグラフ(ルーター/ジェネレーター/エグゼキューターへの分割)を作成するには、
build-agent-broker-projectを使用してください。
避けるべきよくある間違い
schemaVersion: 1.0.0を残さないでください。 V2 ではagentNetwork: 2.0.0を使用します。- V1 の
agent-network分類子を残さないでください。 V2 ではagentic-networkを使用します。 - 余分なノード(ルーター、ジェネレーター、エグゼキューター)を作成しないでください。 ユーザーは単一のオーケストレーターを求めています。
- ユーザーのプロンプトを「改善」するために書き換えないでください。
- URL をハードコードしないでください。
${<name>.url}でパラメーター化し、値をexchange.jsonに記述します。 info.versionを忘れないでください。 V2 では必須ですが、V1 にはありません。- レジストリ内に認証ブロックを置かないでください。 認証情報は
context.connections.<name>.authenticationに設定します。 - V1→V2 変換時に MCP アクションへ
inputs:を追加しないでください。 V1 にスキーマはないため、inputs:ブロックは文章から推測したものになります。 - レジストリエージェントに
metadata.protocolやフラットなmetadata.cardを出力しないでください。 GA ではmetadata.interfaces.<branch>.cardを使用します。V1 から変換したエージェントは、後方互換性のためa2a_v03配下に配置します。ブローカー自体ではa2a(v1.0)を使用します。 - echo ノードで、ネストした
task: a2a.task({...})を伴うkind: "a2a:response"を出力しないでください。 GA ではkind: "a2a:status_update_event"(state + message)またはkind: "a2a:artifact_update_event"(artifact + append/lastChunk)を使用します。state の値にはTASK_STATE_*定数を使用します。 # @dialect: AGENTFABRIC=0.1-BETAまたは# @dialect: AGENTFABRIC=0.1を出力しないでください。 GA では# @dialect: AGENTFABRIC=1.0を使用します。