app:
  description: IT・開発向け SLO/SLAレポート生成ワークフロー。直近期間の稼働率・レスポンスタイム・エラーレートとSLO目標値を入力として、SLO達成状況、エラーバジェット消費率と残量、未達成原因分析、顧客向けSLA文面、改善推奨アクションを生成します。バジェット消費50%超のSLIには警告を表示します。
  icon: 📈
  icon_background: '#FFEAD5'
  mode: workflow
  name: SLO/SLAレポート生成
  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-code1
      source: extractor1
      target: code1
    - data:
        sourceType: code
        targetType: llm
      id: code1-to-llm1
      source: code1
      target: llm1
    - data:
        sourceType: llm
        targetType: end
      id: llm1-to-end
      source: llm1
      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: period
          type: string
          description: '対象期間（例: 2026-03-01 〜 2026-03-31）'
          required: true
        - name: uptime_pct
          type: number
          description: '稼働率（%）。例: 99.95'
          required: true
        - name: uptime_slo_pct
          type: number
          description: '稼働率SLO（%）。例: 99.9'
          required: true
        - name: response_time_ms
          type: number
          description: '平均レスポンスタイム（ms）。例: 250'
          required: true
        - name: response_time_slo_ms
          type: number
          description: 'レスポンスタイムSLO閾値（ms）。例: 300'
          required: true
        - name: error_rate_pct
          type: number
          description: 'エラーレート（%）。例: 0.5'
          required: true
        - name: error_rate_slo_pct
          type: number
          description: 'エラーレートSLO（%）。例: 1.0'
          required: true
        - name: notes
          type: string
          description: 追加メモ（任意）
          required: false
        reasoning_mode: prompt
        instruction: ユーザー入力テキストから対象期間・各SLIの実績値とSLO目標値を抽出してください。数値は可能な限り数値型で返してください。
      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    # ユーザー入力（parameter-extractorの出力）を受け取ってSLO判定とバジェット消費率を計算して返す\n\
          \    def to_float(v):\n        try:\n            return float(v)\n     \
          \   except Exception:\n            return 0.0\n    period = inputs.get(\"\
          period\", \"\")\n    uptime_pct = to_float(inputs.get(\"uptime_pct\", 0))\n\
          \    uptime_slo = to_float(inputs.get(\"uptime_slo_pct\", 0))\n    response_ms\
          \ = to_float(inputs.get(\"response_time_ms\", 0))\n    response_slo = to_float(inputs.get(\"\
          response_time_slo_ms\", 0))\n    error_pct = to_float(inputs.get(\"error_rate_pct\"\
          , 0))\n    error_slo = to_float(inputs.get(\"error_rate_slo_pct\", 0))\n\
          \    notes = inputs.get(\"notes\", \"\")\n    # SLO判定\n    uptime_met =\
          \ uptime_pct >= uptime_slo\n    response_met = response_ms <= response_slo\n\
          \    error_met = error_pct <= error_slo\n    # 消費率計算（上が良い指標と下が良い指標で計算方法を分ける）\n\
          \    def compute_consumption_higher_is_better(metric, slo):\n        # uptimeなど「高いほど良い」指標用\n\
          \        try:\n            metric_f = float(metric)\n            slo_f =\
          \ float(slo)\n        except Exception:\n            return 0.0\n      \
          \  if metric_f >= slo_f:\n            return 0.0\n        allowed = 100.0\
          \ - slo_f\n        if allowed <= 0.0:\n            return 100.0\n      \
          \  consumed = max(0.0, slo_f - metric_f)\n        consumption = consumed\
          \ / allowed * 100.0\n        if consumption > 100.0:\n            consumption\
          \ = 100.0\n        return consumption\n    def compute_consumption_lower_is_better(metric,\
          \ slo):\n        # エラーレートやレスポンスタイムなど「低いほど良い」指標用\n        try:\n        \
          \    metric_f = float(metric)\n            slo_f = float(slo)\n        except\
          \ Exception:\n            return 0.0\n        if metric_f <= slo_f:\n  \
          \          return 0.0\n        if slo_f <= 0.0:\n            return 100.0\n\
          \        consumed = max(0.0, metric_f - slo_f)\n        consumption = consumed\
          \ / slo_f * 100.0\n        if consumption > 100.0:\n            consumption\
          \ = 100.0\n        return consumption\n    cons_uptime = compute_consumption_higher_is_better(uptime_pct,\
          \ uptime_slo)\n    cons_response = compute_consumption_lower_is_better(response_ms,\
          \ response_slo)\n    cons_error = compute_consumption_lower_is_better(error_pct,\
          \ error_slo)\n    rem_uptime = max(0.0, 100.0 - cons_uptime)\n    rem_response\
          \ = max(0.0, 100.0 - cons_response)\n    rem_error = max(0.0, 100.0 - cons_error)\n\
          \    warning = (cons_uptime > 50.0) or (cons_response > 50.0) or (cons_error\
          \ > 50.0)\n    metrics = dict(\n        period=period,\n        uptime=dict(actual=round(uptime_pct,\
          \ 4), slo=round(uptime_slo, 4), met=bool(uptime_met), consumption=round(cons_uptime,\
          \ 2), remaining=round(rem_uptime, 2)),\n        response_time=dict(actual=round(response_ms,\
          \ 4), slo=round(response_slo, 4), met=bool(response_met), consumption=round(cons_response,\
          \ 2), remaining=round(rem_response, 2)),\n        error_rate=dict(actual=round(error_pct,\
          \ 4), slo=round(error_slo, 4), met=bool(error_met), consumption=round(cons_error,\
          \ 2), remaining=round(rem_error, 2)),\n        notes=str(notes),\n     \
          \   any_warning=bool(warning)\n    )\n    return dict(metrics=metrics)\n"
        variables:
        - value_selector:
          - extractor1
          - period
          variable: period
        - value_selector:
          - extractor1
          - uptime_pct
          variable: uptime_pct
        - value_selector:
          - extractor1
          - uptime_slo_pct
          variable: uptime_slo_pct
        - value_selector:
          - extractor1
          - response_time_ms
          variable: response_time_ms
        - value_selector:
          - extractor1
          - response_time_slo_ms
          variable: response_time_slo_ms
        - value_selector:
          - extractor1
          - error_rate_pct
          variable: error_rate_pct
        - value_selector:
          - extractor1
          - error_rate_slo_pct
          variable: error_rate_slo_pct
        - value_selector:
          - extractor1
          - notes
          variable: notes
        outputs:
          metrics:
            type: object
            children: null
      height: 90
      id: code1
      position:
        x: 680
        y: 282
      type: custom
      width: 244
    - data:
        title: AIレポート生成
        type: llm
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.2
        prompt_template:
        - role: system
          text: 'あなたはSRE・信頼性エンジニアとして、与えられたSLOメトリクスと計算結果から客観的かつ分かりやすいSLO/SLAレポートを作成してください。


            ---


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

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

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

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

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

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

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


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

            に変換してください。)'
        - role: user
          text: '入力テキスト: {{#start.query#}}


            解析済みメトリクス（自動計算結果）:

            {{#code1.metrics#}}


            出力要件:

            1) 各SLIごとのSLO達成状況（達成/未達成）

            2) 各SLIのエラーバジェット消費率と残量（%表示）

            3) 未達成SLOについての原因分析（根拠付き）

            4) 顧客向けSLAレポート文面（短く明確に）

            5) 改善推奨アクション（優先度付き）


            注意:

            - バジェット消費率が50%を超えるSLIには明確に警告を含めてください。

            - 出力は日本語で、見出し付きのレポート形式で分かりやすく作成してください。'
        vision:
          enabled: false
        memory: null
        context:
          enabled: false
      height: 90
      id: llm1
      position:
        x: 980
        y: 282
      type: custom
      width: 244
    - data:
        title: 終了
        type: end
        outputs:
        - value_selector:
          - llm1
          - text
          variable: result
      height: 90
      id: end
      position:
        x: 1280
        y: 282
      type: custom
      width: 244
  hash: null
