{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://docs.pipelines.tech/schemas/agent-response.json",
  "title": "Pipelines Agent Response (v1)",
  "description": "Body returned by a customer-hosted agent under Odyssey Agent Testing v1. final_response is required; messages and metadata enable the data explorer's rich trace mode. See https://docs.pipelines.tech/docs/agents/runtime-setup/porting-your-agent for the wire contract and rendering semantics.",
  "type": "object",
  "additionalProperties": true,
  "required": [
    "final_response"
  ],
  "properties": {
    "final_response": {
      "type": "string",
      "description": "The agent's terminal user-visible answer. One of several inputs the judge LLM scores against the user instruction (alongside the trajectory and the agent's last few messages). Strings over ~50,000 characters are truncated with a soft warning."
    },
    "messages": {
      "type": [
        "array",
        "null"
      ],
      "description": "Optional OpenAI-style transcript. Each entry is a role-tagged message; assistant messages may include tool_calls and an optional thinking sub-array for extended-reasoning blocks. Optional unless the agent is registered with response_mode=rich and strictness=strict, which requires a gradeable assistant message and fails the run when it is missing.",
      "items": {
        "$ref": "#/$defs/Message"
      }
    },
    "metadata": {
      "type": [
        "object",
        "null"
      ],
      "description": "Optional free-form runtime metadata. Common keys (model, system_prompt_id, total_input_tokens, total_output_tokens, agent_runtime_ms) get first-class rendering; unknown keys land in a generic key/value table.",
      "additionalProperties": true
    }
  },
  "$defs": {
    "Message": {
      "type": "object",
      "additionalProperties": true,
      "required": [
        "role"
      ],
      "properties": {
        "role": {
          "type": "string",
          "enum": [
            "system",
            "user",
            "assistant",
            "tool"
          ]
        },
        "content": {
          "description": "Plain string content, or an array of content parts (OpenAI / Anthropic multi-modal style). null is allowed for assistant messages that only emit tool_calls.",
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array"
            },
            {
              "type": "null"
            }
          ]
        },
        "tool_call_id": {
          "type": "string",
          "description": "Set on role='tool' messages."
        },
        "tool_calls": {
          "type": "array",
          "description": "OpenAI-style tool_calls on assistant turns. The platform accepts either the flat shape ({id?, name, arguments?}) or the OpenAI Chat Completions nested shape ({id?, type: 'function', function: {name, arguments?}}); nested entries are normalized to the flat shape on ingest so downstream consumers (judge prompt, trajectory timeline) only see {name, arguments?, id?}. Entries with no resolvable name (neither top-level 'name' nor 'function.name') are dropped with a soft warning.",
          "items": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true,
                "required": [
                  "name"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "arguments": {
                    "description": "Tool arguments \u2014 object preferred, string-encoded JSON also accepted (matches the OpenAI tool_use legacy shape)."
                  }
                }
              },
              {
                "type": "object",
                "additionalProperties": true,
                "required": [
                  "function"
                ],
                "description": "OpenAI Chat Completions nested shape. Normalized to the flat form on ingest.",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "type": {
                    "const": "function"
                  },
                  "function": {
                    "type": "object",
                    "additionalProperties": true,
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "arguments": {
                        "description": "Tool arguments \u2014 object preferred, string-encoded JSON also accepted."
                      }
                    }
                  }
                }
              }
            ]
          }
        },
        "thinking": {
          "type": "array",
          "description": "Reasoning blocks: Claude extended-thinking, OpenAI o1 reasoning summaries, custom CoT, etc. Each block has a free-form shape; the platform's renderer looks for a 'text' key, falling back to JSON dump.",
          "items": {
            "type": "object",
            "additionalProperties": true
          }
        }
      }
    }
  }
}
