feat(phase9): ContentTags schema, system prompt, and GBNF grammar
ContentTags serde-serialisable. CONTENT_TAGS_SYSTEM is the system message rendered at extraction time; INTENT_CLOSED_SET is the single source of truth for the enum values the grammar restricts. Grammar is strict: lowercase hyphen-joined topic 3+ chars (max enforced by max_tokens at call site), intent from the closed set, JSON-only output. Recursive topic-rest matches the existing GBNF style in this file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
// Phase 9 content-tag extraction. Restricts the model output to a
|
||||
// strict {topic, intent} JSON object where topic is a lowercase
|
||||
// hyphen-joined slug of at least 3 chars (no upper bound is encoded
|
||||
// in the grammar — max_tokens caps it in practice) and intent is one
|
||||
// of the six closed-set values. Recursive `topic-rest` keeps the
|
||||
// shape compatible with the existing GBNF style in this file.
|
||||
pub const CONTENT_TAGS_GRAMMAR: &str = r##"
|
||||
root ::= "{" ws "\"topic\":" ws topic-str ws "," ws "\"intent\":" ws intent ws "}" ws
|
||||
topic-str ::= "\"" topic-char topic-char topic-char topic-rest "\""
|
||||
topic-rest ::= "" | topic-char topic-rest
|
||||
topic-char ::= [a-z0-9-]
|
||||
intent ::= "\"planning\"" | "\"reflection\"" | "\"venting\"" | "\"capture\"" | "\"decision\"" | "\"question\""
|
||||
ws ::= ([ \t\n] ws)?
|
||||
"##;
|
||||
|
||||
pub const TASK_ARRAY_GRAMMAR: &str = r#"
|
||||
root ::= "[" ws string ws "," ws string ws "," ws string rest3 ws "]"
|
||||
rest3 ::= "" | "," ws string rest4
|
||||
|
||||
@@ -15,7 +15,9 @@ pub mod grammars;
|
||||
pub mod model_manager;
|
||||
pub mod prompts;
|
||||
|
||||
pub use grammars::CONTENT_TAGS_GRAMMAR;
|
||||
pub use model_manager::{recommend_tier, LlmModelId, LlmModelInfo};
|
||||
pub use prompts::{is_valid_intent, ContentTags, CONTENT_TAGS_SYSTEM, INTENT_CLOSED_SET};
|
||||
|
||||
const DEFAULT_CONTEXT_TOKENS: u32 = 4096;
|
||||
const MAX_CONTEXT_TOKENS: u32 = 8192;
|
||||
|
||||
@@ -4,6 +4,39 @@ between 3 and 7 concrete, physical micro-steps. Each step must be a short \
|
||||
imperative sentence, actionable today, with no commentary. Output ONLY a \
|
||||
JSON array of strings.";
|
||||
|
||||
// Phase 9 content-tag extraction. The model emits a {topic, intent}
|
||||
// JSON pair under a strict GBNF (see grammars::CONTENT_TAGS_GRAMMAR).
|
||||
// CONTENT_TAGS_SYSTEM is the system message; the user message wraps
|
||||
// the transcript text.
|
||||
pub const CONTENT_TAGS_SYSTEM: &str = "\
|
||||
You tag a transcript with ONE topic and ONE intent. \
|
||||
TOPIC is a 1 to 3 token lowercase hyphen-joined noun phrase naming the \
|
||||
dominant subject. Examples: interview-prep, grant-application, \
|
||||
daily-standup. \
|
||||
INTENT is exactly one of: planning, reflection, venting, capture, \
|
||||
decision, question. \
|
||||
Return JSON only, with this exact shape: \
|
||||
{\"topic\":\"...\",\"intent\":\"...\"}";
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ContentTags {
|
||||
pub topic: String,
|
||||
pub intent: String,
|
||||
}
|
||||
|
||||
pub const INTENT_CLOSED_SET: &[&str] = &[
|
||||
"planning",
|
||||
"reflection",
|
||||
"venting",
|
||||
"capture",
|
||||
"decision",
|
||||
"question",
|
||||
];
|
||||
|
||||
pub fn is_valid_intent(s: &str) -> bool {
|
||||
INTENT_CLOSED_SET.contains(&s)
|
||||
}
|
||||
|
||||
pub const EXTRACT_TASKS_SYSTEM: &str = "\
|
||||
You are a task-extraction assistant. Given a transcript of spoken notes, \
|
||||
output a JSON array of action items the speaker committed to. Each item must \
|
||||
|
||||
Reference in New Issue
Block a user