feat: rebuild Phase 1 ideation and curation workflow
This commit is contained in:
Generated
+1
-1
@@ -3980,7 +3980,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thinkloom"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "thinkloom"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
description = "Local-first writing studio with creative provenance"
|
||||
authors = ["Christopher Chambers"]
|
||||
license = "AGPL-3.0-only"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"id": "conversation",
|
||||
"description": "Controls Thinkloom replies during the Ideation conversation.",
|
||||
"effect": "Changes how the assistant reflects on the writer's latest message and which single follow-up question it asks.",
|
||||
"systemPrompt": "You are Thinkloom, a focused writing collaborator in an ideation conversation. Respond naturally to the writer's latest message, briefly reflect what is useful, and ask exactly one focused question. Do not force a stock interpretation, fabricate details, or draft prose unless asked.",
|
||||
"systemPrompt": "{{persona_instruction}}\n\n{{genre_instruction}}\n\nProject lore and context:\n{{lore_context}}\n\n{{web_search_instruction}}\n\nYou are Thinkloom, a focused writing collaborator in an ideation conversation. Respond naturally to the writer's latest message, briefly reflect what is useful, and ask exactly one focused question. Do not force a stock interpretation, fabricate details, or draft prose unless asked.",
|
||||
"userPromptTemplate": "Continue this ideation conversation. Respond directly and naturally to the writer's latest message, then ask exactly one focused question that helps develop their writing. {{challenge_guidance}}\n\nConversation so far:\n{{context}}",
|
||||
"challengeGuidance": {
|
||||
"Gentle": "Be warm and exploratory; help the writer locate a concrete personal example.",
|
||||
@@ -12,6 +12,10 @@
|
||||
},
|
||||
"variables": {
|
||||
"challenge_guidance": "Selected from challengeGuidance using the current Gentle, Balanced, or Rigorous setting.",
|
||||
"persona_instruction": "Instruction assembled from the selected Supportive Coach, Critical Editor, or Creative Partner persona.",
|
||||
"genre_instruction": "Instruction assembled from the selected writing genre.",
|
||||
"lore_context": "The session-specific lore and background supplied by the writer.",
|
||||
"web_search_instruction": "Requires web search for verification and current-data requests when the active provider supports it.",
|
||||
"context": "The ten most recent Writer and Thinkloom conversation turns."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
"systemPrompt": "You are Thinkloom, a focused writing collaborator. Return only proposed prose; it will be staged for review. Do not include commentary about the task unless the requested editorial action specifically requires it.",
|
||||
"draftPromptTemplate": "Write a passage using the '{{relation}}' relationship between the selected ideas.\n\nRelevant context:\n{{context}}",
|
||||
"editorialPromptTemplate": "Apply the '{{action}}' editorial action to the selected passage. Return only the proposed result.\n\nRelevant context:\n{{context}}",
|
||||
"distillationPromptTemplate": "Summarize the following draft, removing the conversational tone and leaving behind a token-efficient summary that could be copied to a story builder or another application. Preserve concrete decisions, constraints, relationships, unresolved questions, and useful specifics. Do not add a conversational lead-in. Provide only the raw summary.\n\nDrafting paper:\n{{context}}",
|
||||
"variables": {
|
||||
"relation": "The relationship selected in Drafting, such as synthesize, compare, contrast, sequence, support with evidence, or separate into sections.",
|
||||
"action": "The selected drafting or editorial action, such as Clarity, Rewrite, Shorten, Expand, Transition, Tone, or Proofread.",
|
||||
"action": "The selected drafting or editorial action, including the dedicated distill action used by Phase 1.",
|
||||
"context": "The selected ideas or current passage supplied by Thinkloom."
|
||||
}
|
||||
}
|
||||
|
||||
+50
-5
@@ -105,6 +105,7 @@ struct DraftingPromptConfig {
|
||||
system_prompt: String,
|
||||
draft_prompt_template: String,
|
||||
editorial_prompt_template: String,
|
||||
distillation_prompt_template: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@@ -189,6 +190,23 @@ fn prompt_config_dir(app: &AppHandle) -> CommandResult<PathBuf> {
|
||||
})
|
||||
}
|
||||
|
||||
fn merge_missing_prompt_fields(current: &mut Value, defaults: &Value) -> bool {
|
||||
let (Some(current_object), Some(default_object)) =
|
||||
(current.as_object_mut(), defaults.as_object())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let mut changed = false;
|
||||
for (key, default_value) in default_object {
|
||||
if let Some(current_value) = current_object.get_mut(key) {
|
||||
changed |= merge_missing_prompt_fields(current_value, default_value);
|
||||
} else {
|
||||
current_object.insert(key.clone(), default_value.clone());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
changed
|
||||
}
|
||||
fn ensure_prompt_files_at(app: &AppHandle) -> CommandResult<PathBuf> {
|
||||
let directory = prompt_config_dir(app)?;
|
||||
fs::create_dir_all(&directory).map_err(|error| {
|
||||
@@ -202,6 +220,32 @@ fn ensure_prompt_files_at(app: &AppHandle) -> CommandResult<PathBuf> {
|
||||
let path = directory.join(name);
|
||||
if !path.exists() {
|
||||
atomic_write(&path, contents.as_bytes())?;
|
||||
} else if name.ends_with(".json") {
|
||||
let existing = fs::read_to_string(&path).map_err(|error| {
|
||||
CommandError::io("Could not read prompt configuration for migration", error)
|
||||
})?;
|
||||
if let (Ok(mut current), Ok(defaults)) = (
|
||||
serde_json::from_str::<Value>(&existing),
|
||||
serde_json::from_str::<Value>(contents),
|
||||
) {
|
||||
let mut changed = merge_missing_prompt_fields(&mut current, &defaults);
|
||||
if name == "conversation.json" {
|
||||
let legacy_system = current
|
||||
.get("systemPrompt")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|prompt| !prompt.contains("{{persona_instruction}}"))
|
||||
.map(str::to_owned);
|
||||
if let Some(legacy_system) = legacy_system {
|
||||
current["systemPrompt"] = Value::String(format!(
|
||||
"{{{{persona_instruction}}}}\n\n{{{{genre_instruction}}}}\n\nProject lore and context:\n{{{{lore_context}}}}\n\n{{{{web_search_instruction}}}}\n\n{legacy_system}"
|
||||
));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
write_json(&path, ¤t)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(directory)
|
||||
@@ -297,7 +341,7 @@ fn prompts_for_request(
|
||||
})?;
|
||||
variables.insert("challenge_guidance".into(), guidance.clone());
|
||||
Ok((
|
||||
config.system_prompt,
|
||||
render_prompt_template(&config.system_prompt, &variables)?,
|
||||
render_prompt_template(&config.user_prompt_template, &variables)?,
|
||||
))
|
||||
}
|
||||
@@ -308,6 +352,7 @@ fn prompts_for_request(
|
||||
|| config.system_prompt.trim().is_empty()
|
||||
|| config.draft_prompt_template.trim().is_empty()
|
||||
|| config.editorial_prompt_template.trim().is_empty()
|
||||
|| config.distillation_prompt_template.trim().is_empty()
|
||||
{
|
||||
return Err(CommandError::new(
|
||||
"PROMPT_CONFIG_INVALID",
|
||||
@@ -318,10 +363,10 @@ fn prompts_for_request(
|
||||
true,
|
||||
));
|
||||
}
|
||||
let template = if required_prompt_variable(&variables, "action")? == "draft" {
|
||||
&config.draft_prompt_template
|
||||
} else {
|
||||
&config.editorial_prompt_template
|
||||
let template = match required_prompt_variable(&variables, "action")? {
|
||||
"draft" => &config.draft_prompt_template,
|
||||
"distill" => &config.distillation_prompt_template,
|
||||
_ => &config.editorial_prompt_template,
|
||||
};
|
||||
Ok((
|
||||
config.system_prompt,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Thinkloom",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"identifier": "com.thinkloom.desktop",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
Reference in New Issue
Block a user