artificial_types/fragments/static_fragment.rs
1//! A minimal fragment that injects a *static* string into the prompt.
2//!
3//! Use this when you have pre-determined text (role description, safety
4//! notice, system instruction …) that never changes between invocations.
5//!
6//! ```rust
7//! use artificial_types::fragments::StaticFragment;
8//! use artificial_core::generic::GenericRole;
9//!
10//! let sys_msg = StaticFragment::new(
11//! "You are a multilingual proof-reading engine.",
12//! GenericRole::System,
13//! );
14//! ```
15//!
16//! # Why a dedicated type?
17//!
18//! 1. It keeps the [`IntoPrompt`] API symmetrical – every fragment, no matter
19//! how simple, implements the same trait.
20//! 2. You can attach metadata (`role`) so the provider sees the correct
21//! message type without manual wrapping.
22//! 3. Unlike `&'static str`, this struct can carry a *borrowed* slice with
23//! lifetime `'a`, allowing the caller to reference larger inline strings
24//! without `String` allocation.
25//!
26//! The `From<&str>` blanket impl defaults to `GenericRole::System` for
27//! convenience since system messages are the most common static fragments.
28
29use artificial_core::{
30 generic::{GenericMessage, GenericRole},
31 template::IntoPrompt,
32};
33
34/// A borrowed static string bundled with an LLM chat role.
35///
36/// The tuple struct keeps the footprint at *exactly two machine words*
37/// (`&str` + `GenericRole`) while still offering ergonomic constructors.
38pub struct StaticFragment<'a>((&'a str, GenericRole));
39
40/// Shorthand so you can write `StaticFragment::from("…")` without specifying
41/// the role each time. Defaults to **system**.
42impl<'a> From<&'a str> for StaticFragment<'a> {
43 fn from(value: &'a str) -> Self {
44 Self((value, GenericRole::System))
45 }
46}
47
48impl<'a> StaticFragment<'a> {
49 /// Create a new fragment with explicit role.
50 pub fn new(value: &'a str, role: GenericRole) -> Self {
51 Self((value, role))
52 }
53}
54
55impl IntoPrompt for StaticFragment<'_> {
56 type Message = GenericMessage;
57
58 fn into_prompt(self) -> Vec<Self::Message> {
59 vec![GenericMessage::new(self.0.0.to_string(), self.0.1)]
60 }
61}