sn-infographic について
sn-infographicは、テキストの依頼からインフォグラフィックを生成するエージェント向けスキルです。プロンプトの評価・拡張に加え、複数回の生成結果を画像レビューで評価して順位付けします。
主な機能
- 01プロンプト品質の評価
- 02必要に応じたプロンプト拡張
- 03複数回の生成と画像レビュー
- 04品質順の結果提示
- 05簡潔または詳細な出力
活用シーン
- 01短い依頼を画像プロンプトに変換
- 02複数回生成した画像の比較
- 03指定した比率とサイズでのインフォグラフィック生成
MCP 対応
入力にはMCPとの関係が記載されていません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ opensensenova/ sensenova-skills --skill sn-infographicインストール後、Claude Code で/sn-infographicを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/analysis-framework.mdbase-prompt.mdevaluation-standard.mdlayout-style-selection.mdreferences/layouts/asymmetry.mdaxial-expansion.mdbento-grid.mdbig-typography.mdbinary-comparison.mdbreaking-the-grid.mdbridge.mdcenter-focus.mdchapter-layout.mdcharacter-guide.mdcircular-flow.mdcollage-glitch.mdcomic-strip.mdcomparison-matrix.mdconflict-contrast.mdcontainerization.mddashboard.mddata-landscape.mddeconstruction.mddiagonal-composition.mddisrupted-flow.mdedge-tension.mdeditorial-vogue.mdemotional-gradient.mdf-pattern.mdflashback.md詳細
sn-infographic
インフォグラフィック生成シーン向けスキル(ティア 1)。sn-image-base(ティア 0)が提供する sn-image-generate、sn-image-recognize、sn-text-optimize ツールに依存します。
特徴:
- プロンプト品質の評価(自動モード)
- プロンプトの拡張(強制/自動モード)
- 画像生成と VLM によるレビューを複数回実施
- 品質ランキングに基づいて最良の結果を出力
入力仕様
| パラメーター | 型 | デフォルト値 | 説明 |
|---|---|---|---|
user_prompt | string | 必須 | ユーザーの元のリクエストです。UTF-8 テキストで、Markdown、URL、構造化データを含めることができます。長さは、基盤となる LLM のコンテキスト予算によってのみ制限されます。 |
max_rounds | int | 1 | 生成ラウンドの最大数です。有効範囲:1~8。max_rounds=1 の場合、ステップ 3 の VLM レビューと早期終了チェックの両方がスキップされます。 |
output_mode | string | friendly | friendly:1 行のコンテンツ説明 + rank=1 の画像 1 枚 |
verbose:品質ランキング全体 + 所要時間の統計 + すべての画像(順位順) | |||
prompts_expand_mode | string | auto | auto:まず user_prompt の品質を評価し、品質が不十分な場合にのみステップ 2 の拡張を実行します |
force:評価をスキップし、常にステップ 2 の拡張を実行します | |||
disable:ステップ 2 をスキップし、user_prompt をそのまま expanded_prompt として使用します | |||
aspect_ratio | string | 推定(16:9) | ユーザーが対応している比率を明示した場合(例:16:9/9:16、または 宽高比/画面比例/aspect ratio を使用した場合)は、Main Agent が設定します。それ以外の場合は未設定のままとなり、Worker が references/runtime-parameters.md に従い、ステップ 0 で user_prompt から推定します(向き/シーンの手がかりを使用)。 |
image_size | string | 推定(2k) | ユーザーがサイズ(2k/4k)を明示した場合は、Main Agent が設定します。それ以外の場合は、Worker がステップ 0 で推定します(現在、選択肢は 2k のみです)。SN_IMAGE_GEN_MODEL=sensenova-u1.5-lite の場合は 4k を使用できます。ほかのモデルでは拒否される場合があり、その場合はスキルがエラーを表示します。 |
抽出する項目の担当者: Main Agent によるパラメーター抽出では、ユーザーが明示した値がある場合に限り、
max_rounds、output_mode、prompts_expand_mode、aspect_ratio/image_sizeを解決します。明示的な値がない場合、aspect_ratioとimage_sizeはステップ 0 で Worker が推定します。
API の設定
このスキルのすべての API 呼び出しは、sn-image-base スキルの sn_agent_runner.py を通じて実行されます。認証パラメーターにはデフォルト値が使用されるため(CLI > 環境変数 > 組み込みのデフォルト値)、明示的に渡す必要はありません。
| 呼び出しの種類 | ツール | 認証パラメーター | 説明 |
|---|---|---|---|
| LLM | sn-text-optimize(評価/拡張) | デフォルトでは SN_TEXT_API_KEY -> SN_CHAT_API_KEY -> SN_API_KEY の順に読み込みます | 組み込みのデフォルト値は Sensenova の社内ネットワークサービスを参照します |
| VLM | sn-image-recognize(画像レビュー) | デフォルトでは SN_VISION_API_KEY -> SN_CHAT_API_KEY -> SN_API_KEY の順に読み込みます | 組み込みのデフォルト値は Sensenova の社内ネットワークサービスを参照します |
| 画像生成 | sn-image-generate | デフォルトでは SN_IMAGE_GEN_API_KEY -> SN_API_KEY の順に読み込みます。SN_IMAGE_GEN_API_KEY が必要なのは、画像固有の上書きを行う場合のみです | sn-image-base の画像生成設定を使用します |
MissingApiKeyError が発生した場合、またはモデルを指定する必要がある場合: CLI パラメーターを使って明示的に渡してください。パラメーターの詳細は $SN_IMAGE_BASE/references/api_spec.md を参照してください。
$SN_IMAGE_BASE パスの説明: $SN_IMAGE_BASE は sn-image-base スキルのインストールディレクトリです(SKILL.md が存在する場所)。
エージェントは、インストール済みスキルの一覧からスキル名 sn-image-base を使ってこのパスを特定できます。
アーキテクチャ:メインエージェント + ワーカーエージェント
このスキルでは、2 層構造のエージェントアーキテクチャを使用します。
| 役割 | 責任 |
|---|---|
| メインエージェント | ユーザーのリクエストを受け取り、パラメーターを正規化し、事前チェックを送信し、ワーカーを起動し、結果を収集して、テキストと画像をユーザーに送信します |
| ワーカーエージェント | 生成パイプライン(拡張 → 複数回の生成とレビュー → 並べ替え)を実行し、構造化 JSON を返します |
責任の境界:
- ワーカーエージェントはユーザーにメッセージを直接送信せず、構造化 JSON のみを返します
- ユーザーに表示されるすべてのメッセージの送信は、メインエージェントが担当します
- ワーカーエージェントの最後のメッセージは、Return Contract で定義された JSON 文字列のみでなければなりません
- ワーカーエージェント内部の VLM 呼び出しは、サブエージェントを起動せず、常に直接実行されます
ワークフロー
メインエージェントのワークフロー
-
ユーザーリクエストからパラメーターを3段階で抽出します。
-
インラインKVディレクティブ —
key=value形式のトークンを解析します。ここで、key∈ {max_rounds,output_mode,prompts_expand_mode,aspect_ratio,image_size}です。認識されたトークンをユーザーメッセージから取り除き、残りをuser_promptとします。例:"生成一张信息图 max_rounds=3 output_mode=verbose"→user_prompt="生成一张信息图"、max_rounds=3、output_mode=verbose。 -
キーワード認識(大文字と小文字を区別せず、除去後のテキストに適用)— 以下の表に従って、インラインKVでまだ設定されていないパラメーターを設定します。
パラメーター トリガーキーワード 解決値 output_modeverbose,详细,详尽,完整统计verbosefriendly,简洁,精简friendlymax_roundsN 轮,N rounds,重试 N 次(Nを解析)N、[1, 8]の範囲に制限prompts_expand_mode强制扩写,force expand,force expansionforce不扩写,跳过扩写,disable expansion,no expanddisableaspect_ratio明示されたサポート対象の比率( 16:99:164:33:41:12:33:24:55:421:99:21)。宽高比/画面比例/比例/aspect ratioの前置きがあってもなくても可その比率( runtime-parameters.mdのサポート対象一覧に照らして検証します。サポートされていない値の場合は、Workerが推論できるよう未設定のままにします)image_size明示されたサポート対象サイズ( 2k4k)。image_size/分辨率/清晰度/image sizeの前置きがあってもなくても可そのサイズ( 高清/超清のような曖昧な品質表現は対象になりません。サポートされていない値の場合は、Workerが推論できるよう未設定のままにします) -
デフォルト — まだ設定されていないパラメーターは、
max_rounds=1、output_mode=friendly、prompts_expand_mode=autoにフォールバックします。aspect_ratioとimage_sizeには、メインエージェントのデフォルト値はありません。明示的な値が検出されない場合は、ステップ0でWorkerが推論できるよう未設定のままにします。
優先順位:インラインKV > キーワード認識 > デフォルト。インラインKVの値はInput Specificationに照らして検証します(範囲外の
max_roundsは[1, 8]の範囲に制限し、認識されない列挙値はデフォルトにフォールバックして、メインエージェントが不一致をログに記録します)。 -
-
統一された事前メッセージを送信します:
"Using sn-infographic skill to generate infographic, please wait..." -
完全なパラメーターと作業ディレクトリを渡して、Worker Agent(サブエージェント)を起動します。
-
Worker Agentが
status=okかつneed_main_agent_send=trueを返した場合:- max_rounds = 1:返されたJSONの
expanded_promptからテキスト要約を生成し(長さと言語のルールについてはOutput Format → friendly modeを参照)、送信した後、rank=1の単一画像を送信します。 - max_rounds > 1、friendly mode:rank=1のラウンドの
resultとviolationsに基づいてテキスト要約を生成し、送信した後、rank=1の単一画像を送信します。 - max_rounds > 1、verbose mode:verboseテンプレートをレンダリングし(置換ルールについてはOutput Format → verbose modeを参照)、送信した後、すべての画像をrank順に送信します。
- max_rounds = 1:返されたJSONの
-
Worker Agentが
status=errorを返した場合は、実際のerrorフィールドの内容をユーザーに報告します。
Worker Agentのワークフロー
Worker Agentは、user_prompt、max_rounds、prompts_expand_mode、任意のaspect_ratioとimage_size(それぞれ、ユーザーが明示的に指定した場合にのみ設定)、およびこのスキルの作業ディレクトリ(SKILL_DIR)を受け取ります。(output_modeはメインエージェント側に留まり、Workerにはこれに依存する分岐はありません。)
ワーカー環境
以下の bash スニペットで $NAME として参照される変数です。ワーカーは、それぞれを使用するステップの前にバインドする必要があります。
| 変数 | ソース | 使用箇所 |
|---|---|---|
USER_PROMPT | メインエージェントの入力 — 元のユーザーリクエスト | ステップ 1 の評価、ステップ 2.0 のコンテンツ分析 |
MAX_ROUNDS | メインエージェントの入力(デフォルト 1) | ステップ 3 のループ上限、早期終了ゲート |
PROMPTS_EXPAND_MODE | メインエージェントの入力(デフォルト auto) | ステップ 1 の分岐 |
SKILL_DIR | エージェントのランタイムが現在のスキルのインストールパス(例:~/.openclaw/skills/sn-infographic、~/.hermes/skills/sn-infographic)を解決します | references/* の読み込み |
SN_IMAGE_BASE | エージェントのランタイムが、インストール済みスキルのレジストリでスキル名 sn-image-base を基に解決します | scripts/sn_agent_runner.py の実行 |
TASK_ID | ステップ 0(date +%Y%m%d_%H%M%S) | 一意性トークン |
TEMP_DIR | ステップ 0(/tmp/openclaw/sn-infographic/${TASK_ID}) | すべての中間生成物用の作業ディレクトリ |
IMAGE_SIZE | ユーザーが明示的なサイズを指定した場合はメインエージェントの入力。それ以外の場合は、USER_PROMPT からステップ 0 で推定します(選択肢は 1 つ、2k) | sn-image-generate --image-size |
ASPECT_RATIO | ユーザーが明示的な比率を指定した場合はメインエージェントの入力。それ以外の場合は、USER_PROMPT からステップ 0 で推定します(デフォルト 16:9) | sn-image-generate --aspect-ratio |
EXPANDED_PROMPT | ステップ 1(ステップ 2 がスキップされた場合は USER_PROMPT のコピー)またはステップ 2.3(展開後の結果) | sn-image-generate --prompt |
LAYOUT、STYLE | ステップ 2.1 の選択結果(フォールバック先は hub-spoke / corporate-memphis) | ステップ 2.3 のシステムプロンプトの組み立て |
ROUND | ステップ 3 のループカウンター(for ROUND in $(seq 1 "$MAX_ROUNDS")) | ラウンドごとのファイル名(round_${ROUND}.png) |
命名規則:自身のファイルには $SKILL_DIR、スキル間の参照には $SN_<SKILL_NAME>(例:$SN_IMAGE_BASE)を使用します。
JSON の解析:sn_agent_runner.py ... -o json の各呼び出しは、標準出力に JSON の エンベロープ({"status", "result", "model", ...}。診断情報は標準エラー出力に出力されます)を出力します。呼び出しに失敗すると、status は ok 以外の値(例:failed)になり、result は省略されます。そのため、.result を読む前に、エンベロープの .status == ok を必ず確認してください。確認しない場合、.result が欠落すると文字列の null として出力されます。これは有効な JSON であるため、jq -r と extract_json.py のどちらでもエラーにならずに処理されてしまいます。LLM 自身の JSON(評価/分析ステップ)は result 文字列の中にあり、余分な文章や ```json フェンスが含まれる場合があります。jq を使う前に、ランナーの出力を $SN_IMAGE_BASE/scripts/extract_json.py にパイプしてください(標準入力を読み取り、復元した JSON を出力します。JSON が見つからない場合はゼロ以外で終了します)。内部の LLM/VLM JSON を解析するステップでは、.result も同様にパイプしてください。ステータスが ok 以外の場合、または extract_json.py がゼロ以外で終了した場合、応答は使用できません → Error Flow JSON を返します。
ステップ 0 — 初期化
-
task_id(タイムスタンプ、形式YYYYMMDD_HHMMSS)を生成し、共通の一時ディレクトリ/tmp/openclaw/sn-infographic/<task_id>/をTEMP_DIRとして作成します。後続のステップで書き込みを行う前に、TEMP_DIRが存在している必要があります。TASK_ID=$(date +%Y%m%d_%H%M%S) TEMP_DIR="/tmp/openclaw/sn-infographic/${TASK_ID}" mkdir -p "$TEMP_DIR" -
空の
roundsリストを初期化します -
aspect_ratioとimage_sizeを解決します(ASPECT_RATIO/IMAGE_SIZEにバインド)。明示的なメインエージェントの値があればそれを使い、なければ$SKILL_DIR/references/runtime-parameters.mdに従ってuser_promptから推定します。デフォルト:aspect_ratio→16:9、image_sizeの推定候補は現在2kの 1 つです。
Step 1 — 画像プロンプトを書き換えるかどうかを判断する(必ず実行)
このステップでは、Step 3 で画像を生成する前に、ユーザーの画像生成用promptテキストを書き換え/拡張するかどうかを判断し、ブール値のshould_expandを生成します。Step 2 をスキップする場合は、EXPANDED_PROMPTも設定し、prompts_expand_skipped = trueを記録します。
対象範囲(ステップ名を過度に解釈しないでください)。 ここでの「拡張」とは、画像生成用のテキストプロンプトを書き換えることだけを意味します。それ以上のことではありません。これはタスクの分解、計画の生成、計画レビューのゲートではなく、Step 1 自体がエージェントを起動することもありません。Worker 自身が行う単一のsn-text-optimize呼び出しです。これをsubagent-driven-development/delegate_task形式のワークフローに当てはめないでください。また、計画ファイルも作成しないでください。(このスキルで使用するサブエージェントは Worker だけです。Main Agent によって 1 回起動され、Worker 自身はサブエージェントを起動しません。「責任の境界」を参照してください。)
PROMPTS_EXPAND_MODEは、Main Agent から渡される解決済みの入力です。Step 1 はその値に基づいて動作するものであり、ユーザーリクエストを再解析するものではありません。モード値の解決(Main Agent によるパラメーター抽出)と、この判断の実行は別々の作業です。前者を完了しても、Step 1 が完了したことにはなりません。このステップをスキップしないでください。autoモードでは、以下の評価呼び出しが必須です。プロンプトの見かけ上の品質からshould_expandを推測してはいけません。
スキップされる可能性があるのはStep 2(プロンプトの拡張)だけであり、このステップでスキップすると判断された場合に限ります。分岐はPROMPTS_EXPAND_MODEによって決まります。
autoモード(デフォルト):
-
評価呼び出しを実行します(必須)。内側の評価 JSON は
.result内にあります。スキーマは$SKILL_DIR/references/evaluation-standard.md(required_results、optional_results)です。EVAL_ENVELOPE=$(python "$SN_IMAGE_BASE/scripts/sn_agent_runner.py" sn-text-optimize \ --system-prompt-path "$SKILL_DIR/references/evaluation-standard.md" \ --user-prompt "$USER_PROMPT" \ --output-format json | python "$SN_IMAGE_BASE/scripts/extract_json.py") # A failed runner envelope (status != ok) carries no .result. EVAL_STATUS=$(printf '%s' "$EVAL_ENVELOPE" | jq -r '.status') EVAL=$(printf '%s' "$EVAL_ENVELOPE" | jq -r '.result' \ | python "$SN_IMAGE_BASE/scripts/extract_json.py") -
should_expandを判断します。required_pass:required_results内のすべてのanswerが"yes"であるoptional_pass:optional_results内でanswer="yes"の数/合計が0.6以上であるshould_expand = not (required_pass and optional_pass)
-
保守的なフォールバック:
EVAL_STATUSがokでない場合(評価呼び出し自体が失敗した場合)、またはextract_json.pyがゼロ以外で終了した場合は、デフォルトでshould_expand = trueにします。Step 2.0/2.3とは異なり、評価に失敗してもWorkerは中断しません。autoは拡張にフォールバックします。 -
should_expand = trueの場合:Step 2を実行します。 -
should_expand = falseの場合:Step 2をスキップし、EXPANDED_PROMPTに元のプロンプトを設定して、prompts_expand_skipped = trueを記録します。EXPANDED_PROMPT="$USER_PROMPT" echo "$EXPANDED_PROMPT" > "$TEMP_DIR/expanded-prompt.txt"
forceモード:
- 評価をスキップし、必ずStep 2を実行します(拡張は必須です)。
prompts_expand_skippedは記録されません。このフィールドはStep 2がスキップされた場合にのみReturn JSONに含まれます(「Return Contract」のルールを参照してください)。
disableモード:
-
評価とStep 2の両方をスキップし、
user_promptをそのままexpanded_promptとして使用します。EXPANDED_PROMPT="$USER_PROMPT" echo "$EXPANDED_PROMPT" > "$TEMP_DIR/expanded-prompt.txt" -
prompts_expand_skipped = trueを記録します。
ステップ 2 — コンテンツ分析+レイアウトとスタイルの選択+プロンプトの拡張
2.0 コンテンツ分析(sn-image-base の sn-text-optimize ツールを使用):
ANALYSIS_ENVELOPE=$(python "$SN_IMAGE_BASE/scripts/sn_agent_runner.py" sn-text-optimize \
--system-prompt-path "$SKILL_DIR/references/analysis-framework.md" \
--user-prompt "$USER_PROMPT" \
--output-format json | python "$SN_IMAGE_BASE/scripts/extract_json.py")
.result から内部の分析 JSON を(エンベロープではなく、ステップ 2.1 で data_type / tone / audience を直接 jq で取得できるように)$TEMP_DIR/analysis.json に保存します。以下のガードは、まず失敗したエンベロープを拒否します(ステータスが ok 以外、または extract_json.py がゼロ以外を返す場合 → .error を含むエラーフロー):
# A failed runner envelope (status != ok) has no .result → return Error Flow.
if [ "$(printf '%s' "$ANALYSIS_ENVELOPE" | jq -r '.status')" != "ok" ]; then
ANALYSIS_ERROR=$(printf '%s' "$ANALYSIS_ENVELOPE" | jq -r '.error')
# return Error Flow JSON {"status":"error","error":"$ANALYSIS_ERROR"} to Main Agent and stop
fi
printf '%s' "$ANALYSIS_ENVELOPE" | jq -r '.result' \
| python "$SN_IMAGE_BASE/scripts/extract_json.py" > "$TEMP_DIR/analysis.json"
スキーマ:$SKILL_DIR/references/analysis-framework.md(data_type、tone、audience およびステップ 2.1 / 2.2 で使用するその他のフィールドを定義しています)。
2.1 レイアウトとスタイルの選択
これは、$SKILL_DIR/references/layout-style-selection.md の候補テーブルから名前レベルで重み付きランダムに選択する処理です。レイアウト/スタイルの名前だけを対象とします。ここでは references/layouts/ または references/styles/ 内のファイルを開かないでください。また、最適なものを選ぶために「選択肢を比較」しないでください。選択はランダムであり、ファイルの内容に基づく判断は行いません。選択されたレイアウトファイル 1 つとスタイルファイル 1 つは、後のステップ 2.3 でそれぞれ 1 回だけ読み込みます。
- 一時ディレクトリ
$TEMP_DIR/analysis.jsonから分析結果を読み込みます。
ANALYSIS=$(cat "$TEMP_DIR/analysis.json")
data_type/tone/audienceから、$SKILL_DIR/references/layout-style-selection.mdで定義された候補の検索と重み付きランダムサンプリングを実行し、LAYOUT名とSTYLE名をそれぞれ 1 つ取得します(名前のみ。ファイルは読み込みません)。- 定義ファイルが存在することだけを
[ -f ]で確認して選択結果を検証します(読み込みは引き続き行いません)。ファイルがない場合はhub-spoke+corporate-memphisにフォールバックします。
[ -f "$SKILL_DIR/references/layouts/${LAYOUT}.md" ] || LAYOUT=hub-spoke
[ -f "$SKILL_DIR/references/styles/${STYLE}.md" ] || STYLE=corporate-memphis
- 選択結果を一時ディレクトリに保存します:
$TEMP_DIR/layout-style.json。
layout-style.json の形式:
{
"layout": "<layout>",
"style": "<style>"
}
2.2 構造化コンテンツの生成
分析結果と構造化コンテンツのテンプレートを読み込み、テンプレートのルールに基づいて user_prompt をデザイン用の構造化コンテンツに変換します。
ANALYSIS=$(cat "$TEMP_DIR/analysis.json")
LAYOUT_STYLE=$(cat "$TEMP_DIR/layout-style.json")
STRUCTURED_CONTENT_TEMPLATE=$(cat "$SKILL_DIR/references/structured-content-template.md")
テンプレートで定義された 3 つのフェーズ(概要の作成 → セクションの作成 → データ整合性の確認)に従い、analysis.json の学習目標、視覚化の機会、重要なデータを組み合わせて構造化コンテンツを生成し、一時ディレクトリに保存します。
cat > "$TEMP_DIR/structured-content.md" << 'EOF'
<Content generated based on structured-content-template.md format>
EOF
構造:$SKILL_DIR/references/structured-content-template.md。
ルール:すべてのデータを正確に保持してください。書き換えないでください。ソースにない情報を追加しないでください。
2.3 プロンプトの拡張(sn-image-base の sn-text-optimize ツールを使用):
レイアウト/スタイルの選択結果を読み込み、システムプロンプトをファイルを直接連結して組み立てます(レイアウト/スタイルファイルにはバッククォートと $(...) が含まれているため、引用符で囲まれていないヒアドキュメントの本文では実行されてしまいます。ヒアドキュメントは使用しないでください)。
LAYOUT=$(jq -r '.layout' "$TEMP_DIR/layout-style.json")
STYLE=$(jq -r '.style' "$TEMP_DIR/layout-style.json")
{
cat "$SKILL_DIR/references/prompts-expand-system.md"
printf '\n\n---\n\n## Selected Layout: %s\n\n' "$LAYOUT"
cat "$SKILL_DIR/references/layouts/${LAYOUT}.md"
printf '\n\n---\n\n## Selected Style: %s\n\n' "$STYLE"
cat "$SKILL_DIR/references/styles/${STYLE}.md"
printf '\n\n---\n\n## Output Template Reference\n\n'
cat "$SKILL_DIR/references/base-prompt.md"
} > "$TEMP_DIR/expand-system-prompt.md"
structured-content.md の内容をユーザープロンプトとして使用し(引数の長さとクォートの問題を避けるため --user-prompt-path で渡します)、一時ファイルからシステムプロンプトを読み込み、sn-text-optimize を呼び出します。
EXPAND_ENVELOPE=$(python "$SN_IMAGE_BASE/scripts/sn_agent_runner.py" sn-text-optimize \
--system-prompt-path "$TEMP_DIR/expand-system-prompt.md" \
--user-prompt-path "$TEMP_DIR/structured-content.md" \
--output-format json | python "$SN_IMAGE_BASE/scripts/extract_json.py")
result フィールドを expanded_prompt として抽出し、一時ディレクトリに書き込みます。ここでの .result は JSON ではなく拡張後のプロンプトテキストなので、extract_json.py で解析するのはエンベロープだけです。まず .status == ok を確認してください。失敗したエンベロープには .result がないため、jq -r '.result' はリテラル文字列 null を返し、画像プロンプトとして "null" が書き込まれてしまいます。
# A failed runner envelope (status != ok) has no .result → return Error Flow.
if [ "$(printf '%s' "$EXPAND_ENVELOPE" | jq -r '.status')" != "ok" ]; then
EXPAND_ERROR=$(printf '%s' "$EXPAND_ENVELOPE" | jq -r '.error')
# return Error Flow JSON {"status":"error","error":"$EXPAND_ERROR"} to Main Agent and stop
fi
EXPANDED_PROMPT=$(printf '%s' "$EXPAND_ENVELOPE" | jq -r '.result')
echo "$EXPANDED_PROMPT" > "$TEMP_DIR/expanded-prompt.txt"
expanded-prompt.txt:UTF-8 の単一文字列。ステップ 3 で sn-image-generate --prompt にそのまま渡します。
上記のステータスガードに加えて、解析に失敗した場合や、出力の切り詰めが疑われる場合(返された内容が不完全な場合)も、Worker は同様にエラーフローの JSON(status=error、実際のメッセージ)を返して終了する必要があります。ユーザーに直接メッセージを送ってはいけません(「責任の境界」を参照)。
ステップ 3 — 画像生成ループ
ROUND を 1 から max_rounds まで順番に実行します。各反復内で、シェル変数 ROUND に現在のラウンド番号を設定し、後続のラウンドで互いのファイルを上書きしないよう、すべてのパスで ${ROUND} を使用します。
for ROUND in $(seq 1 "$MAX_ROUNDS"); do
# the Generate Image / Review Image / Save Round Result blocks below run inside this loop body
:
done
画像を生成(sn-image-base の sn-image-generate ツールを使用):
python "$SN_IMAGE_BASE/scripts/sn_agent_runner.py" sn-image-generate \
--prompt "$EXPANDED_PROMPT" \
--image-size "$IMAGE_SIZE" \
--aspect-ratio "$ASPECT_RATIO" \
--save-path "$TEMP_DIR/round_${ROUND}.png" \
-o json
画像をレビュー(max_rounds > 1 の場合にのみ実行):
- VLM モデルが設定されていない場合:VLM 設定を追加するか、
max_rounds=1に設定するようユーザーに提案する Error Flow JSON を返します。 - VLM 呼び出しが失敗するかタイムアウトした場合:フォールバックは行わず、実際のエラーを含む Error Flow JSON を返します。
python "$SN_IMAGE_BASE/scripts/sn_agent_runner.py" sn-image-recognize \
--system-prompt-path "$SKILL_DIR/references/prompts-critic-system.md" \
--user-prompt "Evaluate the diagram in the image against the rules. Output your assessment." \
--images "$TEMP_DIR/round_${ROUND}.png" \
--output-format json
VLM の応答をラウンドごとのレコードにマッピング(VLM の応答スキーマは $SKILL_DIR/references/prompts-critic-system.md で定義されており、各違反は 4 フィールドのオブジェクトです):
vlm.result→rounds[i].result(そのまま —"PASS"または"FAIL")vlm.violations→rounds[i].violations(そのまま渡す —{ rule_id, rule_name, detail, revised_description }オブジェクトの配列)len(vlm.violations)→rounds[i].violations_countvlm.reasoning→rounds[i].reasoning(文字列をそのまま渡す)
max_rounds=1(VLM 呼び出しなし)の場合、ラウンドレコードは result="PASS"、violations=[]、violations_count=0、reasoning="" をデフォルト値とします。
ラウンド結果を保存:
{
"round": 1,
"image": "$TEMP_DIR/round_1.png",
"result": "PASS|FAIL",
"violations_count": 1,
"violations": [
{
"rule_id": "5",
"rule_name": "Illegible Text",
"detail": "<offending element description>",
"revised_description": "<suggested fix per the prompts-critic-system.md standards>"
}
],
"reasoning": "<VLM reasoning, or \"\" when max_rounds=1>",
"timing": {
"image_generation": { "elapsed_seconds": 12.34, "model": "sn_image_model" },
"vlm_review": { "elapsed_seconds": 5.67, "model": "sensenova-6.8-flash-lite" }
}
}
早期終了の確認(max_rounds > 1 の場合にのみ実行):
result=PASSの場合、直ちにループを終了し、生成を続行しませんresult=FAILの場合、残りのラウンドがあれば次のラウンドに進みます
ステップ 4 — 画像品質のランキング
violations_count の昇順、続いて round の昇順で画像を並べ替え、構造化 JSON を Main Agent に返します。
返却契約
Worker Agent の完了後、最後のメッセージは次の JSON 文字列のみでなければなりません(コードフェンスなしの生の JSON。前後にテキストを付けないでください)。
以下の例で使用する表記:
<...>— ドキュメント内のプレースホルダーです。実行時に実際の値に置き換えてください。A|B— 列挙されたリテラルのうち 1 つです。返却する JSON には、そのうち正確に 1 つを含めてください(例:"result": "PASS"または"result": "FAIL"。「PASS|FAIL」というリテラル文字列は不可)。$VAR— シリアライズ前に解決済みの値へ展開する必要があります。たとえば、スキーマ内の"image": "$TEMP_DIR/round_1.png"は、Step 3 で実際に書き込まれた絶対パス(例:"/tmp/openclaw/sn-infographic/20260521_120000/round_1.png")として返し、"$TEMP_DIR/round_1.png"というリテラルは返さないでください。- 条件付きフィールド — Rules の項目に「…の場合は省略」とあるフィールドは、その場合、
nullを設定するのではなく、JSON から完全に削除してください。
通常フロー:
{
"status": "ok",
"need_main_agent_send": true,
"expanded_prompt": "<original user_prompt if prompts_expand_skipped, else expanded result from Step 2.3>",
"prompts_expand_skipped": true,
"early_terminated": true,
"timing": {
"total_elapsed_seconds": 35.12,
"prompt_evaluation": { "elapsed_seconds": 2.11, "model": "sensenova-6.8-flash-lite" },
"content_analysis": { "elapsed_seconds": 3.22, "model": "sensenova-6.8-flash-lite" },
"prompt_expand": { "elapsed_seconds": 8.45, "model": "sensenova-6.8-flash-lite" }
},
"rounds": [
{
"round": 1,
"image": "$TEMP_DIR/round_1.png",
"result": "PASS|FAIL",
"violations_count": 1,
"violations": [
{
"rule_id": "5",
"rule_name": "Illegible Text",
"detail": "<offending element description>",
"revised_description": "<suggested fix>"
}
],
"reasoning": "<VLM reasoning, or \"\" when max_rounds=1>",
"timing": {
"image_generation": { "elapsed_seconds": 12.34, "model": "sn_image_model" },
"vlm_review": { "elapsed_seconds": 5.67, "model": "sensenova-6.8-flash-lite" }
}
}
]
}
エラーフロー:
{
"status": "error",
"error": "<Actual error information>"
}
ルール:
status=okにはneed_main_agent_send: trueを含めてください。expanded_prompt:status=okでは常に含めます。prompts_expand_skipped=trueの場合は元のuser_prompt、それ以外の場合は Step 2.3 の結果を値にします。prompts_expand_skipped:Step 2 をスキップした場合(prompts_expand_mode=disable、またはautoで評価に合格した場合)のみtrueを含めます。それ以外の場合は省略します。early_terminated:Step 3 がPASSによってループを早期終了した場合のみtrueを含めます。それ以外の場合(max_rounds=1の実行を含む)は省略します。violations:VLM のレスポンスから取得したオブジェクトの配列。スキーマは$SKILL_DIR/references/prompts-critic-system.md(rule_id、rule_name、detail、revised_description)です。result=PASSまたはmax_rounds=1の場合は[]です。violations_count:len(violations)。max_rounds=1の場合は0です。reasoning:VLM のreasoningフィールドをそのまま使用します。max_rounds=1の場合は""です。max_rounds=1の場合、VLM によるチェックなしで画像を納品するため、単一ラウンドのresultはデフォルトで"PASS"です。- トップレベルの
timing:total_elapsed_seconds:Step 0 から JSON を返すまでの Worker の実時間。prompt_evaluation:Step 1 の評価による{elapsed_seconds, model}。prompts_expand_mode=autoの場合のみ含めます。content_analysis:Step 2.0 の{elapsed_seconds, model}。prompts_expand_skipped=trueの場合は省略します。prompt_expand:Step 2.3 の{elapsed_seconds, model}。prompts_expand_skipped=trueの場合は省略します。
rounds[].timing.image_generation.model:"sn_image_model"を固定値として使用します(sn-image-generate は model フィールドを返しません)。rounds[].timing.vlm_review:max_rounds=1の場合は省略します。
出力形式
friendly モード(デフォルト)
テキスト要約 — Main Agent が生成する、1 文の説明です。長さは言語を問わず 50 文字以下です(漢字 1 文字 = 1 単位、ASCII 文字 1 文字 = 1 単位)。言語は user_prompt の主な言語に合わせてください(主に中国語の場合は中国語、それ以外の場合は英語)。
max_rounds = 1の場合:expanded_promptをもとに説明を作成します(インフォグラフィックに何が描かれているかに焦点を当てます)。max_rounds > 1の場合:rank=1 のラウンドのresultとviolationsをもとに説明を作成します。result=PASS:肯定的な表現にします。result=FAIL(違反が 1~2 件):具体的な問題点を簡潔に指摘します。result=FAIL(違反が 3 件以上):主な問題点を客観的に要約します。
画像:rank=1 の単一画像。
詳細モード
Quality ranking result (high -> low)
---
Expanded prompt: [expanded | not expanded, using original prompt]
<expanded_prompt>
---
#1 round=<n> result=<PASS|FAIL> violations=<n> [early terminated]
#2 round=<n> result=<PASS|FAIL> violations=<n>
...
---
Time statistics: Total <total>s | Prompt evaluation <t>s | Content analysis <t>s | Prompt expansion <t>s | Image generation <t>s×<n> rounds | VLM review <t>s×<n> rounds
---
Images (sent in rank order)
置換ルール:
| プレースホルダー | ルール |
|---|---|
[expanded | not expanded, using original prompt] | Return JSON に prompts_expand_skipped=true が含まれる場合は not expanded, using original prompt、それ以外の場合は expanded です。 |
<expanded_prompt> | Return JSON の expanded_prompt フィールドをそのまま使用します。 |
#k round=<n> result=… violations=… | rounds[] の各エントリにつき1行を、順位順(k = 1..len(rounds))に並べます。<n> は rounds[i].round です。 |
[early terminated] | 早期終了を実際に引き起こしたラウンド(ループを打ち切った result=PASS のラウンド)にのみ追加します。それ以外の行には追加しません。Return JSON に early_terminated が存在しない場合、このタグは表示されません。 |
Total <total>s | timing.total_elapsed_seconds です。必ず表示します。 |
Prompt evaluation <t>s | timing.prompt_evaluation.elapsed_seconds です。Return JSON に prompt_evaluation が存在しない場合、この | Prompt evaluation … セグメント全体を省略します。 |
Content analysis <t>s | timing.content_analysis.elapsed_seconds です。存在しない場合はセグメント全体を省略します。 |
Prompt expansion <t>s | timing.prompt_expand.elapsed_seconds です。存在しない場合はセグメント全体を省略します。 |
Image generation <t>s×<n> rounds | <t> は rounds[].timing.image_generation.elapsed_seconds の合計、<n> は len(rounds) です。 |
VLM review <t>s×<n> rounds | <t> は rounds[].timing.vlm_review.elapsed_seconds の合計(このフィールドが存在するラウンドのみ)、<n> は VLM レビューを行ったラウンド数です。max_rounds=1(VLM レビューが行われない場合)は、セグメント全体を省略します。 |
Images (sent in rank order) | セクション見出しです。画像の配信自体は、ホストランタイムのチャネル規約に従います。 |
呼び出し関係
- 最下層の依存関係:
sn-image-base→sn-image-generate、sn-image-recognize、sn-text-optimize
参考資料
references/analysis-framework.md- 分析手法references/base-prompt.md- プロンプトテンプレートreferences/evaluation-standard.md- 評価基準references/layout-style-selection.md- レイアウトとスタイルの選択ルールreferences/prompts-expand-system.md- プロンプト拡張システムプロンプトreferences/prompts-critic-system.md- プロンプト批評システムプロンプトreferences/runtime-parameters.md- ランタイムパラメーターreferences/structured-content-template.md- 構造化コンテンツテンプレートreferences/layouts/<layout>.md- レイアウト定義(87種類)references/styles/<style>.md- スタイル定義(66種類)
(Step 2.3 では)選択されたレイアウト/スタイルファイルのみを読み込みます。選択のためにこの2つのディレクトリをまとめて読み込まないでください。選択は名前レベルでランダムに行われます(Step 2.1)。