Events and the event system

Events are the primary mechanism through which the Newo platform triggers skill execution. Every user message, phone call, timer tick, API response, and inter-agent signal is represented as an event that flows through a subscription-based routing system to invoke the correct skill at the correct time.

What is an event?

An event is a structured notification that something has happened. When a user sends a chat message, the platform emits a user_message event. When a voice call connects, it emits conversation_started. When a timer fires, it emits timer. Each event carries an identifier, a set of arguments, and metadata that tell the platform what happened and provide context for the skill that will process it.

Events are the glue between the outside world and agent intelligence. Without events, skills would have no trigger -- they would never execute. The event system ensures that the right skill runs in response to the right stimulus, on the right integration, at the right time.

Event structure

Every event on the platform carries the following fields:

FieldTypeDescription
idnstrThe event identifier (e.g., user_message, conversation_started, timer). This is the primary key used for routing.
argumentsdict[str, str]Key-value payload carried with the event. For a user_message, this includes text. For a conversation_ended, it includes callSid, reason, and recordingUrl.
uninterruptibleboolWhen True, the skill triggered by this event must complete without being interrupted by subsequent events. Defaults to False.
external_event_idUUID or NoneAn external identifier assigned by the connector or caller. Used for deduplication and tracing.
command_act_idUUID or NoneLinks this event to a previously issued command, enabling request-response correlation (e.g., a result_success event referencing the command that initiated it).

The platform defines several standard event patterns:

Factory methodProduces event idnPurpose
as_result_success()result_successSignals that a command completed successfully. Carries a referenceIdn argument pointing to the originating command.
as_result_error()result_errorSignals that a command failed. Carries referenceIdn, errorType (user_error or server_error), and a message.
as_tool_called()tool_calledEmitted during voice-to-voice (V2V) sessions when the LLM invokes a tool. Carries name and parameters.
as_conversation_ended()conversation_endedEmitted when a voice call ends. Carries callSid, reason, and recordingUrl.

Event subscription model

Events do not automatically invoke skills. A flow must explicitly subscribe to the events it wants to handle. Subscriptions are defined in the events section of a flow YAML file. Each subscription has the following fields:

FieldDescription
idnThe event identifier to subscribe to (must match the idn of the incoming event).
skill_selectorHow the target skill is determined. skill_idn means the skill is hardcoded in the subscription. skill_idn_from_state means the skill identifier is read from a flow state field at runtime.
skill_idnThe identifier of the skill to execute. Used when skill_selector is skill_idn.
state_idnThe identifier of the state field that holds the target skill name. Used when skill_selector is skill_idn_from_state.
integration_idnFilters the subscription to events from a specific integration (e.g., newo_voice, telegram). When null, the subscription matches events from any integration.
connector_idnFurther narrows the filter to a specific connector within the integration. When null, any connector on the matched integration qualifies.
interrupt_modeControls what happens when this event fires while the flow is already executing a skill. interrupt stops the current skill and starts the new one. queue waits for the current skill to finish, then runs. cancel discards the event if a skill is already running.

How event-to-skill routing works

When an event arrives, the platform evaluates every event subscription across all flows belonging to the target agent. A subscription matches when all of the following conditions are true:

  1. The subscription's idn equals the event's idn.
  2. If the subscription specifies an integration_idn, it must match the event's source integration.
  3. If the subscription specifies a connector_idn, it must match the event's source connector.

When a match is found, the platform resolves the target skill:

  • If skill_selector is skill_idn, the platform invokes the skill identified by skill_idn.
  • If skill_selector is skill_idn_from_state, the platform reads the current value of the state field identified by state_idn and uses that value as the skill identifier.

The interrupt_mode then determines execution timing relative to any already-running skill.

::: 🗒️ NOTE A single event can match multiple subscriptions across different flows within the same agent. Each matching subscription triggers its respective skill independently. This is how a conversation_started event can simultaneously initialize both the main conversation flow and the follow-up timer flow. :::

YAML event subscription configuration

Event subscriptions are declared in the events section of a flow YAML file. Below are annotated examples drawn from real Newo Agent Framework (NAF) flows.

Basic subscription: conversation started on Newo Chat

events:
  - idn: conversation_started
    skill_selector: skill_idn
    skill_idn: ConversationStartedSkill
    state_idn: null
    integration_idn: newo_chat
    connector_idn: null
    interrupt_mode: queue

This subscription listens for conversation_started events originating from the newo_chat integration, regardless of which connector. When triggered, it executes ConversationStartedSkill in queue mode.

Same event, different integrations

The same event identifier can be subscribed to multiple times with different integration filters. This is how a single flow handles the same logical event across different channels:

events:
  # Chat messages
  - idn: user_message
    skill_selector: skill_idn
    skill_idn: UserNewoChatReplySkill
    state_idn: null
    integration_idn: newo_chat
    connector_idn: newo_chat
    interrupt_mode: queue

  # SMS messages
  - idn: user_message
    skill_selector: skill_idn
    skill_idn: UserSMSReplySkill
    state_idn: null
    integration_idn: twilio_messenger
    connector_idn: sms_connector
    interrupt_mode: interrupt

  # Telegram messages
  - idn: user_message
    skill_selector: skill_idn
    skill_idn: UserTelegramReplySkill
    state_idn: null
    integration_idn: telegram
    connector_idn: telegram_connector
    interrupt_mode: interrupt

  # Voice messages (Newo Voice)
  - idn: user_message
    skill_selector: skill_idn_from_state
    skill_idn: null
    state_idn: phone_reply_skill
    integration_idn: newo_voice
    connector_idn: newo_voice_connector
    interrupt_mode: interrupt

Notice that the Newo Voice subscription uses skill_idn_from_state. The skill to execute is determined at runtime by reading the phone_reply_skill state field. This allows the agent to dynamically switch which skill handles voice messages based on the current conversation state.

Timer subscription

events:
  - idn: timer
    skill_selector: skill_idn
    skill_idn: FetchData
    state_idn: null
    integration_idn: program_timer
    connector_idn: data_injection_timer
    interrupt_mode: queue

Timer events come from the program_timer integration. The connector_idn identifies which specific timer fired, allowing a flow to subscribe to multiple timers with different handlers.

Integration response subscription

events:
  - idn: magic_browser_response
    skill_selector: skill_idn
    skill_idn: MWreceiveResponseSkill
    state_idn: null
    integration_idn: magic_browser
    connector_idn: magic_browser_connector
    interrupt_mode: queue

When a Magic Browser command finishes processing a web page, the platform emits a magic_browser_response event. This subscription routes that response to the appropriate processing skill.

Custom event subscription

events:
  - idn: end_session
    skill_selector: skill_idn
    skill_idn: EndSessionSkill
    state_idn: null
    integration_idn: system
    connector_idn: system
    interrupt_mode: queue

Custom events use integration_idn: system and connector_idn: system. The event identifier end_session is a custom event name defined by the application rather than a platform-standard event.

Event identifier reference

The table below lists all core event identifiers recognized by the Newo platform.

Conversation and session events

Event idnSource integration(s)DescriptionKey arguments
conversation_startednewo_chat, newo_voice, vapi, telegramFired when a new conversation begins -- a chat widget opens for the first time, a voice call is answered, or a Telegram user starts a chat.callSid, isSharedPhoneNumber (voice only)
conversation_endednewo_voice, vapiFired when a voice call terminates.callSid, reason, recordingUrl, callId
session_started(any)Fired when a new logical session begins within the platform.--
session_endedsystemFired (typically via SendSystemEvent) when a session ends. Carries analytics data.transcript, summary, category, workingHours, and many others

Message events

Event idnSource integration(s)DescriptionKey arguments
user_messagenewo_chat, newo_voice, vapi, telegram, twilio_messenger, sandbox, apiFired every time a user sends a message (text or transcribed voice).text, eosReason (voice only)
agent_message(any)Fired every time the agent sends a message. Used for tracking or post-processing agent responses.--

Call and voice events

Event idnSource integration(s)DescriptionKey arguments
call_abortednewo_voice, vapiFired when a user or agent hangs up the phone.--
call_endednewo_voice, vapiFired when a phone call cannot be started or finishes unexpectedly.--
user_speech_startednewo_voiceFired when the platform detects the user has begun speaking.--
user_speech_detectednewo_voiceFired during speech recognition with interim and final transcription results.text, isEnded, speaker, confidence
agent_speech_endednewo_voiceFired when the agent finishes speaking a response.--
agent_speech_startednewo_voiceFired when the agent begins speaking.--
user_message_transcription_finishednewo_voiceFired when the final transcription of a user's spoken turn is complete.--
tool_callednewo_voiceFired during V2V sessions when the LLM invokes a function/tool.name, parameters, callId

Response events

Event idnSource integration(s)DescriptionKey arguments
magic_http_responsehttpFired when the HTTP connector receives a response from a send_request command.Response body and headers
magic_api_responsemagic_apiFired when the Magic API connector receives a response from the target API.Response data
magic_browser_responsemagic_browserFired when the Magic Browser connector finishes processing a web page or action.Response data

Command result events

Event idnSource integration(s)DescriptionKey arguments
result_success(varies by command target)Fired when a previously issued command completes successfully.referenceIdn (the command that succeeded)
result_error(varies by command target)Fired when a previously issued command fails.referenceIdn, errorType, message

Timer events

Event idnSource integration(s)DescriptionKey arguments
timerprogram_timerFired when a programmable timer fires. The specific timer is identified by the connector_idn.--
follow_up_messageprogram_timerFired by the follow-up timer to prompt the agent to send a follow-up message.--
waiting_mode_fallbackprogram_timerFired as a fallback when the agent has been in waiting mode for too long.--

System and custom events

Event idnSource integration(s)DescriptionKey arguments
project_init(any)Fired when a project is initialized for the first time.--
project_publish_finishsystemFired when project publishing completes.--
interruptnewo_voiceFired when the user interrupts the agent during speech.streamId
interrupt_mode_changednewo_voiceFired when the interrupt mode setting changes.interruptMode
(custom)systemAny custom event emitted via SendSystemEvent. The idn is whatever string the developer specifies.Developer-defined

::: 🗒️ NOTE This list covers the core platform events. Custom events with arbitrary identifiers can be created using the SendSystemEvent action. See the section below for details. :::

Connector event payloads

When events arrive from external connectors (such as webhooks), they carry additional routing metadata:

FieldDescription
integration_idnThe integration this event originates from (e.g., api, telegram).
connector_idnThe specific connector instance (e.g., webhook, telegram_connector).
event_idnThe event identifier (e.g., user_message).
command_act_idLinks to a command if this event is a response to one.
user_actor_idThe actor ID of the user associated with this event.
external_event_idA caller-supplied UUID for tracing and deduplication.
argumentsA list of name-value pairs carrying the event payload.
uninterruptibleWhether the triggered skill should be protected from interruption.

Each argument in the arguments list is a name-value pair: name (string) and value (string).

Event emission pipeline

Understanding how events travel from their source to a skill helps clarify the system architecture. The sequence is:

  1. Source emits event -- A service (voice, webhooks, chat, timer, or another agent) creates an event and passes it to the event emitter.
  2. Event emitter serializes and dispatches -- The event emitter serializes the arguments and sends them to the Flow Runner.
  3. Flow Runner matches subscriptions -- The Flow Runner evaluates the incoming event against all subscriptions for the target agent. It checks idn, integration_idn, and connector_idn.
  4. Skill resolution -- For each matching subscription, the Flow Runner resolves the target skill (from skill_idn or from a state field).
  5. Interrupt mode evaluation -- The Flow Runner applies the interrupt_mode rule to determine whether to start immediately, queue, or cancel.
  6. Skill execution -- The resolved skill runs with access to the event's arguments via the GetTriggeredAct() action.
flowchart TD
    Source["Source<br/>voice · chat · webhook · timer · agent"] --> Event["Event<br/>idn + arguments"]
    Event --> Emitter["Event Emitter<br/>serializes arguments"]
    Emitter --> Runner["Flow Runner<br/>matches subscriptions"]
    Runner --> M1["Match subscription 1"] --> SA["Skill A<br/>interrupt mode"]
    Runner --> M2["Match subscription 2"] --> SB["Skill B<br/>queue mode"]
    Runner --> NoM["No match"] --> Ignored["event ignored"]

Custom events with SendSystemEvent

The SendSystemEvent action allows skills to emit arbitrary custom events. This is the primary mechanism for inter-agent communication, multi-step workflows, and application-defined signaling.

SendSystemEvent(
  eventIdn: str,
  connectorIdn: str = "system",
  actorIds: List[str] | None = None,
  global: Literal['true', 'false'] = 'false',
  uninterruptible: Literal['true', 'false'] | None = None,
  **arguments: str
)
ParameterDescription
eventIdnThe custom event identifier. Can be any string.
connectorIdnThe connector identifier for the event. Defaults to "system".
actorIdsList of actor IDs to send this event to. If omitted, the event targets the current actor.
globalIf "true", the event is broadcast globally. The actorIds parameter is ignored in this case.
uninterruptibleIf "true", the skill triggered by this event cannot be interrupted by subsequent events.
**argumentsAny additional keyword arguments are sent as event arguments (name-value pairs).

Sending a custom event

The following skill script emits a custom event called my_custom_event with four arguments:

{{SendSystemEvent(
    eventIdn="my_custom_event",
    last_user_message_text=GetTriggeredAct(fields=['text']),
    last_agent_message_text=RESULT,
    my_argument_1="MY ARGUMENT VALUE 1",
    my_argument_2="MY ARGUMENT VALUE 2"
)}}

Subscribing to a custom event

To handle the custom event, another flow subscribes with integration_idn: system and connector_idn: system:

events:
  - idn: my_custom_event
    skill_selector: skill_idn
    skill_idn: HandleCustomEventSkill
    state_idn: null
    integration_idn: system
    connector_idn: system
    interrupt_mode: queue

Reading event arguments in the receiving skill

The receiving skill retrieves the event's arguments using GetTriggeredAct:

{{set(name='act_info', value=GetTriggeredAct(fields=[
    'my_argument_1',
    'my_argument_2',
    'last_user_message_text',
    'last_agent_message_text'
]))}}

Real-world example: session ended event

The NAF uses SendSystemEvent extensively for inter-agent signaling. When a conversation session ends, the CAEndSessionFlow emits a session_ended event packed with analytics data:

{{SendSystemEvent(
    eventIdn="session_ended",
    connectorIdn="system",
    businessEmail=business_email,
    businessLabel=business_name,
    transcript=transcript,
    summary=summary,
    recordingUrls=recording_urls,
    workingHours=working_hours_status,
    category=category,
    success=success_classification,
    potentialRevenue=potential_revenue
)}}

Other agents and external systems can subscribe to this event to perform post-conversation processing -- updating CRM records, sending reports, triggering webhooks, and more.

::: ❗❗ IMPORTANT Custom events sent with SendSystemEvent use integration_idn: system and connector_idn: system by default. The receiving flow's event subscription must match these values, or the event will not be routed. :::

Integration-specific event mapping

Different integrations emit different subsets of events. The table below maps each integration to the events it can produce.

Integration idnEvents emitted
newo_chatconversation_started, user_message
newo_voiceconversation_started, conversation_ended, user_message, user_speech_started, user_speech_detected, agent_speech_ended, agent_speech_started, user_message_transcription_finished, tool_called, interrupt, interrupt_mode_changed, result_success, result_error
vapiconversation_started, conversation_ended, user_message, call_aborted, call_ended
telegramconversation_started, user_message
twilio_messengeruser_message, result_success
sandboxuser_message
apiuser_message
httpmagic_http_response
magic_apimagic_api_response
magic_browsermagic_browser_response
program_timertimer, follow_up_message, waiting_mode_fallback
systemAny custom event via SendSystemEvent

::: 🗒️ NOTE The result_success and result_error events can originate from any integration that supports commands. The integration listed in the event's source metadata corresponds to the integration where the original command was sent. :::

Interrupt modes explained

The interrupt_mode field on an event subscription controls concurrency behavior within a flow. Choosing the right mode is critical for correct agent behavior.

ModeBehaviorUse when
interruptImmediately stops the currently running skill and starts the new one.The new event should take priority. Common for voice user_message events where the user's latest input supersedes whatever the agent was doing.
queueWaits for the currently running skill to finish, then executes the new skill.Both the current and new work are important. Common for conversation_ended and custom system events.
cancelDiscards the event entirely if a skill is already running.The event is only relevant when the flow is idle. Used for low-priority background signals.

In practice, the NAF uses interrupt for real-time user input on voice channels (where responsiveness is critical) and queue for most other events (where data integrity matters more than immediacy).

flowchart TD
    Arrives["New event arrives"] --> Check{"Is a skill<br/>already running?"}
    Check -->|No| Start["Start skill immediately"]
    Check -->|Yes| Mode{"interrupt_mode?"}
    Mode -->|interrupt| StopStart["Stop current skill<br/>Start new skill now"]
    Mode -->|queue| WaitRun["Wait for current skill<br/>to finish, then start"]
    Mode -->|cancel| Drop["Discard event"]

Further reading

  • See Integrations and connectors for details on integration types, connector configuration, and how events relate to the outgoing_events_descriptions field.
  • See Agents and the multi-agent system for how events enable inter-agent communication within the NAF.
  • See SendSystemEvent in the Actions reference for the full action specification and additional examples.
  • See Event Identifier List for a quick-reference list of all event identifiers.