Skip to main content

comindly_api/
prompts.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum Task {
8    Summary,
9    Guide,
10    Flow,
11}
12
13impl Task {
14    pub const ALL: [Task; 3] = [Task::Summary, Task::Guide, Task::Flow];
15
16    pub fn name(self) -> &'static str {
17        match self {
18            Task::Summary => "summary",
19            Task::Guide => "guide",
20            Task::Flow => "flow",
21        }
22    }
23
24    pub fn parse(s: &str) -> Option<Task> {
25        Task::ALL.into_iter().find(|t| t.name() == s)
26    }
27
28    /// The built-in instructions, version 0.
29    pub fn builtin(self) -> &'static str {
30        match self {
31            Task::Summary => "You document code for a search index.",
32            Task::Guide => {
33                "You are a senior engineer documenting ONE section of a codebase's house-style \
34                guide so an AI coding agent writes code INDISTINGUISHABLE from this repo's. You are \
35                given REAL evidence (signatures, code excerpts, dependency facts, measured stats) for \
36                this section only. Make the repo's tacit conventions explicit.\n\
37                Hard rules:\n\
38                - Cite a real FILE PATH (and symbol/signature) for every non-trivial claim; quote a \
39                short real snippet as the example. Where useful, show a correct vs incorrect example.\n\
40                - Prefer the repo's OWN wrapper/abstraction over a raw library when the evidence \
41                shows one; name it exactly.\n\
42                - NEVER output generic advice that would apply to any codebase ('use meaningful \
43                names', 'write tests', 'handle errors gracefully'). Delete such lines.\n\
44                - Strength tags: **MUST**/**NEVER** for patterns across ≥3 files or enforced by \
45                config; 'prefer' for weaker signals. Give a one-line reason where non-obvious."
46            }
47            Task::Flow => {
48                "You explain how a code flow works to a developer new to the codebase. The \
49                narration is a 2-5 sentence walkthrough of what happens step by step, referencing \
50                the actual symbol names."
51            }
52        }
53    }
54
55    /// What the reply holds; the same shape goes along as a JSON schema, and is never editable.
56    pub fn format(self) -> &'static str {
57        match self {
58            Task::Summary => {
59                "Reply as JSON: \"summary\" is one concise sentence describing what this does; \
60                \"queries\" are 3 natural-language questions a developer might ask that this code \
61                answers."
62            }
63            Task::Guide => {
64                "Reply as JSON: \"rules\" holds this section's rules, one terse markdown rule per \
65                item, with no heading, preamble or closing note; \"observed\" is false, with no \
66                rules, when the evidence shows no consistent convention."
67            }
68            Task::Flow => {
69                "You get an entry point and its call trace (each line: depth, relation, symbol, \
70                location). Reply as JSON: \"narration\" is the walkthrough; \"queries\" are 3 \
71                questions a developer might ask about this flow."
72            }
73        }
74    }
75}
76
77/// One saved version of a task's instructions.
78#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79pub struct Version {
80    pub task: Task,
81    pub version: u32,
82    pub text: String,
83    /// Style guide only: what to cover in a section, by title, in place of the built-in guidance.
84    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
85    pub sections: BTreeMap<String, String>,
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub note: Option<String>,
88    pub author: String,
89    pub created_at: String,
90    /// The built-in prompt when this version was written, to tell when a release changed it.
91    #[serde(default, skip_serializing_if = "Option::is_none")]
92    pub based_on: Option<String>,
93}