agentic_reality/query/
intent.rs1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
8pub enum ExtractionIntent {
9 Exists,
10 #[default]
11 IdsOnly,
12 Summary,
13 Fields(Vec<String>),
14 Full,
15}
16
17impl ExtractionIntent {
18 pub fn estimated_tokens(&self) -> u64 {
19 match self {
20 Self::Exists => 1,
21 Self::IdsOnly => 10,
22 Self::Summary => 50,
23 Self::Fields(f) => 20 * f.len() as u64,
24 Self::Full => 500,
25 }
26 }
27
28 pub fn parse_label(s: &str) -> Self {
29 match s {
30 "exists" => Self::Exists,
31 "ids" | "ids_only" => Self::IdsOnly,
32 "summary" => Self::Summary,
33 "full" => Self::Full,
34 _ => Self::Full,
35 }
36 }
37
38 pub fn is_minimal(&self) -> bool {
39 matches!(self, Self::Exists | Self::IdsOnly)
40 }
41
42 pub fn includes_content(&self) -> bool {
43 matches!(self, Self::Summary | Self::Fields(_) | Self::Full)
44 }
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub enum ScopedResult {
49 Bool(bool),
50 Id(String),
51 Ids(Vec<String>),
52 Summary(String),
53 Fields(HashMap<String, Value>),
54 Full(Value),
55 Count(usize),
56}
57
58impl ScopedResult {
59 pub fn estimated_tokens(&self) -> u64 {
60 match self {
61 Self::Bool(_) => 1,
62 Self::Id(_) => 5,
63 Self::Ids(ids) => ids.len() as u64 * 5,
64 Self::Summary(_) => 50,
65 Self::Fields(f) => f.len() as u64 * 20,
66 Self::Full(v) => serde_json::to_string(v)
67 .map(|s| s.len() as u64 / 4)
68 .unwrap_or(500),
69 Self::Count(_) => 2,
70 }
71 }
72}
73
74pub trait Scopeable {
75 fn id_str(&self) -> String;
76 fn summarize(&self) -> String;
77 fn extract_fields(&self, fields: &[String]) -> HashMap<String, Value>;
78 fn to_json(&self) -> Value;
79}
80
81pub fn apply_intent<T: Scopeable>(intent: &ExtractionIntent, item: &T) -> ScopedResult {
82 match intent {
83 ExtractionIntent::Exists => ScopedResult::Bool(true),
84 ExtractionIntent::IdsOnly => ScopedResult::Id(item.id_str()),
85 ExtractionIntent::Summary => ScopedResult::Summary(item.summarize()),
86 ExtractionIntent::Fields(f) => ScopedResult::Fields(item.extract_fields(f)),
87 ExtractionIntent::Full => ScopedResult::Full(item.to_json()),
88 }
89}
90
91pub fn apply_intent_many<T: Scopeable>(intent: &ExtractionIntent, items: &[T]) -> ScopedResult {
92 match intent {
93 ExtractionIntent::Exists => ScopedResult::Bool(!items.is_empty()),
94 ExtractionIntent::IdsOnly => ScopedResult::Ids(items.iter().map(|i| i.id_str()).collect()),
95 ExtractionIntent::Summary => ScopedResult::Count(items.len()),
96 _ => ScopedResult::Full(serde_json::json!(items
97 .iter()
98 .map(|i| i.to_json())
99 .collect::<Vec<_>>())),
100 }
101}