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
//! Abstractions that tie a **prompt** to a concrete **model** and a **typed
//! response**.
//!
//! The *artificial* framework purposely keeps the public surface small. A
//! developer usually needs only two traits to go from “some string fragments”
//! to “ready-to-send payload”:
//!
//! 1. [`IntoPrompt`] – turns *any* value into a list of chat messages.
//! 2. [`PromptTemplate`] – adds metadata such as the target model and the
//! expected JSON response schema.
//!
//! Provider back-ends (e.g. `artificial-openai`) accept *any* `P` that
//! implements **both** traits. Thanks to Rust’s powerful type system the
//! compiler guarantees at compile time that
//!
//! * the message type produced by the prompt matches what the back-end expects,
//! * the JSON returned by the provider can be deserialised into `P::Output`.
//!
//! ```rust
//! use artificial_core::template::{IntoPrompt, PromptTemplate};
//! use artificial_core::generic::{GenericMessage, GenericRole};
//! use artificial_core::model::{Model, OpenAiModel};
//! use schemars::JsonSchema;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Serialize, Deserialize, JsonSchema)]
//! #[serde(deny_unknown_fields)]
//! struct Hello { greeting: String }
//!
//! struct HelloPrompt;
//!
//! impl IntoPrompt for HelloPrompt {
//! type Message = GenericMessage;
//! fn into_prompt(self) -> Vec<Self::Message> {
//! vec![GenericMessage::new("Say hello!".into(), GenericRole::User)]
//! }
//! }
//!
//! impl PromptTemplate for HelloPrompt {
//! type Output = Hello;
//! const MODEL: Model = Model::OpenAi(OpenAiModel::Gpt4oMini);
//! }
//! ```
//!
//! See `examples/openai_hello_world.rs` for a fully working program.
use Any;
use JsonSchema;
use Deserialize;
use crateModel;
/// High-level description of a prompt.
///
/// Implement this trait **in addition** to [`IntoPrompt`] to specify:
///
/// * `Output` – the strongly-typed Rust struct you expect from the LLM.
/// * `MODEL` – the identifier of the model that should handle the request.
///
/// The blanket constraints on `Output` (`JsonSchema + Deserialize + Any`)
/// enable the OpenAI adapter to automatically derive a JSON Schema and to
/// down-cast the erased type if necessary.
/// Converts a value into a series of chat messages.
///
/// Provider crates typically use [`crate::generic::GenericMessage`], but a
/// back-end can require its own richer struct. By making the `Message` type
/// an **associated type** we keep the trait flexible without resorting to
/// dynamic dispatch.
/// Convenience implementation so a single [`crate::generic::GenericMessage`]
/// can be passed directly to the client without wrapping it in a struct.