CustomerInteraction v1.0
Schema Type: customer-interactionVersion: v1.0JSON Schema: https://schemas.platform.ontopix.ai/customer-interaction/v1.0.jsonViews: https://schemas.platform.ontopix.ai/customer-interaction/v1.0.views.json
Overview
CustomerInteraction provides a unified, event-based format for capturing customer interactions across multiple channels and modalities (audio, text, video, hybrid), with optional enrichment via metrics and semantic analysis.
The schema is designed for three primary uses:
- Storage and interchange — a canonical representation of any customer service interaction regardless of channel or source system
- LLM enrichment — a target for automated quality analysis, sentiment detection, topic extraction, and summarization
- Audit evaluation — the primary input for
audit-criteriapolicies, which evaluate interactions against structured quality indicators
Required fields
{
"schema_type": "customer-interaction",
"schema_version": "v1.0",
"id": "550e8400-e29b-41d4-a716-446655440000",
"source": {
"media": "text",
"channel": "whatsapp"
},
"time": {
"start": "2025-01-15T10:00:00Z"
},
"participants": [
{ "id": "p1", "role": "customer" }
],
"events": [
{
"id": "e1",
"type": "message",
"time_offset": { "start": 0.0 },
"participant_id": "p1",
"content": { "text": "Hello, I need help." }
}
]
}
Root-level field reference
| Field | Type | Required | Description |
|---|---|---|---|
schema_type | const "customer-interaction" | Yes | Schema type identifier |
schema_version | string | Yes | Version. Pattern: ^v\d+\.\d+(-(alpha|beta|rc)\d+)?$ |
id | string (minLength 1) | Yes | Unique interaction identifier (UUID recommended) |
source | object | Yes | Origin and technical context. See source. |
time | object | Yes | Temporal boundaries. See time. |
participants | array (min 1) | Yes | Participants in the interaction. See participants[]. |
events | array (min 1) | Yes | Chronological event stream. See events[]. |
languages | array | No | Detected languages with probability scores. See languages[]. |
summary | object | No | High-level interaction summary. See summary. |
metrics | object | No | Interaction-level quantitative metrics. See Metrics. |
analysis | object | No | Interaction-level qualitative analysis. See Analysis. |
metadata | object | No | Free-form key-value pairs (JsonValue values). |
source (required)
Origin and technical context of the interaction.
| Field | Type | Required | Description |
|---|---|---|---|
source.media | enum | Yes | Primary modality: audio, text, video, hybrid |
source.channel | string (minLength 1) | Yes | Specific channel, e.g. whatsapp, email, webchat, phone, sms |
source.synchronicity | enum | No | Interaction cadence: synchronous (live call/video), asynchronous (email/SMS), near-synchronous (chat/messaging) |
source.source_system | string | No | Upstream system or vendor (e.g. genesys, twilio, zendesk, salesforce) |
source.reference | string (uri) | No | External reference in the source system. URI-like format recommended (e.g. zendesk://ticket/12345, genesys://conversation/abc-def) |
source.raw_content | string (uri) | No | URI to the original raw content (e.g. s3://bucket/recordings/call.wav) |
source.references_base | string (uri) | No | URI prefix for resolving events[].references[].file paths. Example: s3://bucket/pkg-id/sources/. See events[].references[]. |
time (required)
Temporal boundaries of the interaction. Uses absolute ISO 8601 timestamps.
| Field | Type | Required | Description |
|---|---|---|---|
time.start | string (date-time) | Yes | ISO 8601 timestamp when the interaction started |
time.end | string (date-time) | No | ISO 8601 timestamp when the interaction ended |
time.duration | number (≥ 0) | No | Duration in seconds (may be derived from start/end or independently measured) |
participants[] (required, min 1)
Each participant represents an actor in the interaction. Two orthogonal fields capture participant identity:
role(required): which side of the interaction the participant represents (business semantics)actor_type(optional): how the participant operates (technical implementation)
This separation enables consistent analytics across mixed human/bot interactions — e.g., filtering all customer_support participants regardless of whether they are human agents, IVRs, or AI bots.
role values
| Value | Meaning |
|---|---|
customer | The service consumer |
customer_support | The service provider (agents, bots, IVRs) |
system | Automated infrastructure (routing, notifications) |
unknown | Role not yet determined; to be inferred during enrichment |
actor_type values
| Value | Meaning |
|---|---|
human | A person |
ivr | Interactive Voice Response — DTMF-based voice menu |
interactive_menu | Text-based menu with structured options (buttons, quick replies) |
ai_agent | Conversational AI with natural language understanding |
automated | Automated process without interaction capability (auto-responders, notifications) |
ambient | Auditory presence without a producing agent — hold music, ringtones, IVR tones, silence, environmental noise. See Ambient participants. |
If actor_type is omitted, the implementation type is unknown or irrelevant.
Ambient participants
actor_type: "ambient" represents non-speech audio captured in a recording (hold music, ringtones, IVR tones, silence, background noise) — material that exists in the audio stream but is not produced by an agent participating in the conversation.
Channel attribution stays in role. Ambient audio is attributed to the side of the recording channel where it was captured, not collapsed into a synthetic neutral side:
- Hold music or IVR tones captured on the agent's channel →
role: "customer_support" - Background noise on the customer's side →
role: "customer" - Mono recordings without channel separation →
role: "unknown"
Events. Events referencing an ambient participant typically use type: "call_segment" (the segment is still part of the call; it just contains no speech). content.text carries a free-text bracketed label such as "[hold music]", "[ringtone]", "[silence]".
Consumer note. When an event's participant has actor_type: "ambient", its call_segment does not contain transcribed speech. Consumers performing speech analysis (sentiment, word counts, intent detection) should filter out events whose participant is ambient. For example: identify hold time as the cumulative duration of call_segment events whose participant has actor_type: "ambient" and role: "customer_support".
Example:
{
"participants": [
{ "id": "p1", "role": "customer", "actor_type": "human" },
{ "id": "p2", "role": "customer_support", "actor_type": "human" },
{ "id": "ambient-cs", "role": "customer_support", "actor_type": "ambient" }
],
"events": [
{
"id": "e1",
"type": "call_segment",
"time_offset": { "start": 60.0, "end": 180.0 },
"participant_id": "ambient-cs",
"content": { "text": "[hold music]" }
}
]
}
Participant fields
| Field | Type | Required | Description |
|---|---|---|---|
participants[].id | string (minLength 1) | Yes | Unique participant identifier (referenced by events[].participant_id) |
participants[].role | enum | Yes | See role values above |
participants[].actor_type | enum | No | See actor_type values above |
participants[].name | string | No | Display name |
participants[].identifiers | object | No | Map of external identifiers (e.g. email, phone, crm_id). Values are strings. |
participants[].metrics | object | No | Participant-level metrics (same shape as root metrics) |
participants[].analysis | object | No | Participant-level analysis signals (same shape as root analysis) |
participants[].metadata | object | No | Additional metadata. Values constrained to JsonValue. |
events[] (required, min 1)
events is the canonical timeline of the interaction. Each event belongs to exactly one participant and has a relative temporal position (time_offset) measured in seconds from interaction start.
Temporal model distinction:
- Root
timeuses absolute ISO 8601 timestamps for the overall interaction boundaries - Event
time_offsetuses relative seconds from interaction start for temporal positioning within the interaction
Event fields
| Field | Type | Required | Description |
|---|---|---|---|
events[].id | string (minLength 1) | Yes | Unique event identifier |
events[].type | enum | Yes | message, call_segment, system_notification, status_change |
events[].time_offset | object | Yes | Relative temporal position. See time_offset. |
events[].participant_id | string (minLength 1) | Yes | Reference to participants[].id |
events[].content | object | Yes | Event payload. See content. |
events[].metrics | object | No | Event-level metrics (same shape as root metrics) |
events[].analysis | object | No | Event-level analysis signals (same shape as root analysis) |
events[].language | string | No | ISO 639-1 language code for this specific event (e.g. "en", "es") |
events[].references | array | No | Source files used to derive this event. See events[].references[]. |
Event types
| Value | Use case |
|---|---|
message | Text-based communication (chat, email, SMS) |
call_segment | Speech-based communication (phone, video call) — may include word-level timing |
system_notification | Automated messages (queue updates, transfer notices, auto-replies) |
status_change | State transitions (queued → active → resolved) |
events[].time_offset
| Field | Type | Required | Description |
|---|---|---|---|
time_offset.start | number (≥ 0) | Yes | Start offset in seconds from interaction start |
time_offset.end | number (≥ 0) | No | End offset in seconds from interaction start |
time_offset.duration | number (≥ 0) | No | Duration in seconds |
events[].content
| Field | Type | Required | Description |
|---|---|---|---|
content.subject | string (minLength 1) | No | Subject line of the event (e.g. email subject). Only meaningful for channels that support subjects. |
content.text | string | Yes | Message text or speech transcript |
content.text_format | enum | No | plain (default), html, markdown, rich_text |
content.audio_url | string (uri) | No | URL to audio recording |
content.attachments[] | array | No | Attached files or media |
content.attachments[].url | string (uri) | Yes | Attachment URL |
content.attachments[].type | string | Yes | MIME type (e.g. image/png, application/pdf) |
content.attachments[].name | string | No | Original filename |
content.metadata | object | No | Event-level metadata (JsonValue values) |
content.words[] | array | No | Word-level timing alignment (for transcripts). See below. |
events[].content.words[]
Word-level timing data from speech transcription.
| Field | Type | Required | Description |
|---|---|---|---|
words[].text | string (minLength 1) | Yes | Word text |
words[].start_offset | number (≥ 0) | Yes | Start time in seconds from event start |
words[].end_offset | number (≥ 0) | Yes | End time in seconds from event start |
words[].confidence | number 0, 1 | No | Transcription confidence score |
events[].references[]
Per-event lineage: source files that were used to generate or derive this event. Distinct from events[].content.attachments[], which models files attached to the message itself (e.g. a PDF the customer sent in an email). Both arrays can coexist on the same event.
Paths in references[].file are resolved against source.references_base when present; otherwise they are opaque strings whose meaning is defined by the consumer (for example, the ELSA ZIP ingest pipeline treats them as relative to the package's sources/ directory).
| Field | Type | Required | Description |
|---|---|---|---|
references[].file | string (minLength 1) | Yes | Path to the source file. Resolved against source.references_base when present. |
references[].type | enum | Yes | Type of source: email, image, document, chat, audio, other. |
references[].rationale | string (minLength 1) | No | Free-text explanation of how this file was used. |
Example:
{
"id": "evt-001",
"type": "message",
"time_offset": { "start": 0 },
"participant_id": "agent-1",
"content": { "text": "Estimado cliente, en respuesta a su consulta..." },
"references": [
{ "file": "emails/01.eml", "type": "email", "rationale": "Body paragraph 2" },
{ "file": "notes/policy.md", "type": "document" }
]
}
languages[] (optional)
Detected languages with confidence scores for the entire interaction. Multiple entries represent code-switching or multi-lingual participants.
| Field | Type | Required | Description |
|---|---|---|---|
languages[].language | string | Yes | ISO 639-1 language code. Pattern: ^[a-z]{2}$ (e.g. en, es, fr) |
languages[].probability | number 0, 1 | Yes | Confidence score for language detection |
For per-event language annotation, use events[].language.
summary (optional)
High-level interaction summary distilling the entire conversation into key takeaways.
| Field | Type | Description |
|---|---|---|
summary.title | string | Human-readable title or subject (e.g. "Billing dispute - incorrect charge") |
summary.overview | string|null | 2–5 sentence narrative: what the customer wanted, what was done, what the outcome was |
summary.resolution_status | enum|null | resolved, unresolved, partial, escalated, pending, or null |
summary.key_topics[] | arraystring|null | Main topics discussed (e.g. ["billing", "refund"]) |
summary.interaction_flow[] | array|null | Ordered functional milestones referencing specific events. See below. |
summary.customer_satisfaction | object|null | Satisfaction measurement. See below. |
summary.interaction_flow[]
Each entry represents a functional milestone in the interaction, linked to a specific event.
| Field | Type | Required | Description |
|---|---|---|---|
interaction_flow[].event_id | string | Yes | Reference to events[].id. Any non-empty string (e.g. UUID or event_1). |
interaction_flow[].activity | enum | Yes | request, acknowledgment, information, action, resolution, escalation, handoff, follow_up, closure |
interaction_flow[].description | string | No | Human-readable description of this milestone |
summary.customer_satisfaction
| Field | Type | Required | Description |
|---|---|---|---|
customer_satisfaction.score | integer 0, 10 | Yes | Satisfaction score (0 = completely dissatisfied, 10 = completely satisfied) |
customer_satisfaction.collection_method | enum | No | survey (direct customer input), inferred (AI-estimated), agent_reported |
metadata (optional)
Free-form key-value pairs for session-level metadata. Values are constrained to JsonValue (any valid JSON type: string, number, boolean, null, object, array).
"metadata": {
"campaign_id": "PROMO-2024",
"customer_tier": "premium",
"priority_level": 3
}
Metrics (optional, transversal)
metrics appears at three levels with the same structure:
- root (
metrics): aggregated over the entire interaction participants[].metrics: aggregated per participantevents[].metrics: for the individual event
metrics is a flat map where:
- keys use dot-notation (e.g.
count.words,rate.words_per_minute) - values are objects:
{ "value": <number>, "unit": <string>, "context"?: <string> }
Custom metric keys must use the x. prefix (e.g. x.acme.my_metric).
Standard metrics
| Key | Unit | Value type | Applicable at | Description |
|---|---|---|---|---|
count.words | words | integer ≥ 0 | root, participant, event | Total words |
count.characters | characters | integer ≥ 0 | root, participant, event | Total characters |
count.syllables | syllables | integer ≥ 0 | root, participant, event | Total syllables |
count.messages | messages | integer ≥ 0 | root, participant | Total messages |
count.events | events | integer ≥ 0 | root, participant | Total events |
count.participants | participants | integer ≥ 0 | root only | Total participants |
count.interruptions | interruptions | integer ≥ 0 | root, participant | Interruption count |
time.response_seconds | seconds | number ≥ 0 | event only | Time to respond |
rate.words_per_minute | wpm | number ≥ 0 | root, participant, event | Speaking/typing rate |
rate.syllables_per_minute | spm | number ≥ 0 | root, participant, event | Syllable rate |
ratio.talk_time | ratio | number 0, 1 | root, participant | Proportion of time active |
avg.by_message.words | words/message | number ≥ 0 | root, participant | Average words per message |
avg.by_message.syllables | syllables/message | number ≥ 0 | root, participant | Average syllables per message |
avg.by_message.response_seconds | seconds/message | number ≥ 0 | root, participant | Average response time |
distribution.expressive_state.sentiment.<value> | ratio | number 0, 1 | root, participant | Distribution over positive, neutral, negative, null |
distribution.expressive_state.emotion.<value> | ratio | number 0, 1 | root, participant | Distribution over 13 emotions (see Analysis signals) |
distribution.expressive_state.urgency.<value> | ratio | number 0, 1 | root, participant | Distribution over low, medium, high, null |
distribution.expressive_state.clarity.<value> | ratio | number 0, 1 | root, participant | Distribution over clear, unclear, null |
distribution.communicative_intent.<label> | ratio | number 0, 1 | root, participant | Distribution over intent labels |
distribution.semantic_content.topics.<topic> | ratio | number 0, 1 | root, participant | Distribution over topic labels |
distribution.pragmatic_function.message_type.<value> | ratio | number 0, 1 | root, participant | Distribution over message types (see Analysis signals) |
Analysis (optional, transversal)
analysis appears at three levels with the same structure:
- root (
analysis): over the entire interaction participants[].analysis: per participantevents[].analysis: per event
analysis is a flat map where:
- keys use dot-notation (e.g.
expressive_state.sentiment,semantic_content.topics) - values are objects:
{ "value": <JsonValue>, "confidence"?: <0..1>, "context"?: <string> }
Custom analysis keys must use the x. prefix.
Standard analysis signals
| Key | Value type | Applicable at | Description |
|---|---|---|---|
expressive_state.sentiment | enum|null: positive, neutral, negative | root, participant, event | Overall sentiment polarity |
expressive_state.sentiment_score | number -1, 1 | root, participant, event | Continuous sentiment score |
expressive_state.emotion | enum|null | event only | Detected emotion: anger, anxiety, confusion, contempt, disgust, fear, frustration, gratitude, joy, neutral, relief, sadness, surprise |
expressive_state.tone | string|null | event only | Communicative tone (free-form) |
expressive_state.formality_level | enum|null: formal, informal, neutral, mixed | event only | Formality level |
expressive_state.urgency | enum|null: low, medium, high | event only | Perceived urgency |
expressive_state.clarity | enum|null: clear, unclear | event only | Message clarity |
communicative_intent | string (minLength 1) | root, participant, event | Detected communicative intent |
pragmatic_function.message_type | enum | event only | greeting, question, command, acknowledgment, response, statement, interjection, closing |
pragmatic_function.speech_act | string (pattern ^[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$) | event only | Speech act (controlled taxonomy) |
semantic_content.topics | arraystring | root, participant, event | Topics/themes detected |
semantic_content.key_points | arraystring | root, participant, event | Key points |
Available Views
| View | Description |
|---|---|
one-liner | Single-line identification: id, participant count, event count |
summary | Context-setting fields: id, channel, media, participants (id/role/name), event count, overview |
full | Complete object (identity projection) |
for-enrichment | Compact projection for LLM enrichment: id, channel, participants (id/role/name), events (id, participant_id, text) |
for-audit | Projection optimized for quality auditing: id, channel, media, participants (id/role), events (id, type, participant_id, text, offset) |
Examples
Minimal valid document
{
"schema_type": "customer-interaction",
"schema_version": "v1.0",
"id": "550e8400-e29b-41d4-a716-446655440000",
"source": {
"media": "text",
"channel": "whatsapp"
},
"time": {
"start": "2025-12-29T10:00:00Z"
},
"participants": [
{ "id": "p1", "role": "customer" },
{ "id": "p2", "role": "customer_support" }
],
"events": [
{
"id": "e1",
"type": "message",
"time_offset": { "start": 0.0 },
"participant_id": "p1",
"content": { "text": "Hola, tengo un problema con mi pedido." }
},
{
"id": "e2",
"type": "message",
"time_offset": { "start": 20.0 },
"participant_id": "p2",
"content": { "text": "Gracias, ¿me confirmas el número de pedido?" }
}
]
}
Complete document with enrichment
{
"schema_type": "customer-interaction",
"schema_version": "v1.0",
"id": "550e8400-e29b-41d4-a716-446655440000",
"source": {
"media": "text",
"channel": "whatsapp",
"synchronicity": "near-synchronous",
"source_system": "zendesk",
"reference": "zendesk://ticket/12345",
"references_base": "s3://elsa-ingest/pkg-abc123/sources/"
},
"time": {
"start": "2025-12-29T10:00:00Z",
"end": "2025-12-29T10:02:00Z",
"duration": 120
},
"participants": [
{
"id": "p1",
"role": "customer",
"actor_type": "human",
"name": "Alex",
"metrics": { "count.messages": { "value": 1, "unit": "messages" } },
"analysis": {
"expressive_state.sentiment": { "value": "neutral", "confidence": 0.72 }
}
},
{
"id": "p2",
"role": "customer_support",
"actor_type": "human",
"name": "Sam",
"identifiers": { "employee_id": "AGT-1234" }
}
],
"events": [
{
"id": "e1",
"type": "message",
"time_offset": { "start": 0.0 },
"participant_id": "p1",
"content": {
"text": "Hola, tengo un problema con mi pedido.",
"metadata": { "order_id": "ORD-123" }
},
"metrics": {
"count.words": { "value": 8, "unit": "words" },
"time.response_seconds": { "value": 0, "unit": "seconds" }
},
"analysis": {
"expressive_state.sentiment": { "value": "neutral", "confidence": 0.72 },
"expressive_state.urgency": { "value": "medium", "confidence": 0.65 },
"pragmatic_function.message_type": { "value": "request" }
},
"language": "es",
"references": [
{ "file": "chats/whatsapp-thread.json", "type": "chat", "rationale": "Original customer message" }
]
},
{
"id": "e2",
"type": "message",
"time_offset": { "start": 20.0 },
"participant_id": "p2",
"content": { "text": "Gracias, ¿me confirmas el número de pedido?" },
"metrics": {
"count.words": { "value": 9, "unit": "words" },
"time.response_seconds": { "value": 20, "unit": "seconds" }
},
"analysis": {
"pragmatic_function.message_type": { "value": "question" }
}
}
],
"languages": [{ "language": "es", "probability": 0.99 }],
"summary": {
"title": "Order issue inquiry",
"overview": "Customer asked for help with an order; agent requested order number.",
"resolution_status": "pending",
"key_topics": ["order", "support"],
"interaction_flow": [
{ "event_id": "event_1", "activity": "request" },
{ "event_id": "event_2", "activity": "acknowledgment" }
],
"customer_satisfaction": {
"score": 8,
"collection_method": "survey"
}
},
"metrics": {
"count.messages": { "value": 2, "unit": "messages" },
"count.words": { "value": 17, "unit": "words" },
"distribution.expressive_state.sentiment.neutral": { "value": 1.0, "unit": "ratio" },
"distribution.semantic_content.topics.order": { "value": 0.6, "unit": "ratio" },
"distribution.semantic_content.topics.support": { "value": 0.4, "unit": "ratio" }
},
"analysis": {
"semantic_content.topics": { "value": ["order", "support"] },
"expressive_state.sentiment": { "value": "neutral", "confidence": 0.72 }
}
}
Multi-participant with IVR, AI, and human agent
{
"schema_type": "customer-interaction",
"schema_version": "v1.0",
"id": "interaction-complex-001",
"source": { "media": "hybrid", "channel": "phone", "source_system": "genesys" },
"time": {
"start": "2025-12-30T09:00:00Z",
"end": "2025-12-30T09:10:00Z",
"duration": 600
},
"participants": [
{ "id": "p1", "role": "customer", "actor_type": "human", "name": "Maria García", "identifiers": { "phone": "+34600123456" } },
{ "id": "p2", "role": "customer_support", "actor_type": "ivr", "name": "Main IVR Menu" },
{ "id": "p3", "role": "customer_support", "actor_type": "ai_agent", "name": "Virtual Assistant" },
{ "id": "p4", "role": "customer_support", "actor_type": "human", "name": "Agent Carlos", "identifiers": { "employee_id": "AGT-1234" } },
{ "id": "p5", "role": "system", "name": "Call Router" }
],
"events": [
{ "id": "e1", "type": "system_notification", "time_offset": { "start": 0.0 }, "participant_id": "p5", "content": { "text": "Call initiated and routed to IVR" } },
{ "id": "e2", "type": "message", "time_offset": { "start": 5.0 }, "participant_id": "p2", "content": { "text": "Welcome. Press 1 for billing, 2 for technical support." } },
{ "id": "e3", "type": "message", "time_offset": { "start": 15.0 }, "participant_id": "p1", "content": { "text": "2" } },
{ "id": "e4", "type": "system_notification", "time_offset": { "start": 20.0 }, "participant_id": "p5", "content": { "text": "Transferred to AI assistant" } },
{ "id": "e5", "type": "message", "time_offset": { "start": 25.0 }, "participant_id": "p3", "content": { "text": "Hello! What technical issue are you experiencing?" } },
{ "id": "e6", "type": "message", "time_offset": { "start": 35.0 }, "participant_id": "p1", "content": { "text": "My internet keeps dropping every few minutes." } },
{ "id": "e7", "type": "message", "time_offset": { "start": 45.0 }, "participant_id": "p3", "content": { "text": "Let me connect you with a specialist." } },
{ "id": "e8", "type": "system_notification", "time_offset": { "start": 50.0 }, "participant_id": "p5", "content": { "text": "Escalated to human agent" } },
{ "id": "e9", "type": "message", "time_offset": { "start": 60.0 }, "participant_id": "p4", "content": { "text": "Hi Maria, I'm Carlos. Let me check your service status." } }
]
}
This example shows:
customer+human: the callercustomer_support+ivr: initial voice routingcustomer_support+ai_agent: conversational triage botcustomer_support+human: specialist agentsystem: infrastructure router
Analytics can filter by role ("all customer_support"), actor_type ("compare human vs ai_agent"), or both.
Migration from v1.0-beta1
No breaking changes. All v1.0-beta1 data is valid v1.0 data.
New field in v1.0: events[].language (optional, ISO 639-1 string). Previously, per-event language could only be stored in events[].analysis as a custom field. The new events[].language provides a canonical location for this annotation.
Additive updates within v1.0
The v1.0 schema has received additive enum extensions since first publication. All previously valid documents remain valid; consumers that strictly validate enum membership should accept the new values gracefully.
participants[].actor_type: added"ambient"for non-speech audio captured in recordings (hold music, ringtones, IVR tones, silence, background noise). See Ambient participants.expressive_state.formality_level: added"neutral"(in addition toformal,informal,mixed).summary.interaction_flow[].event_id: relaxed to allow any non-empty string (UUID or any application-defined identifier).source.references_baseandevents[].references[]: added optional per-event source-file lineage.events[].references[]is an array of{ file, type, rationale? }objects recording which source materials were used to derive each event;source.references_baseis an optional URI prefix used to resolve relativefilepaths. Distinct fromevents[].content.attachments[](which models files attached to the message itself). Seeevents[].references[].