app:
  description: '負荷テスト計画書とk6スクリプトを生成します。非機能要件（目標スループット・レスポンスタイム・同時接続数）とテスト対象エンドポイントを入力してください。出力:
    (1)テスト計画書、(2)k6スクリプト、(3)モニタリング項目、(4)判定基準。前回のタイムアウトを防ぐため生成を分割しています。'
  icon: 🧪
  icon_background: '#FFEAD5'
  mode: workflow
  name: 負荷テスト計画書 & k6スクリプト生成
  use_icon_as_answer_icon: false
kind: app
version: 0.6.0
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      image:
        enabled: false
    opening_statement: ''
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
  graph:
    edges:
    - data:
        sourceType: start
        targetType: parameter-extractor
      id: start-to-extractor1
      source: start
      target: extractor1
    - data:
        sourceType: parameter-extractor
        targetType: code
      id: extractor1-to-prepare1
      source: extractor1
      target: prepare1
    - data:
        sourceType: code
        targetType: llm
      id: prepare1-to-llm_plan
      source: prepare1
      target: llm_plan
    - data:
        sourceType: code
        targetType: llm
      id: prepare1-to-llm_k6
      source: prepare1
      target: llm_k6
    - data:
        sourceType: llm
        targetType: code
      id: llm_plan-to-assemble1
      source: llm_plan
      target: assemble1
    - data:
        sourceType: llm
        targetType: code
      id: llm_k6-to-assemble1
      source: llm_k6
      target: assemble1
    - data:
        sourceType: code
        targetType: end
      id: assemble1-to-end
      source: assemble1
      target: end
    nodes:
    - data:
        title: 開始
        type: start
        variables:
        - label: query
          max_length: 2048
          options: []
          required: true
          type: paragraph
          variable: query
      height: 90
      id: start
      position:
        x: 80
        y: 282
      type: custom
      width: 244
    - data:
        title: パラメータ抽出
        type: parameter-extractor
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
        query:
        - start
        - query
        parameters:
        - name: target_throughput
          type: number
          description: 目標スループット (requests per second)
          required: true
        - name: max_response_time_ms
          type: number
          description: 目標レスポンスタイム (ミリ秒)
          required: true
        - name: concurrent_users
          type: number
          description: 同時接続数
          required: true
        - name: endpoints
          type: string
          description: テスト対象エンドポイント（カンマ区切り）
          required: true
        - name: test_duration_min
          type: number
          description: テスト継続時間（分）
          required: false
        reasoning_mode: prompt
        instruction: ユーザー入力から上記パラメータを抽出してください。endpointsはカンマ区切りの文字列で返してください。未指定項目は空にしてください。
      height: 90
      id: extractor1
      position:
        x: 380
        y: 282
      type: custom
      width: 244
    - data:
        title: 入力整形
        type: code
        code_language: python3
        code: "def _safe_str(v):\n    \"\"\"Convert any value to string safely.\"\"\
          \"\n    if v is None:\n        return \"\"\n    if isinstance(v, list):\n\
          \        return \"\\n\".join(str(i) for i in v)\n    return str(v)\n\ndef\
          \ _safe_list(v):\n    \"\"\"Ensure value is a list.\"\"\"\n    if v is None:\n\
          \        return []\n    if isinstance(v, str):\n        return [v]\n   \
          \ if isinstance(v, list):\n        return v\n    return [v]\n\ndef main(**kwargs)\
          \ -> dict:\n    inputs = kwargs\n    # 入力項目を受け取り、LLMに渡すための整形テキストを作成する\n\
          \    throughput = inputs.get(\"throughput\")\n    response_ms = inputs.get(\"\
          max_response_time_ms\")\n    users = inputs.get(\"concurrent_users\")\n\
          \    endpoints = inputs.get(\"endpoints\")\n    duration = inputs.get(\"\
          test_duration_min\")\n    # 安全に文字列化して改行区切りのテキストにする\n    s_throughput = \"\
          目標スループット (rps): \" + str(throughput)\n    s_response = \"目標レスポンスタイム (ms):\
          \ \" + str(response_ms)\n    s_users = \"同時接続数: \" + str(users)\n    s_endpoints\
          \ = \"エンドポイント(カンマ区切り): \" + str(endpoints)\n    s_duration = \"テスト継続時間 (分):\
          \ \" + (str(duration) if duration is not None and duration != \"\" else\
          \ \"未指定\")\n    result = s_throughput + \"\\n\" + s_response + \"\\n\" +\
          \ s_users + \"\\n\" + s_endpoints + \"\\n\" + s_duration\n    return dict(output=result)\n"
        variables:
        - value_selector:
          - extractor1
          - target_throughput
          variable: throughput
        - value_selector:
          - extractor1
          - max_response_time_ms
          variable: max_response_time_ms
        - value_selector:
          - extractor1
          - concurrent_users
          variable: concurrent_users
        - value_selector:
          - extractor1
          - endpoints
          variable: endpoints
        - value_selector:
          - extractor1
          - test_duration_min
          variable: test_duration_min
        outputs:
          output:
            type: string
            children: null
      height: 90
      id: prepare1
      position:
        x: 680
        y: 282
      type: custom
      width: 244
    - data:
        title: テスト計画・監視・判定生成
        type: llm
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.2
        prompt_template:
        - role: system
          text: 'あなたは負荷テストエンジニアです。前回の試行でタイムアウトが発生したため、出力は読みやすくセクションで明確に分け、冗長を避けてください。k6スクリプトは別ノードで生成します。


            ---


            【最終出力フォーマット (この指示が最優先)】

            最終出力は **読みやすい日本語の Markdown** で返してください。JSON

            配列・オブジェクトをそのまま出力してはいけません。

            - 見出し (## / ###) でセクションを区切る

            - リスト (- / 1.) や表 (| ... |) で構造化

            - 各項目の意図や根拠が分かるよう短い説明文を添える

            - 営業デモで顧客に直接見せられる体裁にする


            (構造化されたデータ項目を内部で扱うのは構いませんが、出力時に Markdown

            に変換してください。)'
        - role: user
          text: '入力（整形済み）:

            {{#prepare1.output#}}


            出力フォーマット:

            1) テスト計画（シナリオ、成功基準、テスト環境要件）

            2) モニタリング項目（優先度付けとしきい値の目安）

            3) 判定基準（成功/失敗の判定ロジック）


            要求: 簡潔かつ実践的に箇条書きで出力してください。必要に応じて推奨値を示してください。'
        vision:
          enabled: false
        memory: null
        context:
          enabled: false
      height: 90
      id: llm_plan
      position:
        x: 980
        y: 282
      type: custom
      width: 244
    - data:
        title: k6スクリプト生成
        type: llm
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.2
        prompt_template:
        - role: system
          text: 'あなたはk6での負荷テストスクリプト作成の専門家です。出力は必ず実行可能なk6のJavaScriptコードのみを返してください（余分な説明は付けないでください）。


            ---


            【最終出力フォーマット (この指示が最優先)】

            最終出力は **読みやすい日本語の Markdown** で返してください。JSON

            配列・オブジェクトをそのまま出力してはいけません。

            - 見出し (## / ###) でセクションを区切る

            - リスト (- / 1.) や表 (| ... |) で構造化

            - 各項目の意図や根拠が分かるよう短い説明文を添える

            - 営業デモで顧客に直接見せられる体裁にする


            (構造化されたデータ項目を内部で扱うのは構いませんが、出力時に Markdown

            に変換してください。)'
        - role: user
          text: '入力（整形済み）:

            {{#prepare1.output#}}


            仕様:

            - フェーズ: ramp-up, steady, spike を含む

            - ramp-upとsteadyの時間・VU数は入力の同時接続数とスループットを考慮して決定

            - 各フェーズの説明をコメントとしてコード内に入れてください


            出力: 実行可能なk6スクリプト（JavaScript）だけを返してください。'
        vision:
          enabled: false
        memory: null
        context:
          enabled: false
      height: 90
      id: llm_k6
      position:
        x: 1280
        y: 282
      type: custom
      width: 244
    - data:
        title: 最終出力組立
        type: code
        code_language: python3
        code: "def main(**kwargs) -> dict:\n    candidates = ['llm_text_0', 'llm_text_1']\n\
          \    text = ''\n    for name in candidates:\n        v = kwargs.get(name)\n\
          \        if v:\n            text = str(v)\n            break\n    return\
          \ {\n        'output': text,\n    }\n"
        variables:
        - value_selector:
          - llm_plan
          - text
          variable: llm_text_0
        - value_selector:
          - llm_k6
          - text
          variable: llm_text_1
        outputs:
          output:
            type: string
            children: null
      height: 90
      id: assemble1
      position:
        x: 1580
        y: 282
      type: custom
      width: 244
    - data:
        title: 終了
        type: end
        outputs:
        - value_selector:
          - assemble1
          - output
          variable: result
      height: 90
      id: end
      position:
        x: 1880
        y: 282
      type: custom
      width: 244
  hash: null
