# Events, context, and diagnostics

> Wait for one event or stream many, build request context, and check a connection.

Source: https://docs.thalovant.com/developers/sdk-functions/events-and-context/

---
Part of [SDK Functions](/developers/sdk-functions/). Every call below is shown in each language that has it.

## Wait For One Event

Use this when one event proves the request completed.

  

```python
from thalovant import EVENT_UTTERANCE_HANDLED

event = client.wait_for_event(EVENT_UTTERANCE_HANDLED, timeout=12)
print(event.text)
```

  
  

```ts

const event = await client.waitForEvent(EVENT_UTTERANCE_HANDLED, {
  timeoutMs: 12_000,
});
console.log(event.text);
```

  
  

```go
event, err := client.WaitForEvent(ctx, thalovant.EventUtteranceHandled, thalovant.EventOptions{
    Timeout: 12 * time.Second,
})
if err != nil { return err }
fmt.Println(event.Name, event.Text())
```

  
  

```rust
use thalovant::{ListenOptions, EVENT_UTTERANCE_HANDLED};

let event = client.wait_for_event(EVENT_UTTERANCE_HANDLED, ListenOptions::default()).await?;
println!("{} {}", event.name, event.text());
```

  

## Stream Events

Use event streams for long-running clients, live status, speech output, and UI updates.

  

```python
from thalovant import EVENT_SPEAK

for event in client.listen(EVENT_SPEAK, timeout=30, max_events=3):
    print(event.text)
```

  
  

```ts

const subscription = client.on(EVENT_SPEAK, event => {
  console.log(event.text);
});

// Later, when the listener is no longer needed:
subscription.close();
```

  
  

```go
events, err := client.Listen(ctx, thalovant.EventSpeak, thalovant.ListenOptions{MaxEvents: 3})
if err != nil { return err }
defer events.Close()
for event := range events.C {
    fmt.Println(event.Name, event.Text())
}
if err := events.Err(); err != nil { return err }
```

  
  

```rust
use thalovant::{ListenOptions, EVENT_SPEAK};

let mut events = client.listen(EVENT_SPEAK, ListenOptions {
    max_events: Some(3), ..ListenOptions::default()
}).await?;
while let Some(event) = events.recv().await? {
    println!("{} {}", event.name, event.text());
}
```

  

## Build Request Context

Context carries stable user, source, locale, and trace metadata without changing the utterance.

  

```python
from thalovant import build_client_context

context = build_client_context(
    user_id="user-42",
    user_name="Ada",
    source="checkout-kiosk",
    platform="kiosk",
    locale="en-US",
    metadata={"trace_id": "req-2026-06-10-001"},
)

reply = client.ask("Show the next instruction.", context=context)
print(reply.text)
```

  
  

```ts

const context = buildClientContext({}, {
  userId: "user-42",
  userName: "Ada",
  source: "checkout-kiosk",
  platform: "kiosk",
  locale: "en-US",
  channel: "chat",
  metadata: { traceId: "req-2026-06-10-001" },
});

const reply = await client.ask("Show the next instruction.", { context });
console.log(reply.text);
```

  
  

```go
requestContext := thalovant.BuildClientContext(nil, thalovant.ClientContextOptions{
	UserID:   "user-42",
	UserName: "Ada",
	Source:   "checkout-kiosk",
	Platform: "kiosk",
	Locale:   "en-US",
	Channel:  "chat",
	Metadata: map[string]any{"trace_id": "req-2026-06-10-001"},
})

reply, err := client.Ask(ctx, "Show the next instruction.", thalovant.RequestOptions{
	Context: requestContext,
})
```

  
  

```rust
use serde_json::json;

let mut metadata = serde_json::Map::new();
metadata.insert("trace_id".into(), json!("req-2026-06-10-001"));

let context = build_client_context(None, ClientContextOptions {
    user_id: Some("user-42".into()),
    user_name: Some("Ada".into()),
    source: Some("checkout-kiosk".into()),
    platform: Some("kiosk".into()),
    locale: Some("en-US".into()),
    channel: Some("chat".into()),
    metadata: Some(metadata),
    ..Default::default()
});

let reply = client
    .ask(
        "Show the next instruction.",
        RequestOptions {
            context: Some(context),
            ..Default::default()
        },
    )
    .await?;
```

  

  Context should explain the request later. Do not put passwords, API tokens, full identity files, or private user profiles in request context.

## Run Diagnostics

Use diagnostics when a client cannot connect, a protocol is missing, or an event never arrives.

  

```python
print(client.doctor())
```

  
  

```ts
console.log(await client.healthcheck());
```

  
  

```go
fmt.Println(client.Healthcheck())
```

  
  

```rust
println!("{:?}", client.healthcheck().await);
```

  

## Protocol Values

Use the SDK protocol enum or string that matches your language.

| Protocol | Python | Node.js | Go | Rust |
| --- | --- | --- | --- | --- |
| WSS | `"wss"` | `"wss"` | `thalovant.ProtocolWSS` | `HubProtocol::Wss` |
| HTTPS | `"https"` | `"https"` | `thalovant.ProtocolHTTPS` | `HubProtocol::Https` |
| MQTT | `"mqtt"` | `"mqtt"` | `thalovant.ProtocolMQTT` | `HubProtocol::Mqtt` |

The automatic protocol selectors prefer WSS, then HTTPS, then MQTT when the identity includes broker credentials. Go's older `NewClient(identity)` and Rust's `Client::new(identity)` constructors select HTTPS directly; use `NewClientWithOptions` or `Client::auto` for automatic selection.

## Common Build Patterns

1. **Discover a hub.** Use `list_public_hubs`, `get_public_hub`, `list_hubs`, or `get_hub`.
2. **Create or load identity material.** Use `create_client_identity` for new clients, or load an existing identity from config, file, or environment.
3. **Choose a protocol.** Start with WSS unless your deployment needs HTTPS or MQTT.
4. **Send one request.** Use `ask` first because it gives a clear reply.
5. **Add events and context.** Add `listen`, `wait_for_event`, and `build_client_context` once the basic request works.
6. **Show what can be asked.** Use `intents` when the client should list the hub's intents and sentences per language.
