Skip to main content

systemprompt_models/brain/
kind_decl.rs

1//! A fact kind declared under `services/brain/kinds/*.yaml`: its subject,
2//! fields, statement template, identity and extractor.
3//!
4//! Copyright (c) systemprompt.io — Business Source License 1.1.
5//! See <https://systemprompt.io> for licensing details.
6
7use std::collections::BTreeMap;
8
9use serde::{Deserialize, Serialize};
10use systemprompt_identifiers::{FactKindId, TopicId};
11
12pub const SUBJECT_FIELD: &str = "subject";
13
14/// One declared fact kind.
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16#[serde(deny_unknown_fields)]
17pub struct KindDecl {
18    pub kind: FactKindId,
19    pub subject: String,
20    #[serde(default)]
21    pub description: Option<String>,
22    pub fields: BTreeMap<String, FieldDecl>,
23    #[serde(default)]
24    pub topics: Vec<TopicId>,
25    pub statement: String,
26    pub identity: Vec<String>,
27    #[serde(default)]
28    pub materiality: Materiality,
29    #[serde(default)]
30    pub review_after_days: Option<u32>,
31    #[serde(default)]
32    pub extractor: Option<ExtractorDecl>,
33}
34
35impl KindDecl {
36    #[must_use]
37    pub fn knows(&self, name: &str) -> bool {
38        name == SUBJECT_FIELD || self.fields.contains_key(name)
39    }
40
41    #[must_use]
42    pub fn prompt_version(&self) -> Option<&str> {
43        match &self.extractor {
44            Some(ExtractorDecl::Model { prompt_version, .. }) => prompt_version.as_deref(),
45            _ => None,
46        }
47    }
48}
49
50/// The value type of a declared field.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
52#[serde(rename_all = "snake_case")]
53pub enum FieldType {
54    Text,
55    Entity,
56    Date,
57    Number,
58    Bool,
59    Enum,
60}
61
62/// One declared field of a kind.
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
64#[serde(deny_unknown_fields)]
65pub struct FieldDecl {
66    #[serde(rename = "type")]
67    pub field_type: FieldType,
68    #[serde(default)]
69    pub required: bool,
70    #[serde(default)]
71    pub max_len: Option<u32>,
72    #[serde(default, rename = "ref")]
73    pub entity_ref: Option<String>,
74    #[serde(default)]
75    pub values: Vec<String>,
76    #[serde(default)]
77    pub alias: bool,
78}
79
80/// The fields a candidate must carry before it is worth keeping.
81#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(deny_unknown_fields, default)]
83pub struct Materiality {
84    pub require: Vec<String>,
85}
86
87/// How candidates of a kind are produced: a named parser, or a model call
88/// with a versioned prompt.
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
90#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
91pub enum ExtractorDecl {
92    Parser {
93        name: String,
94    },
95    Model {
96        prompt: String,
97        #[serde(default)]
98        prompt_version: Option<String>,
99    },
100}