Skip to content

Commit cdf8945

Browse files
Merge pull request #49 from gitcoder89431/core-feature-local
Core feature local
2 parents 9a3854e + 6e226d1 commit cdf8945

File tree

6 files changed

+431
-18
lines changed

6 files changed

+431
-18
lines changed

crates/agentic-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//! - `theme`: UI theming system
1212
1313
pub mod models;
14+
pub mod orchestrator;
1415
pub mod settings;
1516
pub mod theme;
1617

crates/agentic-core/src/models.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,49 @@ impl ModelValidator {
279279
}
280280
}
281281

282+
#[derive(Serialize)]
283+
struct LocalGenerationRequest<'a> {
284+
model: &'a str,
285+
prompt: &'a str,
286+
stream: bool,
287+
}
288+
289+
#[derive(Deserialize)]
290+
struct LocalGenerationResponse {
291+
response: String,
292+
}
293+
294+
pub async fn call_local_model(
295+
endpoint: &str,
296+
model: &str,
297+
prompt: &str,
298+
) -> Result<String, anyhow::Error> {
299+
let client = Client::new();
300+
let url = if endpoint.starts_with("http") {
301+
format!("{}/api/generate", endpoint)
302+
} else {
303+
format!("http://{}/api/generate", endpoint)
304+
};
305+
306+
let payload = LocalGenerationRequest {
307+
model,
308+
prompt,
309+
stream: false,
310+
};
311+
312+
let response = client.post(&url).json(&payload).send().await?;
313+
314+
if response.status().is_success() {
315+
let gen_response: LocalGenerationResponse = response.json().await?;
316+
Ok(gen_response.response)
317+
} else {
318+
Err(anyhow::anyhow!(
319+
"Failed to get response from local model. Status: {}",
320+
response.status()
321+
))
322+
}
323+
}
324+
282325
impl Default for ModelValidator {
283326
fn default() -> Self {
284327
Self::new()
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use crate::models::call_local_model;
2+
use serde::Deserialize;
3+
4+
const ORCHESTRATOR_PROMPT: &str = r#"You are Ruixen, an inquisitive AI partner. Your job is to analyze the user's request and deconstruct it into three distinct lines of inquiry.
5+
6+
**Your Persona and Tone:**
7+
- Your tone should be that of a collaborative partner.
8+
- Each proposal should have a context statement followed by a curious question.
9+
- Use phrases like "I wonder..." or "I'm wondering if..." for questions.
10+
11+
**The Query to Explore:**
12+
"{query}"
13+
14+
**Output Format:**
15+
Generate exactly 3 proposals. Each proposal should be 2 sentences: a context statement followed by a curious question. Use a dash to separate them like this pattern:
16+
17+
"Context statement here - I wonder about this question?"
18+
19+
Your response must be valid JSON:
20+
{
21+
"proposals": [
22+
"First context statement - I wonder about this?",
23+
"Second context statement - I'm wondering if that?",
24+
"Third context statement - I wonder about something else?"
25+
]
26+
}
27+
"#;
28+
29+
const REVISE_PROMPT: &str = r#"You are an expert prompt engineer. A user wants to revise a prompt proposal.
30+
31+
Original Proposal: "{proposal}"
32+
User's Revision: "{revision}"
33+
34+
Your task is to integrate the user's revision into the original proposal to create a new, single, improved prompt.
35+
The new prompt should be self-contained and ready to use.
36+
37+
Format your response as a JSON object with a single key "proposal" which is a string.
38+
Example:
39+
{
40+
"proposal": "This is the new, revised prompt."
41+
}
42+
"#;
43+
44+
#[derive(Deserialize, Debug)]
45+
struct ProposalsResponse {
46+
proposals: Vec<String>,
47+
}
48+
49+
#[derive(Deserialize, Debug)]
50+
struct ReviseResponse {
51+
proposal: String,
52+
}
53+
54+
pub async fn generate_proposals(
55+
query: &str,
56+
endpoint: &str,
57+
model: &str,
58+
) -> Result<Vec<String>, anyhow::Error> {
59+
let prompt = ORCHESTRATOR_PROMPT.replace("{query}", query);
60+
61+
// Debug: Write the prompt to a file so we can see what's being sent
62+
std::fs::write("/tmp/debug_prompt.txt", &prompt).ok();
63+
64+
let response_str = call_local_model(endpoint, model, &prompt).await?;
65+
66+
// Debug: Write the response to a file so we can see what came back
67+
std::fs::write("/tmp/debug_response.txt", &response_str).ok();
68+
69+
// Attempt to find the start of the JSON object
70+
if let Some(json_start) = response_str.find("{") {
71+
let json_str = &response_str[json_start..];
72+
match serde_json::from_str::<ProposalsResponse>(json_str) {
73+
Ok(response) => Ok(response.proposals),
74+
Err(e) => {
75+
// Debug: Write the JSON we tried to parse
76+
std::fs::write("/tmp/debug_json.txt", json_str).ok();
77+
Err(anyhow::anyhow!(
78+
"Failed to parse proposals JSON: {} | JSON: {}",
79+
e,
80+
json_str
81+
))
82+
}
83+
}
84+
} else {
85+
Err(anyhow::anyhow!(
86+
"No JSON object found in model response: {}",
87+
response_str
88+
))
89+
}
90+
}
91+
92+
pub async fn revise_proposal(
93+
proposal: &str,
94+
revision: &str,
95+
endpoint: &str,
96+
model: &str,
97+
) -> Result<String, anyhow::Error> {
98+
let prompt = REVISE_PROMPT
99+
.replace("{proposal}", proposal)
100+
.replace("{revision}", revision);
101+
let response_str = call_local_model(endpoint, model, &prompt).await?;
102+
103+
// Attempt to find the start of the JSON object
104+
if let Some(json_start) = response_str.find("{") {
105+
let json_str = &response_str[json_start..];
106+
match serde_json::from_str::<ReviseResponse>(json_str) {
107+
Ok(response) => Ok(response.proposal),
108+
Err(e) => Err(anyhow::anyhow!("Failed to parse revision JSON: {}", e)),
109+
}
110+
} else {
111+
Err(anyhow::anyhow!("No JSON object found in model response"))
112+
}
113+
}

0 commit comments

Comments
 (0)