{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://agentcall.smartycode.com/schemas/agentcall-events-0.1.schema.json",
  "title": "AgentCall normalized event envelope (0.1) - public NFC/photo profile",
  "description": "Public AgentCall 0.1 NFC/photo profile generated from canonical contracts. Only the reviewed dependency closure is published; see the release manifest and /ext/agentcall-agui/0.1 for negotiation and semantic validation duties.",
  "type": "object",
  "required": [
    "sequence",
    "event"
  ],
  "properties": {
    "sequence": {
      "type": "integer",
      "minimum": 1,
      "description": "Monotonic per-session server sequence. Every accepted event advances it, including heartbeats."
    },
    "event": {
      "$ref": "#/$defs/event"
    }
  },
  "$defs": {
    "event": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "maxLength": 64
        }
      },
      "oneOf": [
        {
          "$ref": "#/$defs/sessionEstablished"
        },
        {
          "$ref": "#/$defs/runStarted"
        },
        {
          "$ref": "#/$defs/runCompleted"
        },
        {
          "$ref": "#/$defs/textDelta"
        },
        {
          "$ref": "#/$defs/speechSegment"
        },
        {
          "$ref": "#/$defs/interactionRequested"
        },
        {
          "$ref": "#/$defs/interactionResolved"
        },
        {
          "$ref": "#/$defs/stateChanged"
        },
        {
          "$ref": "#/$defs/warning"
        },
        {
          "$ref": "#/$defs/failure"
        },
        {
          "$ref": "#/$defs/heartbeat"
        }
      ]
    },
    "segmentID": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128
    },
    "sessionEstablished": {
      "type": "object",
      "required": [
        "type",
        "resumed"
      ],
      "properties": {
        "type": {
          "const": "session.established"
        },
        "resumed": {
          "type": "boolean"
        },
        "resumeMode": {
          "type": "string",
          "enum": [
            "replay",
            "fresh"
          ],
          "description": "Additive; meaningful only with resumed=true. Absent or 'replay': buffered envelopes were re-sent before this event. 'fresh': the server had no record of the session (a process restart or an expired grace), re-established it against the same conversation, replayed nothing, and continued the client's sequence space from resumeFromSequence; any response in flight at the drop is gone."
        }
      }
    },
    "runStarted": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "run.started"
        }
      }
    },
    "runCompleted": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "run.completed"
        },
        "elapsedMs": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "textDelta": {
      "type": "object",
      "required": [
        "type",
        "text"
      ],
      "properties": {
        "type": {
          "const": "text.delta"
        },
        "text": {
          "type": "string",
          "maxLength": 65536
        }
      }
    },
    "speechSegment": {
      "type": "object",
      "required": [
        "type",
        "segmentId",
        "stable"
      ],
      "properties": {
        "type": {
          "const": "speech.segment"
        },
        "segmentId": {
          "$ref": "#/$defs/segmentID"
        },
        "text": {
          "type": "string",
          "maxLength": 65536
        },
        "stable": {
          "type": "boolean"
        }
      }
    },
    "interactionOption": {
      "type": "object",
      "required": [
        "id",
        "label"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "label": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "description": {
          "type": "string",
          "maxLength": 512
        }
      }
    },
    "interactionRequested": {
      "type": "object",
      "required": [
        "type",
        "interactionId",
        "prompt",
        "spokenPrompt",
        "options",
        "allowsFreeform",
        "kind"
      ],
      "properties": {
        "type": {
          "const": "interaction.requested"
        },
        "interactionId": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "kind": {
          "enum": [
            "physical.nfc.scan",
            "physical.photo.capture"
          ]
        },
        "prompt": {
          "type": "string",
          "minLength": 1,
          "maxLength": 4096
        },
        "spokenPrompt": {
          "type": "string",
          "minLength": 1,
          "maxLength": 4096
        },
        "options": {
          "type": "array",
          "maxItems": 0,
          "items": {
            "$ref": "#/$defs/interactionOption"
          }
        },
        "allowsFreeform": {
          "const": false
        },
        "stepIndex": {
          "type": "integer",
          "minimum": 1,
          "maximum": 8
        },
        "stepCount": {
          "type": "integer",
          "minimum": 1,
          "maximum": 8
        }
      }
    },
    "interactionResolved": {
      "type": "object",
      "required": [
        "type",
        "interactionId",
        "outcome"
      ],
      "properties": {
        "type": {
          "const": "interaction.resolved"
        },
        "interactionId": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "outcome": {
          "enum": [
            "answered",
            "cancelled",
            "withdrawn",
            "rejected"
          ]
        }
      }
    },
    "stateChanged": {
      "type": "object",
      "required": [
        "type",
        "state"
      ],
      "properties": {
        "type": {
          "const": "state.changed"
        },
        "state": {
          "type": "string",
          "maxLength": 64
        }
      }
    },
    "warning": {
      "type": "object",
      "required": [
        "type",
        "code"
      ],
      "properties": {
        "type": {
          "const": "warning"
        },
        "code": {
          "type": "string",
          "maxLength": 64
        },
        "segmentId": {
          "$ref": "#/$defs/segmentID"
        }
      }
    },
    "failure": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "failure"
        },
        "code": {
          "type": "string",
          "maxLength": 64
        },
        "message": {
          "type": "string",
          "maxLength": 2048
        }
      }
    },
    "heartbeat": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "heartbeat"
        }
      }
    }
  }
}
