Files
agentic-studio/network-poc/cli/src/main.rs
2026-04-02 20:27:37 +03:00

166 lines
5.0 KiB
Rust

use clap::{Parser, Subcommand};
use indicatif::{ProgressBar, ProgressStyle};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
use std::time::Duration;
#[derive(Parser)]
#[command(name = "kpn")]
#[command(about = "Kipinä Agent Local CLI", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Alustaa uuden Kipinä-agenttikansion nykyiseen projektiin
Init {
#[arg(short, long, default_value = "kipina-tasks")]
dir: String,
},
/// Ajaa `.md` tiedostossa kuvatun tehtävän Kipinä-verkoston kautta
Run {
/// Polku `.md` työtiedostoon
file: String,
},
}
#[derive(Debug, Deserialize, Serialize)]
struct Frontmatter {
agent: Option<String>,
status: Option<String>,
context: Option<Vec<String>>,
}
#[derive(Serialize)]
struct CompletionRequest {
model: String,
prompt: String,
task_id: String,
}
#[derive(Deserialize)]
struct CompletionResponse {
response: String,
model: String,
tokens_generated: u64,
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
match &cli.command {
Commands::Init { dir } => {
let path = Path::new(dir);
if !path.exists() {
fs::create_dir_all(path).unwrap();
let example = format!("---\nstatus: open\nagent: qwen-coder-3b\ncontext: []\n---\n\n# Tehtävä\nKirjoita tähän mitä haluat verkon koodaavan.");
fs::write(path.join("01-esimerkki.md"), example).unwrap();
println!("✅ Alustettu lokaali agenttikansio: {}", dir);
} else {
println!("⚠️ Kansio {} on jo olemassa.", dir);
}
}
Commands::Run { file } => {
if let Err(e) = run_workflow(file).await {
eprintln!("❌ Virhe: {}", e);
}
}
}
}
async fn run_workflow(filepath: &str) -> Result<(), Box<dyn std::error::Error>> {
let content = fs::read_to_string(filepath)?;
// Yksinkertainen frontmatter-parseri
let mut frontmatter_str = String::new();
let mut body = String::new();
let mut in_frontmatter = false;
let mut fm_found = false;
for line in content.lines() {
if line.trim() == "---" {
if !fm_found {
in_frontmatter = true;
fm_found = true;
continue;
} else if in_frontmatter {
in_frontmatter = false;
continue;
}
}
if in_frontmatter {
frontmatter_str.push_str(line);
frontmatter_str.push('\n');
} else {
body.push_str(line);
body.push('\n');
}
}
let meta: Frontmatter = if fm_found {
serde_yaml::from_str(&frontmatter_str).unwrap_or(Frontmatter { agent: None, status: None, context: None })
} else {
Frontmatter { agent: None, status: None, context: None }
};
let model = meta.agent.unwrap_or_else(|| "qwen-coder-05b".to_string());
// Kerätään kontekstitiedostot
let mut mega_prompt = body.trim().to_string();
if let Some(ctx_files) = meta.context {
mega_prompt.push_str("\n\n=== KONTEKSTI ===\n");
for ctx in ctx_files {
if let Ok(c) = fs::read_to_string(&ctx) {
mega_prompt.push_str(&format!("\n--- Tiedosto: {} ---\n{}\n", ctx, c));
} else {
println!("⚠️ Varoitus: Kontekstitiedostoa {} ei löytynyt.", ctx);
}
}
}
println!("\n🚀 Lähetetään tehtävä Kipinäverkkoon (Malli: {})", model);
let pb = ProgressBar::new_spinner();
pb.enable_steady_tick(Duration::from_millis(100));
pb.set_style(
ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] {msg}")
.unwrap()
.tick_strings(&["", "", "", "", "", "", "", "", "", ""]),
);
pb.set_message("Odotetaan verkon solmua ja laskentaa...");
let task_id = uuid::Uuid::new_v4().to_string();
let client = reqwest::Client::new();
let req = CompletionRequest {
model: model.clone(),
prompt: mega_prompt.clone(),
task_id: task_id.clone(),
};
let res = client.post("http://localhost:3000/api/v1/chat/completions")
.json(&req)
.send()
.await?;
if res.status().is_success() {
let completion: CompletionResponse = res.json().await?;
pb.finish_with_message(format!("Tulos saapui verkolta! ({} tokenia)", completion.tokens_generated));
let new_content = format!("{}\n\n## Kipinä Agentin Ratkaisu\n{}\n", content, completion.response);
let updated_content = new_content.replace("status: open", "status: done");
fs::write(filepath, updated_content)?;
println!("✅ Vastaus tallennettu tiedostoon: {}", filepath);
} else {
pb.finish_with_message("❌ Verkkopyyntö epäonnistui!");
println!("Virhekoodi: {}", res.status());
}
Ok(())
}