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
//! Domain model and ports (traits) of okbot; the SDK for third-party adapters.
//!
//! okbot follows a ports-and-adapters architecture (ADR 0001). This crate holds the types every
//! other crate speaks and the traits adapters implement. It performs no I/O.
//!
//! | Port | Implemented by | Used by |
//! |---|---|---|
//! | [`Channel`] | one crate per chat platform | the runtime |
//! | [`InboundSink`] | the runtime | channels, to deliver events |
//! | [`AgentBackend`] | agent CLIs, fallback chains | the runtime |
//! | [`ConversationStore`] | SQLite store | the runtime |
//! | [`KnowledgeProvider`] | okbase integration | the runtime |
//! | [`MemoryStore`] | okbase integration | the runtime (chat commands) |
//! | [`TaskStore`] | okbase integration | the runtime (chat commands, scheduler) |
//! | [`Renderer`] | Markdown dialect renderer | the runtime |
//! | [`Clock`] | [`SystemClock`], test clocks | everything that reads time |
//!
//! # Writing a channel
//!
//! A platform adapter implements [`Channel`]: receive events and hand them to the [`InboundSink`],
//! send rendered replies. Everything else (policy, agents, knowledge) is the runtime's job.
//!
//! ```
//! use std::sync::Arc;
//! use okbot_core::{
//! async_trait, CancellationToken, Channel, ChannelCaps, ChannelError, ChannelId, InboundSink,
//! MessageId, RenderedMessage, ReplyTarget, SentRef,
//! };
//!
//! struct EchoChannel { id: ChannelId, caps: ChannelCaps }
//!
//! #[async_trait]
//! impl Channel for EchoChannel {
//! fn id(&self) -> &ChannelId { &self.id }
//! fn caps(&self) -> &ChannelCaps { &self.caps }
//!
//! async fn run(&self, _sink: Arc<dyn InboundSink>, shutdown: CancellationToken)
//! -> Result<(), ChannelError> {
//! // Connect to the platform and call `sink.deliver(event)` for each message.
//! shutdown.cancelled().await;
//! Ok(())
//! }
//!
//! async fn send(&self, to: &ReplyTarget, message: &RenderedMessage)
//! -> Result<SentRef, ChannelError> {
//! println!("{}", message.text);
//! Ok(SentRef { target: to.clone(), message_id: MessageId::new("1") })
//! }
//! }
//!
//! let channel = EchoChannel { id: "echo:demo".parse().unwrap(), caps: ChannelCaps::basic() };
//! assert_eq!(channel.id().to_string(), "echo:demo");
//! ```
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use Renderer;
pub use ;
pub use ;
pub use ;
pub use ;
/// Re-exported so adapters use the same cancellation type as the runtime.
pub use CancellationToken;
/// Re-exported so adapters implement the async traits with the same macro version.
pub use async_trait;
/// A boxed error from an adapter, kept as the `source` of port errors.
pub type BoxError = ;