theater 0.3.14

A WebAssembly actor system for AI agents
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
package theater:simple;

/// # Message Server Client Interface
///
/// Defines the callback handlers that actors must implement to receive messages through
/// the message server system.
///
/// ## Purpose
///
/// This interface enables actors to receive and process various types of messages:
/// - One-way messages (send)
/// - Request-response interactions (request)
/// - Bidirectional channel-based communication (channel operations)
///
/// By implementing these handler functions, an actor can participate in different
/// communication patterns with other actors and external systems.
///
/// ## Example
///
/// ```rust
/// use ntwk::theater::message_server_client::Guest;
/// use ntwk::theater::types::{channel_accept, channel_id};
/// use serde_json::{json, Value};
///
/// struct MyMessageHandler;
///
/// impl Guest for MyMessageHandler {
///     fn handle_send(state: Option<Value>, params: (Value,)) 
///             -> Result<(Option<Value>,), String> {
///         let (message,) = params;
///         println!("Received message: {}", message);
///         
///         // Update state if needed
///         let new_state = if let Some(mut state) = state {
///             state["message_count"] = json!(state["message_count"].as_u64().unwrap_or(0) + 1);
///             Some(state)
///         } else {
///             Some(json!({"message_count": 1}))
///         };
///         
///         Ok((new_state,))
///     }
///     
///     // Implement other handlers...
/// }
/// ```
///
/// ## Security
///
/// The message handlers receive input from potentially untrusted sources, so they should:
/// - Validate all incoming message data
/// - Handle malformed messages gracefully
/// - Protect against common attack vectors like JSON injection
///
/// ## Implementation Notes
///
/// - All handlers receive and can update the actor's state
/// - Errors returned from handlers are logged and may trigger supervision
/// - Handler execution is tracked in the actor's event chain
interface message-server-client {
    use types.{event, channel-id, channel-accept};

    /// # Handle one-way message
    ///
    /// Processes a one-way message that doesn't require a response.
    ///
    /// ## Parameters
    ///
    /// * `state` - The current actor state or None if not initialized
    /// * `params` - Tuple containing:
    ///   * `json` - The message payload
    ///
    /// ## Returns
    ///
    /// * `Ok((option<list<u8>>,))` - Updated actor state (or None to retain current state)
    /// * `Err(string)` - Error message if message handling fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// fn handle_send(state: Option<Value>, params: (Value,)) -> Result<(Option<Value>,), String> {
    ///     let (message,) = params;
    ///     
    ///     // Process the message...
    ///     
    ///     // Return updated state (or None to keep current state)
    ///     Ok((Some(updated_state),))
    /// }
    /// ```
    handle-send: func(state: option<list<u8>>, params: tuple<list<u8>>) -> result<tuple<option<list<u8>>>, string>;
    
    /// # Handle request-response message
    ///
    /// Processes a request that requires a response.
    ///
    /// ## Parameters
    ///
    /// * `state` - The current actor state or None if not initialized
    /// * `params` - Tuple containing:
    ///   * `string` - The request ID
    ///   * `json` - The request payload
    ///
    /// ## Returns
    ///
    /// * `Ok((option<list<u8>>, (option<list<u8>>,)))` - Tuple containing:
    ///   * Updated actor state (or None)
    ///   * Response message to send back (or None to send a response yet)
    /// * `Err(string)` - Error message if request handling fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// fn handle_request(state: Option<Vec<u8>>, params: (String, Vec<u8>)) 
    ///         -> Result<(Option<Vec<u8>>, (Option<Vec<u8>>,)), String> {
    ///     let (request_id, request) = params;
    ///     
    ///     // Process the request...
    ///     let response = json!({"status": "success", "data": "result"});
    ///     
    ///     // Return updated state and response
    ///     Ok((Some(updated_state), (Some(response),)))
    /// }
    /// ```
    handle-request: func(state: option<list<u8>>, params: tuple<string, list<u8>>) -> result<tuple<option<list<u8>>, tuple<option<list<u8>>>>, string>;
    
    /// # Handle channel open request
    ///
    /// Called when another actor requests to open a communication channel.
    ///
    /// ## Parameters
    ///
    /// * `state` - The current actor state or None if not initialized
    /// * `params` - Tuple containing:
    ///   * `json` - The initial message payload
    ///
    /// ## Returns
    ///
    /// * `Ok((option<list<u8>>, (channel-accept,)))` - Tuple containing:
    ///   * Updated actor state (or None to retain current state)
    ///   * Channel acceptance decision
    /// * `Err(string)` - Error message if open handling fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// fn handle_channel_open(state: Option<Value>, params: (Value,)) 
    ///         -> Result<(Option<Value>, (channel_accept,)), String> {
    ///     let (initial_message,) = params;
    ///     
    ///     // Decide whether to accept the channel
    ///     let accept = channel_accept {
    ///         accept: true,
    ///         error_message: None,
    ///     };
    ///     
    ///     // Return updated state and acceptance decision
    ///     Ok((Some(updated_state), (accept,)))
    /// }
    /// ```
    ///
    /// ## Security
    ///
    /// The actor should validate the channel request and only accept channels from
    /// trusted sources. The acceptance mechanism provides a security checkpoint.
    handle-channel-open: func(state: option<list<u8>>, params: tuple<string, list<u8>>) -> result<tuple<option<list<u8>>, tuple<channel-accept>>, string>;
    
    /// # Handle channel message
    ///
    /// Processes a message received on an established channel.
    ///
    /// ## Parameters
    ///
    /// * `state` - The current actor state or None if not initialized
    /// * `params` - Tuple containing:
    ///   * `channel-id` - ID of the channel the message was received on
    ///   * `json` - The message payload
    ///
    /// ## Returns
    ///
    /// * `Ok((option<list<u8>>,))` - Updated actor state (or None to retain current state)
    /// * `Err(string)` - Error message if message handling fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// fn handle_channel_message(state: Option<Value>, params: (channel_id, Value)) 
    ///         -> Result<(Option<Value>,), String> {
    ///     let (channel_id, message) = params;
    ///     
    ///     // Process the channel message...
    ///     println!("Received message on channel {}: {}", channel_id, message);
    ///     
    ///     // Return updated state (or None to keep current state)
    ///     Ok((Some(updated_state),))
    /// }
    /// ```
    handle-channel-message: func(state: option<list<u8>>, params: tuple<channel-id, list<u8>>) -> result<tuple<option<list<u8>>>, string>;
    
    /// # Handle channel close
    ///
    /// Called when a communication channel is closed.
    ///
    /// ## Parameters
    ///
    /// * `state` - The current actor state or None if not initialized
    /// * `params` - Tuple containing:
    ///   * `channel-id` - ID of the channel that was closed
    ///
    /// ## Returns
    ///
    /// * `Ok((option<list<u8>>,))` - Updated actor state (or None to retain current state)
    /// * `Err(string)` - Error message if close handling fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// fn handle_channel_close(state: Option<Value>, params: (channel_id,)) 
    ///         -> Result<(Option<Value>,), String> {
    ///     let (channel_id,) = params;
    ///     
    ///     // Clean up any resources associated with the channel
    ///     println!("Channel {} closed", channel_id);
    ///     
    ///     // Return updated state (or None to keep current state)
    ///     Ok((Some(updated_state),))
    /// }
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// This function should perform any necessary cleanup for the closed channel,
    /// such as releasing resources or updating internal state to reflect the channel closure.
    handle-channel-close: func(state: option<list<u8>>, params: tuple<channel-id>) -> result<tuple<option<list<u8>>>, string>;
}

/// # Message Server Host Interface
///
/// Provides functions for actors to send messages to other actors and manage communication channels.
///
/// ## Purpose
///
/// This interface enables actors to initiate various types of communication:
/// - Send one-way messages to other actors
/// - Make request-response interactions with other actors
/// - Establish and use bidirectional communication channels
///
/// These functions allow actors to collaborate, share data, and coordinate their activities
/// within the Theater system.
///
/// ## Example
///
/// ```rust
/// use ntwk::theater::message_server_host;
/// use ntwk::theater::types::actor_id;
/// use serde_json::json;
///
/// async fn example() -> Result<(), String> {
///     // Get the target actor ID (in a real scenario)
///     let target_actor = actor_id { id: "actor-123".to_string() };
///     
///     // Send a one-way message
///     let message = json!({"action": "update", "value": 42});
///     message_server_host::send(target_actor.clone(), message)?;
///     
///     // Make a request and get a response
///     let request = json!({"action": "query", "key": "user-profile"});
///     let response = message_server_host::request(target_actor.clone(), request)?;
///     println!("Received response: {}", response);
///     
///     // Open a channel for ongoing communication
///     let initial_msg = json!({"action": "subscribe", "topic": "updates"});
///     let channel_id = message_server_host::open_channel(target_actor, initial_msg)?;
///     
///     // Send messages on the channel
///     message_server_host::send_on_channel(channel_id.clone(), json!({"update": 1}))?;
///     message_server_host::send_on_channel(channel_id.clone(), json!({"update": 2}))?;
///     
///     // Close the channel when done
///     message_server_host::close_channel(channel_id)?;
///     
///     Ok(())
/// }
/// ```
///
/// ## Security
///
/// The message server enforces security boundaries to ensure that:
/// - Actors can only communicate with actors they have permission to access
/// - Messages are delivered reliably and in order
/// - Channel operations are authenticated
///
/// All message operations are tracked in the actor's event chain for complete auditability.
///
/// ## Implementation Notes
///
/// The message server operations are asynchronous but appear synchronous to the WebAssembly
/// component. The runtime suspends the actor's execution as needed without blocking the
/// entire system.
interface message-server-host {
    use types.{actor-id, channel-id};

    /// # Send one-way message
    ///
    /// Sends a message to another actor without waiting for a response.
    ///
    /// ## Parameters
    ///
    /// * `actor-id` - ID of the target actor
    /// * `msg` - JSON message payload to send
    ///
    /// ## Returns
    ///
    /// * `Ok(_)` - Message was successfully sent
    /// * `Err(string)` - Error message if send fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    /// use ntwk::theater::types::actor_id;
    /// use serde_json::json;
    ///
    /// // Send a notification
    /// let target = actor_id { id: "logging-service".to_string() };
    /// let log_msg = json!({
    ///     "level": "info",
    ///     "message": "User logged in",
    ///     "timestamp": 1625097600000
    /// });
    /// message_server_host::send(target, log_msg)?;
    /// ```
    ///
    /// ## Security
    ///
    /// The runtime verifies that the sender has permission to send messages to the
    /// target actor before delivery.
    send: func(actor-id: actor-id, msg: list<u8>) -> result<_, string>;

    /// # Send request and await response
    ///
    /// Sends a message to another actor and waits for a response.
    ///
    /// ## Parameters
    ///
    /// * `actor-id` - ID of the target actor
    /// * `msg` - JSON request payload to send
    ///
    /// ## Returns
    ///
    /// * `Ok(json)` - The response from the target actor
    /// * `Err(string)` - Error message if the request fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    /// use ntwk::theater::types::actor_id;
    /// use serde_json::json;
    ///
    /// // Query a data service
    /// let data_service = actor_id { id: "data-service".to_string() };
    /// let query = json!({
    ///     "query": "SELECT * FROM users WHERE id = ?",
    ///     "parameters": [42]
    /// });
    /// let result = message_server_host::request(data_service, query)?;
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// This function suspends the calling actor's execution until a response is received
    /// or a timeout occurs. The runtime handles the suspension efficiently without
    /// blocking other actors.
    request: func(actor-id: actor-id, msg: list<u8>) -> result<list<u8>, string>;
    
    /// # Open communication channel
    ///
    /// Establishes a bidirectional communication channel with another actor.
    ///
    /// ## Parameters
    ///
    /// * `actor-id` - ID of the target actor
    /// * `initial-msg` - JSON message sent as part of channel establishment
    ///
    /// ## Returns
    ///
    /// * `Ok(channel-id)` - ID of the established channel
    /// * `Err(string)` - Error message if channel establishment fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    /// use ntwk::theater::types::actor_id;
    /// use serde_json::json;
    ///
    /// // Open a channel to a streaming service
    /// let streaming_service = actor_id { id: "data-stream".to_string() };
    /// let subscription = json!({
    ///     "action": "subscribe",
    ///     "topics": ["market-data", "news-feed"],
    ///     "options": {"buffer_size": 100}
    /// });
    /// let channel = message_server_host::open_channel(streaming_service, subscription)?;
    /// ```
    ///
    /// ## Security
    ///
    /// Channel establishment requires mutual consent:
    /// 1. The initiator requests the channel by calling this function
    /// 2. The target actor explicitly accepts or rejects the channel
    ///
    /// This provides a security checkpoint to prevent unwanted channels.
    open-channel: func(actor-id: actor-id, initial-msg: list<u8>) -> result<channel-id, string>;
    
    /// # Send message on channel
    ///
    /// Sends a message through an established channel.
    ///
    /// ## Parameters
    ///
    /// * `channel-id` - ID of the channel to send on
    /// * `msg` - JSON message payload to send
    ///
    /// ## Returns
    ///
    /// * `Ok(_)` - Message was successfully sent
    /// * `Err(string)` - Error message if send fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    /// use serde_json::json;
    ///
    /// // Send a message on an established channel
    /// let update = json!({
    ///     "type": "position-update",
    ///     "x": 10.5,
    ///     "y": 20.3,
    ///     "timestamp": 1625097600000
    /// });
    /// message_server_host::send_on_channel(channel_id, update)?;
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// Messages sent on a channel are delivered in order. If the channel is closed
    /// or invalid, this function will return an error.
    send-on-channel: func(channel-id: channel-id, msg: list<u8>) -> result<_, string>;
    
    /// # Close channel
    ///
    /// Closes an open communication channel.
    ///
    /// ## Parameters
    ///
    /// * `channel-id` - ID of the channel to close
    ///
    /// ## Returns
    ///
    /// * `Ok(_)` - Channel was successfully closed
    /// * `Err(string)` - Error message if close fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    ///
    /// // Close a channel when done with it
    /// message_server_host::close_channel(channel_id)?;
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// Closing a channel is a final operation - once closed, a channel cannot be reopened.
    /// Both participants receive a notification when a channel is closed.
    close-channel: func(channel-id: channel-id) -> result<_, string>;
    
    /// # List outstanding requests
    ///
    /// Retrieves a list of all pending request IDs that haven't been responded to yet.
    ///
    /// ## Returns
    ///
    /// * `list<string>` - List of outstanding request IDs
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    ///
    /// // Get all pending requests
    /// let pending_requests = message_server_host::list_outstanding_requests();
    /// for request_id in pending_requests {
    ///     println!("Pending request: {}", request_id);
    /// }
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// This function is useful for actors that need to track and manage asynchronous
    /// request processing. It allows actors to check for pending requests and decide
    /// which ones to process next.
    list-outstanding-requests: func() -> list<string>;
    
    /// # Respond to a specific request
    ///
    /// Sends a response to a previously received request identified by its ID.
    ///
    /// ## Parameters
    ///
    /// * `request-id` - ID of the request to respond to
    /// * `response` - JSON response payload to send
    ///
    /// ## Returns
    ///
    /// * `Ok(_)` - Response was successfully sent
    /// * `Err(string)` - Error message if response fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    /// use serde_json::json;
    ///
    /// // Respond to a specific request
    /// let response = json!({
    ///     "status": "success",
    ///     "data": {
    ///         "result": 42
    ///     }
    /// });
    /// message_server_host::respond_to_request("req-123", response)?;
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// This function allows actors to implement asynchronous request handling patterns,
    /// where requests are received, processed in the background, and responded to later.
    /// If the request ID is not found, an error is returned.
    respond-to-request: func(request-id: string, response: list<u8>) -> result<_, string>;
    
    /// # Cancel a pending request
    ///
    /// Explicitly cancels a pending request without sending a response.
    ///
    /// ## Parameters
    ///
    /// * `request-id` - ID of the request to cancel
    ///
    /// ## Returns
    ///
    /// * `Ok(_)` - Request was successfully canceled
    /// * `Err(string)` - Error message if cancellation fails
    ///
    /// ## Example
    ///
    /// ```rust
    /// use ntwk::theater::message_server_host;
    ///
    /// // Cancel a request that can't be fulfilled
    /// message_server_host::cancel_request("req-123")?;
    /// ```
    ///
    /// ## Implementation Notes
    ///
    /// Canceling a request causes the requester to receive an error indicating that
    /// the request was canceled. This is useful for cleanup operations and handling
    /// error cases where a proper response cannot be generated.
    cancel-request: func(request-id: string) -> result<_, string>;
}