honcho-ai 0.1.2

Rust SDK for Honcho — AI agent memory and social cognition infrastructure
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
use std::collections::HashMap;
use std::pin::Pin;

use futures_util::Stream;
use serde_json::Value;

use crate::dialectic_stream::DialecticStream;
use crate::error::Result;
use crate::types::dialectic::{DialecticOptions, ReasoningLevel};
use crate::types::message::MessageSearchOptions;
use crate::types::pagination::Page;
use crate::types::peer::{PeerConfig, PeerContext};
use crate::types::session::{Session, SessionListOptions};

use super::conclusion::ConclusionScope;
use super::iter::{BlockingIter, collect_all_pages};
use super::runtime::block_on;

/// Synchronous wrapper around [`crate::Peer`].
#[derive(Clone)]
pub struct Peer {
    inner: crate::Peer,
}

impl std::fmt::Debug for Peer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Peer")
            .field("id", &self.inner.id())
            .finish()
    }
}

impl Peer {
    pub(crate) fn new(inner: crate::Peer) -> Self {
        Self { inner }
    }

    /// Peer's unique identifier.
    #[must_use]
    pub fn id(&self) -> &str {
        self.inner.id()
    }

    /// Cached metadata.
    #[must_use]
    pub fn metadata(&self) -> Option<HashMap<String, Value>> {
        self.inner.metadata()
    }

    /// Cached configuration.
    #[must_use]
    pub fn configuration(&self) -> Option<PeerConfig> {
        self.inner.configuration()
    }

    /// Refresh cached state from the server.
    pub fn refresh(&self) -> Result<()> {
        block_on(self.inner.refresh())
    }

    /// Fetch and return metadata, updating the cache.
    pub fn get_metadata(&self) -> Result<HashMap<String, Value>> {
        block_on(self.inner.get_metadata())
    }

    /// Set metadata on the server and update the cache.
    pub fn set_metadata(&self, metadata: HashMap<String, Value>) -> Result<()> {
        block_on(self.inner.set_metadata(metadata))
    }

    /// Fetch and return configuration, updating the cache.
    pub fn get_configuration(&self) -> Result<PeerConfig> {
        block_on(self.inner.get_configuration())
    }

    /// Set configuration on the server and update the cache.
    pub fn set_configuration(&self, config: &PeerConfig) -> Result<()> {
        block_on(self.inner.set_configuration(config))
    }

    /// Fetch configuration as a raw JSON map.
    pub fn get_configuration_raw(&self) -> Result<HashMap<String, Value>> {
        block_on(self.inner.get_configuration_raw())
    }

    /// Set configuration from a raw JSON map.
    pub fn set_configuration_raw(&self, config: HashMap<String, Value>) -> Result<()> {
        block_on(self.inner.set_configuration_raw(config))
    }

    /// Patch-update metadata.
    pub fn update(&self, metadata: HashMap<String, Value>) -> Result<()> {
        block_on(self.inner.update(metadata))
    }

    /// Non-streaming dialectic chat.
    pub fn chat(&self, query: &str) -> Result<Option<String>> {
        block_on(self.inner.chat(query))
    }

    /// Non-streaming dialectic chat with full options.
    pub fn chat_with_options(&self, options: &DialecticOptions) -> Result<Option<String>> {
        block_on(self.inner.chat_with_options(options))
    }

    /// Start a streaming dialectic chat. Returns a builder; call `.send()` for an iterator.
    #[must_use]
    pub fn chat_stream(&self, query: impl Into<String>) -> BlockingChatStreamBuilder {
        BlockingChatStreamBuilder {
            inner: self.inner.chat_stream(query),
        }
    }

    /// Get the peer's representation.
    pub fn representation(&self) -> Result<String> {
        block_on(self.inner.representation())
    }

    /// Get a builder for fine-grained representation parameters.
    #[must_use]
    pub fn representation_builder(&self) -> BlockingRepresentationBuilder {
        BlockingRepresentationBuilder {
            inner: self.inner.representation_builder(),
        }
    }

    /// Get a builder for fine-grained context parameters.
    #[must_use]
    pub fn context_builder(&self) -> BlockingContextBuilder {
        BlockingContextBuilder {
            inner: self.inner.context_builder(),
        }
    }

    /// Get the peer's context.
    pub fn context(&self) -> Result<PeerContext> {
        block_on(self.inner.context())
    }

    /// Get the peer's context scoped to a target.
    #[deprecated(since = "0.1.1", note = "use `Peer::context_builder()` instead")]
    #[allow(deprecated)]
    pub fn context_with_target(&self, target: &str) -> Result<PeerContext> {
        block_on(self.inner.context_with_target(target))
    }

    /// Get the peer's context with custom options.
    #[deprecated(since = "0.1.1", note = "use `Peer::context_builder()` instead")]
    #[allow(deprecated)]
    pub fn context_with_options(
        &self,
        options: &crate::types::peer::PeerContextOptions,
    ) -> Result<PeerContext> {
        block_on(self.inner.context_with_options(options))
    }

    /// List sessions for this peer, collecting across pages.
    pub fn sessions(&self) -> Result<Vec<Session>> {
        block_on(async {
            let page = self.inner.sessions().await?;
            collect_all_pages(page).await
        })
    }

    /// List sessions with filters and pagination options. Returns a [`Page`].
    pub fn sessions_with_options(&self, options: &SessionListOptions) -> Result<Page<Session>> {
        block_on(self.inner.sessions_with_options(options))
    }

    /// Search messages for this peer.
    pub fn search(&self, query: &str) -> Result<Vec<crate::Message>> {
        block_on(self.inner.search(query))
    }

    /// Search messages for this peer with custom options.
    pub fn search_with_options(
        &self,
        options: &MessageSearchOptions,
    ) -> Result<Vec<crate::Message>> {
        block_on(self.inner.search_with_options(options))
    }

    /// Get this peer's card.
    pub fn get_card(&self) -> Result<Option<Vec<String>>> {
        block_on(self.inner.get_card())
    }

    /// Get this peer's card scoped to a target.
    pub fn get_card_with_target(&self, target: &str) -> Result<Option<Vec<String>>> {
        block_on(self.inner.get_card_with_target(target))
    }

    /// Set this peer's card.
    pub fn set_card(&self, card: Vec<String>) -> Result<Option<Vec<String>>> {
        block_on(self.inner.set_card(card))
    }

    /// Set this peer's card scoped to a target.
    pub fn set_card_with_target(
        &self,
        card: Vec<String>,
        target: &str,
    ) -> Result<Option<Vec<String>>> {
        block_on(self.inner.set_card_with_target(card, target))
    }

    /// Self-scoped conclusion handle.
    #[must_use]
    pub fn conclusions(&self) -> ConclusionScope {
        ConclusionScope::new(self.inner.conclusions())
    }

    /// Cross-peer conclusion handle.
    #[must_use]
    pub fn conclusions_of(&self, target: impl Into<String>) -> ConclusionScope {
        ConclusionScope::new(self.inner.conclusions_of(target))
    }

    /// Create a message builder (sync, no API call).
    #[must_use]
    pub fn message(&self, content: impl Into<String>) -> crate::peer::MessageBuilder {
        self.inner.message(content)
    }
}

/// Blocking streaming dialectic chat builder.
pub struct BlockingChatStreamBuilder {
    inner: crate::peer::ChatStreamBuilder,
}

impl BlockingChatStreamBuilder {
    /// Scope the chat to a target peer.
    #[must_use]
    pub fn target(self, target: impl Into<String>) -> Self {
        Self {
            inner: self.inner.target(target),
        }
    }

    /// Scope the chat to a session.
    #[must_use]
    pub fn session(self, session_id: impl Into<String>) -> Self {
        Self {
            inner: self.inner.session(session_id),
        }
    }

    /// Set the reasoning level.
    #[must_use]
    pub fn reasoning_level(self, level: ReasoningLevel) -> Self {
        Self {
            inner: self.inner.reasoning_level(level),
        }
    }

    /// Send and return an iterator over SSE chunks.
    pub fn send(self) -> Result<ChatStreamIterator> {
        let stream = block_on(self.inner.send())?;
        Ok(ChatStreamIterator {
            inner: BlockingIter::new(stream),
        })
    }
}

/// Iterator over streaming dialectic chat chunks.
///
/// Wraps a [`DialecticStream`], so [`final_response`](DialecticStream::final_response)
/// and [`is_complete`](DialecticStream::is_complete) are available after iteration.
#[allow(clippy::type_complexity)]
pub struct ChatStreamIterator {
    inner: BlockingIter<DialecticStream<Pin<Box<dyn Stream<Item = Result<String>> + Send>>>>,
}

impl ChatStreamIterator {
    /// Access the accumulated [`FinalResponse`](crate::FinalResponse).
    #[must_use]
    pub fn final_response(&self) -> &crate::FinalResponse {
        self.inner.stream().final_response()
    }

    /// Whether the underlying stream has ended.
    #[must_use]
    pub fn is_complete(&self) -> bool {
        self.inner.stream().is_complete()
    }
}

impl Iterator for ChatStreamIterator {
    type Item = Result<String>;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}

/// Blocking builder for fine-grained representation requests.
pub struct BlockingRepresentationBuilder {
    inner: crate::peer::RepresentationBuilder,
}

impl BlockingRepresentationBuilder {
    /// Scope to a session.
    #[must_use]
    pub fn session_id(self, val: impl Into<String>) -> Self {
        Self {
            inner: self.inner.session_id(val),
        }
    }

    /// Target peer.
    #[must_use]
    pub fn target(self, val: impl Into<String>) -> Self {
        Self {
            inner: self.inner.target(val),
        }
    }

    /// Semantic search query.
    #[must_use]
    pub fn search_query(self, val: impl Into<String>) -> Self {
        Self {
            inner: self.inner.search_query(val),
        }
    }

    /// Top-K for semantic search (1–100).
    #[must_use]
    pub fn search_top_k(self, val: u32) -> Self {
        Self {
            inner: self.inner.search_top_k(val),
        }
    }

    /// Max cosine distance (0.0–1.0).
    #[must_use]
    pub fn search_max_distance(self, val: f64) -> Self {
        Self {
            inner: self.inner.search_max_distance(val),
        }
    }

    /// Include most frequent conclusions.
    #[must_use]
    pub fn include_most_frequent(self, val: bool) -> Self {
        Self {
            inner: self.inner.include_most_frequent(val),
        }
    }

    /// Max conclusions (1–100).
    #[must_use]
    pub fn max_conclusions(self, val: u32) -> Self {
        Self {
            inner: self.inner.max_conclusions(val),
        }
    }

    /// Send the representation request.
    pub fn send(self) -> Result<String> {
        block_on(self.inner.send())
    }
}

/// Blocking builder for fine-grained context requests.
pub struct BlockingContextBuilder {
    inner: crate::peer::ContextBuilder,
}

impl BlockingContextBuilder {
    /// Scope to a target peer.
    #[must_use]
    pub fn target(self, val: impl Into<String>) -> Self {
        Self {
            inner: self.inner.target(val),
        }
    }

    /// Whether to include the peer card summary.
    #[must_use]
    pub fn summary(self, val: bool) -> Self {
        Self {
            inner: self.inner.summary(val),
        }
    }

    /// Limit to a specific session.
    #[must_use]
    pub fn limit_to_session(self, val: bool) -> Self {
        Self {
            inner: self.inner.limit_to_session(val),
        }
    }

    /// Max conclusions (1–100).
    #[must_use]
    pub fn max_conclusions(self, val: u32) -> Self {
        Self {
            inner: self.inner.max_conclusions(val),
        }
    }

    /// Semantic search query.
    #[must_use]
    pub fn search_query(self, val: impl Into<String>) -> Self {
        Self {
            inner: self.inner.search_query(val),
        }
    }

    /// Top-K for semantic search (1–100).
    #[must_use]
    pub fn search_top_k(self, val: u32) -> Self {
        Self {
            inner: self.inner.search_top_k(val),
        }
    }

    /// Max cosine distance (0.0–1.0).
    #[must_use]
    pub fn search_max_distance(self, val: f64) -> Self {
        Self {
            inner: self.inner.search_max_distance(val),
        }
    }

    /// Include most frequent conclusions.
    #[must_use]
    pub fn include_most_frequent(self, val: bool) -> Self {
        Self {
            inner: self.inner.include_most_frequent(val),
        }
    }

    /// Send the context request.
    pub fn send(self) -> Result<PeerContext> {
        block_on(self.inner.send())
    }
}

impl std::fmt::Debug for BlockingChatStreamBuilder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BlockingChatStreamBuilder")
            .finish_non_exhaustive()
    }
}

impl std::fmt::Debug for ChatStreamIterator {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ChatStreamIterator").finish_non_exhaustive()
    }
}

impl std::fmt::Debug for BlockingRepresentationBuilder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BlockingRepresentationBuilder")
            .finish_non_exhaustive()
    }
}

impl std::fmt::Debug for BlockingContextBuilder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BlockingContextBuilder")
            .finish_non_exhaustive()
    }
}