Skip to main content

floopy/
constants.rs

1//! Static configuration: defaults, Floopy wire headers, and API endpoints.
2//!
3//! Mirrors the constants in the Node/Python/Go SDKs so behaviour stays in
4//! lockstep across languages.
5
6use std::time::Duration;
7
8use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
9
10/// Encode everything except the RFC3986 unreserved set (`A-Za-z0-9-._~`),
11/// matching JS `encodeURIComponent`, Python `quote(safe="")`, and Go
12/// `url.PathEscape` so a given id maps to the same path across all SDKs.
13const PATH_SEGMENT: &AsciiSet = &NON_ALPHANUMERIC
14    .remove(b'-')
15    .remove(b'_')
16    .remove(b'.')
17    .remove(b'~');
18
19/// The public Floopy gateway base URL. Override with
20/// [`crate::FloopyBuilder::base_url`] for self-hosted gateways.
21pub const DEFAULT_BASE_URL: &str = "https://api.floopy.ai/v1";
22
23/// Default per-request timeout when none is configured.
24pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
25
26/// Default retry budget for transient failures.
27pub const DEFAULT_MAX_RETRIES: u32 = 2;
28
29pub(crate) const USER_AGENT_PREFIX: &str = "floopy-sdk";
30
31// --- headers --------------------------------------------------------------
32
33pub(crate) const HEADER_CACHE_ENABLED: &str = "Floopy-Cache-Enabled";
34pub(crate) const HEADER_CACHE_BUCKET_MAX_SIZE: &str = "Floopy-Cache-Bucket-Max-Size";
35pub(crate) const HEADER_PROMPT_ID: &str = "Floopy-Prompt-Id";
36pub(crate) const HEADER_PROMPT_VERSION: &str = "Floopy-Prompt-Version";
37pub(crate) const HEADER_LLM_SECURITY_ENABLED: &str = "floopy-llm-security-enabled";
38pub(crate) const HEADER_FLOOPY_PROVIDER: &str = "floopy-provider";
39pub(crate) const HEADER_CONFIRM: &str = "X-Floopy-Confirm";
40pub(crate) const HEADER_REQUEST_ID: &str = "X-Request-Id";
41pub(crate) const HEADER_FLOOPY_SDK: &str = "X-Floopy-SDK";
42
43/// The `X-Floopy-Confirm` value the gateway requires on experiment
44/// create/rollback (gateway control SEC-009). Injected automatically by the
45/// experiments resource.
46pub const CONFIRM_EXPERIMENTS: &str = "experiments";
47
48// --- endpoints ------------------------------------------------------------
49
50pub(crate) const ENDPOINT_FEEDBACK: &str = "/feedback";
51pub(crate) const ENDPOINT_DECISIONS: &str = "/decisions";
52pub(crate) const ENDPOINT_EXPERIMENTS: &str = "/experiments";
53pub(crate) const ENDPOINT_CONSTRAINTS: &str = "/constraints";
54pub(crate) const ENDPOINT_EXPORT_DECISIONS: &str = "/export/decisions";
55pub(crate) const ENDPOINT_ROUTING_EXPLAIN: &str = "/routing/explain";
56pub(crate) const ENDPOINT_EVALUATIONS: &str = "/evaluations";
57pub(crate) const ENDPOINT_FILES: &str = "/files";
58pub(crate) const ENDPOINT_BATCHES: &str = "/batches";
59
60/// Percent-encode a single path segment (matches JS `encodeURIComponent` /
61/// Python `urllib.parse.quote(safe="")`).
62pub(crate) fn path_seg(value: &str) -> String {
63    utf8_percent_encode(value, PATH_SEGMENT).to_string()
64}
65
66pub(crate) fn decision_by_id(id: &str) -> String {
67    format!("{ENDPOINT_DECISIONS}/{}", path_seg(id))
68}
69pub(crate) fn session_by_id(id: &str) -> String {
70    format!("/session/{}", path_seg(id))
71}
72pub(crate) fn experiment_results(id: &str) -> String {
73    format!("{ENDPOINT_EXPERIMENTS}/{}/results", path_seg(id))
74}
75pub(crate) fn experiment_rollback(id: &str) -> String {
76    format!("{ENDPOINT_EXPERIMENTS}/{}/rollback", path_seg(id))
77}
78pub(crate) fn evaluation_by_id(id: &str) -> String {
79    format!("{ENDPOINT_EVALUATIONS}/{}", path_seg(id))
80}
81pub(crate) fn evaluation_results(id: &str) -> String {
82    format!("{ENDPOINT_EVALUATIONS}/{}/results", path_seg(id))
83}
84pub(crate) fn evaluation_cancel(id: &str) -> String {
85    format!("{ENDPOINT_EVALUATIONS}/{}/cancel", path_seg(id))
86}
87pub(crate) fn file_by_id(id: &str) -> String {
88    format!("{ENDPOINT_FILES}/{}", path_seg(id))
89}
90pub(crate) fn file_content(id: &str) -> String {
91    format!("{ENDPOINT_FILES}/{}/content", path_seg(id))
92}
93pub(crate) fn batch_by_id(id: &str) -> String {
94    format!("{ENDPOINT_BATCHES}/{}", path_seg(id))
95}
96pub(crate) fn batch_cancel(id: &str) -> String {
97    format!("{ENDPOINT_BATCHES}/{}/cancel", path_seg(id))
98}