Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/target
.*
.idea
.prompts_perssitense_cache
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
[package]
name = "rigscribe"
version = "0.1.4"
version = "0.1.0"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat Cargo.toml

Repository: hghalebi/rigscribe

Length of output: 405


🏁 Script executed:

#!/bin/bash
# Check if there are any dependents or published versions
echo "Checking for published versions on crates.io..."
curl -s "https://crates.io/api/v1/crates/rigscribe" | jq '.versions[] | .num' 2>/dev/null || echo "Not found or not published"

# Check for any references in Cargo.lock (if exists)
if [ -f "Cargo.lock" ]; then
  echo -e "\nChecking Cargo.lock for version references..."
  grep -A2 "name = \"rigscribe\"" Cargo.lock || echo "No references found in Cargo.lock"
fi

# Check git history for version changes
echo -e "\nChecking git history for version changes in Cargo.toml..."
git log --oneline -n 20 -- Cargo.toml 2>/dev/null | head -5 || echo "Git history not available"

Repository: hghalebi/rigscribe

Length of output: 353


Version downgrade violates semantic versioning conventions.

The package is already published on crates.io with version 0.1.4 as the most recent release. Reverting to 0.1.0 will create version conflicts and confusion for dependents. Semantic versioning requires version numbers to move forward, not backward. Either bump the version to 0.1.5 or higher, or clarify the versioning strategy if this is intentional.

🤖 Prompt for AI Agents
In Cargo.toml around line 3, the version was changed back to 0.1.0 which
downgrades the published crate (latest on crates.io is 0.1.4); update the
version to a forward-moving release (e.g., 0.1.5 or higher) to respect semantic
versioning and avoid conflicts with dependents, or add a comment/metadata
explaining an intentional alternative versioning strategy if this rollback is
deliberate.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Bug critical

version = "0.1.5"

The package version has been reverted from 0.1.4 to 0.1.0. This is a version downgrade, which violates the principles of semantic versioning and prevents publishing to a package registry.

Why this is a problem:
Package registries like crates.io enforce that new versions must be greater than all previously published versions. Attempting to publish version 0.1.0 after 0.1.4 has been released will fail, blocking all future releases.

How to fix:
To maintain a valid release history, the version should be incremented based on the nature of the changes. Since this PR contains significant refactoring, incrementing to at least 0.1.5 (for a patch) or 0.2.0 (if there are breaking API changes) is recommended.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

edition = "2024"
description = "A powerful agentic AI coding assistant and prompt optimizer."
license = "MIT"
repository = "https://github.com/hghalebi/rigscribe"

[dependencies]

Expand Down
1 change: 0 additions & 1 deletion src/agents/mod.rs

This file was deleted.

45 changes: 0 additions & 45 deletions src/agents/optimizer.rs

This file was deleted.

3 changes: 0 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ pub enum ScribeError {

#[error("Extraction failed: {0}")]
Extraction(#[from] rig::extractor::ExtractionError),

#[error("Client error: {0}")]
ClientError(#[from] rig::http_client::Error),
}

pub fn map_provider_error(e: rig::completion::PromptError) -> ScribeError {
Expand Down
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
mod error;
pub mod agents;
pub mod tools;
pub mod pipline;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix module name typo.

The module name "pipline" appears to be a typo for "pipeline". This affects the public API surface and should be corrected before release.

🔎 Proposed fix

Rename the file from src/pipline.rs to src/pipeline.rs, then update the module declaration:

-pub mod pipline;
+pub mod pipeline;

And update the import:

-use pipline::optimizer;
+use pipeline::optimizer;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub mod pipline;
pub mod pipeline;
🤖 Prompt for AI Agents
In src/lib.rs around line 2, the module declaration "pub mod pipline;" is a typo
and should be "pipeline"; rename the physical file src/pipline.rs to
src/pipeline.rs, update the module declaration in src/lib.rs to use the
corrected name, and update any use/import paths across the codebase that
reference "pipline" to "pipeline" so the public API and internal references
remain consistent.

mod types;
pub mod utilities;

use std::path::PathBuf;

pub use error::{Result, ScribeError};
use agents::optimizer::optimizer;
use pipline::optimizer;

pub use types::{Artifact, Intent, ScopeId, Specification};

Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ async fn main() -> Result<()> {
// create caching path
let cache_path = PathBuf::from("./.prompts_perssitense_cache");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in variable name.

The variable name contains a typo: "perssitense" should be "persistence".

🔎 Proposed fix
-    let cache_path = PathBuf::from("./.prompts_perssitense_cache");
+    let cache_path = PathBuf::from("./.prompts_persistence_cache");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let cache_path = PathBuf::from("./.prompts_perssitense_cache");
let cache_path = PathBuf::from("./.prompts_persistence_cache");
🤖 Prompt for AI Agents
In src/main.rs around line 9, the PathBuf is created with a typo in the path
variable name "perssitense" — change the string and any variable names
referencing it to use "persistence" (e.g., ".prompts_persistence_cache") so the
path and identifier read correctly; update any other occurrences in the
file/project to match the corrected spelling to avoid runtime or logical errors.

let scribe = RigScribe::new(cache_path);
let id = ScopeId(2032);
let id = ScopeId(2028);
// Input: The raw, often vague user intent.
let raw_prompt = "write a python fonction";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in comment.

The comment contains a typo: "fonction" should be "function".

🔎 Proposed fix
-    let raw_prompt = "write a python fonction";
+    let raw_prompt = "write a python function";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let raw_prompt = "write a python fonction";
let raw_prompt = "write a python function";
🤖 Prompt for AI Agents
In src/main.rs around line 13, the raw_prompt string contains a typo "fonction";
update the string to use the correct English word "function" (i.e., change
"write a python fonction" to "write a python function") so the prompt reads
correctly.

eprintln!("\n\nOptimizing ...\n\n");
Expand Down
168 changes: 168 additions & 0 deletions src/pipline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
use crate::error::map_provider_error;
use crate::error::Result;
use crate::error::ScribeError;
pub use crate::types::{Artifact, Intent, Specification};
use crate::types::{Webquery, MODEL};
use crate::utilities::read_artifact;
use crate::utilities::require_env;
use rig::completion::Prompt;

use rig::prelude::*;
use rig::providers::gemini::Client;
use rig::{completion::ToolDefinition, tool::Tool};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serpscraper::get_markdown_for_query;

#[derive(Serialize, Deserialize)]
pub struct Deconstructor;
impl Tool for Deconstructor {
const NAME: &'static str = "Deconstructor";

type Error = ScribeError;
type Args = Intent;
type Output = Specification;

async fn definition(&self, _prompt: String) -> ToolDefinition {
let schema = schemars::schema_for!(Intent);
let parameters = serde_json::to_value(schema).unwrap();
ToolDefinition {
name: "Deconstructor".to_string(),
description: "this tools take a raw prompte and give back it Specification include goal and constrian".to_string(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typos in tool description.

The description contains typos: "prompte" should be "prompt", and "constrian" should be "constraint".

🔎 Proposed fix
-            description: "this tools take a raw prompte and give back it Specification include goal and constrian".to_string(),
+            description: "This tool takes a raw prompt and returns its Specification including goal and constraints".to_string(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description: "this tools take a raw prompte and give back it Specification include goal and constrian".to_string(),
description: "This tool takes a raw prompt and returns its Specification including goal and constraints".to_string(),
🤖 Prompt for AI Agents
In src/pipline.rs around line 31, the tool description string contains typos:
change "this tools take a raw prompte and give back it Specification include
goal and constrian" to a corrected, grammatical sentence such as "this tool
takes a raw prompt and returns its specification including goal and constraint"
(adjust capitalization/punctuation to match surrounding code style).

parameters: parameters,
}
}

async fn call(&self, args: Self::Args) -> Result<Self::Output> {
println!("[Tool Calling]-> Deconstructor!");
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let architect = client
.agent(MODEL)
.preamble(
"
Role: Senior Solution Architect\n\
Task: Extract constraints and risks and main goal of given request\n\
Output: A short bullet list, no prose
",
)
.build();
let repons = architect.prompt(args.text.clone()).await?;
let spec_extractor = client.extractor::<Specification>(MODEL).build();
let spec = spec_extractor.extract(repons).await;

Ok(spec?)
}
}

#[derive(Deserialize, Debug, Clone, Serialize, JsonSchema)]
pub struct PromptReviewerArgs {
intent: Intent,
spec: Specification,
}
Comment on lines +58 to +62
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Public struct with private fields limits usability.

PromptReviewerArgs is public but its fields are private. This prevents external construction of the struct, which may be intentional for internal-only use. If this struct should be constructable externally, make the fields public. If it's internal-only, consider marking the struct itself as pub(crate).

🔎 Proposed fixes

Option 1: Make fields public (if external construction is needed):

 #[derive(Deserialize, Debug, Clone, Serialize, JsonSchema)]
 pub struct PromptReviewerArgs {
-    intent: Intent,
-    spec: Specification,
+    pub intent: Intent,
+    pub spec: Specification,
 }

Option 2: Make struct internal (if only for tool use):

-pub struct PromptReviewerArgs {
+pub(crate) struct PromptReviewerArgs {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[derive(Deserialize, Debug, Clone, Serialize, JsonSchema)]
pub struct PromptReviewerArgs {
intent: Intent,
spec: Specification,
}
#[derive(Deserialize, Debug, Clone, Serialize, JsonSchema)]
pub struct PromptReviewerArgs {
pub intent: Intent,
pub spec: Specification,
}
Suggested change
#[derive(Deserialize, Debug, Clone, Serialize, JsonSchema)]
pub struct PromptReviewerArgs {
intent: Intent,
spec: Specification,
}
#[derive(Deserialize, Debug, Clone, Serialize, JsonSchema)]
pub(crate) struct PromptReviewerArgs {
intent: Intent,
spec: Specification,
}
🤖 Prompt for AI Agents
In src/pipline.rs around lines 58 to 62, the public struct PromptReviewerArgs
has private fields which prevents external construction; either make the fields
public by changing intent: Intent and spec: Specification to pub intent: Intent
and pub spec: Specification so callers can construct it, or if the type is
intended for internal use only, change the struct visibility to pub(crate)
PromptReviewerArgs (or remove pub) to restrict external access; pick the
appropriate option and update the struct definition accordingly.

#[derive(Serialize, Deserialize)]
pub struct PromptReviewer;
impl Tool for PromptReviewer {
const NAME: &'static str = "PromptReviewer";

type Error = ScribeError;
type Args = PromptReviewerArgs;
type Output = Artifact;

async fn definition(&self, _prompt: String) -> ToolDefinition {
let schema = schemars::schema_for!(PromptReviewerArgs);
let parameters = serde_json::to_value(schema).unwrap();
ToolDefinition {
name: "PromptReviewer".to_string(),
description: "this tools take a raw prompte it will evelaute that given promte wiuth its Specification include goal and constrian".to_string(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typos in tool description.

Multiple typos: "prompte" → "prompt", "evelaute" → "evaluate", "wiuth" → "with", "constrian" → "constraint".

🔎 Proposed fix
-            description: "this tools take a raw prompte it will evelaute that given promte wiuth its Specification include goal and constrian".to_string(),
+            description: "This tool takes a raw prompt and evaluates it with its Specification including goal and constraints".to_string(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description: "this tools take a raw prompte it will evelaute that given promte wiuth its Specification include goal and constrian".to_string(),
description: "This tool takes a raw prompt and evaluates it with its Specification including goal and constraints".to_string(),
🤖 Prompt for AI Agents
In src/pipline.rs around line 77, the tool description string contains multiple
typos; update the description to correct spelling and grammar (e.g., "this tools
take a raw prompte it will evelaute that given promte wiuth its Specification
include goal and constrian" → a clear, corrected sentence such as "this tool
takes a raw prompt and evaluates that prompt against its specification,
including goals and constraints"). Ensure singular/plural agreement ("tool" vs
"tools"), correct verb forms ("takes", "evaluates"), and correct words
("prompt", "evaluate", "with", "constraint"), and keep it as a proper
String::to_string() value.

parameters,
}
}

async fn call(&self, args: Self::Args) -> Result<Self::Output> {
println!("[Tool Calling]-> PromptReviewer!");
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let system_prompt = read_artifact("data/prompt_officer.json")
.await
.unwrap()
.system_prompt;
Comment on lines +86 to +89
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Bug critical

        let system_prompt = read_artifact("data/prompt_officer.json")
            .await?
            .system_prompt;

Multiple instances of .unwrap() being used on Result types in src/pipline.rs (lines 86-89, 127-128, 134-137) which can cause the application to panic and crash if the operation fails. This bypasses the established error handling pattern.

This issue appears in multiple locations:

  • src/pipline.rs: Lines 86-89
  • src/pipline.rs: Lines 127-128
  • src/pipline.rs: Lines 134-137
  • src/pipline.rs: Lines 86-89
    Replace all instances of .unwrap() with the ? operator to properly propagate errors through the existing Result/ScribeError system.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

let prompt_reviewer = client.agent(MODEL).preamble(system_prompt.as_str()).build();
let input = format!("
Critisize following prompt base on given property:
Goal:\n{}\n\nConstraints:\n{}\n\nDraft:\n{}\n\n\
Instruction: Be highly cretical and persimiste and find every defit or any point which could be better. and use all best practice and if needed use websearch. \n",
args.spec.goal, args.spec.constraints, args.intent.text);
Comment on lines +91 to +95
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typos in prompt text.

Typos: "Critisize" → "Criticize", "persimiste" → "pessimistic", "defit" → "defect".

🔎 Proposed fix
         let input = format!("
-        Critisize following prompt base on given property:
+        Criticize following prompt based on given property:
         Goal:\n{}\n\nConstraints:\n{}\n\nDraft:\n{}\n\n\
-        Instruction: Be highly cretical and persimiste and find every defit or any point which could be better. and use all best practice and if needed use websearch.  \n",
+        Instruction: Be highly critical and pessimistic and find every defect or any point which could be better. Use all best practices and if needed use websearch.\n",
                             args.spec.goal, args.spec.constraints, args.intent.text);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let input = format!("
Critisize following prompt base on given property:
Goal:\n{}\n\nConstraints:\n{}\n\nDraft:\n{}\n\n\
Instruction: Be highly cretical and persimiste and find every defit or any point which could be better. and use all best practice and if needed use websearch. \n",
args.spec.goal, args.spec.constraints, args.intent.text);
let input = format!("
Criticize following prompt based on given property:
Goal:\n{}\n\nConstraints:\n{}\n\nDraft:\n{}\n\n\
Instruction: Be highly critical and pessimistic and find every defect or any point which could be better. Use all best practices and if needed use websearch.\n",
args.spec.goal, args.spec.constraints, args.intent.text);
🤖 Prompt for AI Agents
In src/pipline.rs around lines 91 to 95, the prompt string contains several
typographical errors; update the text to correct spelling and improve clarity by
changing "Critisize" to "Criticize", "persimiste" to "pessimistic", and "defit"
to "defect" (also correct "cretical" → "critical" and "persimiste and
persimiste" phrasing if present), and ensure the overall instruction sentence
reads grammatically correct and concise while preserving intent (e.g.,
"Instruction: Be highly critical and pessimistic; find every defect or any point
which could be improved, use best practices and, if needed, web search.").


let repons = prompt_reviewer.prompt(input).await?;
let artifact_extractor = client.extractor::<Artifact>(MODEL).build();
let artifact = artifact_extractor.extract(repons).await;

Ok(artifact?)
}
Comment on lines +82 to +102
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unwrap can cause panic - use proper error handling.

Lines 86-89 use .unwrap() when reading the artifact, which will panic if the file is missing or malformed. This should propagate the error properly using ? operator.

🔎 Proposed fix
         let system_prompt = read_artifact("data/prompt_officer.json")
             .await
-            .unwrap()
+            ?
             .system_prompt;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async fn call(&self, args: Self::Args) -> Result<Self::Output> {
println!("[Tool Calling]-> PromptReviewer!");
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let system_prompt = read_artifact("data/prompt_officer.json")
.await
.unwrap()
.system_prompt;
let prompt_reviewer = client.agent(MODEL).preamble(system_prompt.as_str()).build();
let input = format!("
Critisize following prompt base on given property:
Goal:\n{}\n\nConstraints:\n{}\n\nDraft:\n{}\n\n\
Instruction: Be highly cretical and persimiste and find every defit or any point which could be better. and use all best practice and if needed use websearch. \n",
args.spec.goal, args.spec.constraints, args.intent.text);
let repons = prompt_reviewer.prompt(input).await?;
let artifact_extractor = client.extractor::<Artifact>(MODEL).build();
let artifact = artifact_extractor.extract(repons).await;
Ok(artifact?)
}
async fn call(&self, args: Self::Args) -> Result<Self::Output> {
println!("[Tool Calling]-> PromptReviewer!");
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let system_prompt = read_artifact("data/prompt_officer.json")
.await?
.system_prompt;
let prompt_reviewer = client.agent(MODEL).preamble(system_prompt.as_str()).build();
let input = format!("
Critisize following prompt base on given property:
Goal:\n{}\n\nConstraints:\n{}\n\nDraft:\n{}\n\n\
Instruction: Be highly cretical and persimiste and find every defit or any point which could be better. and use all best practice and if needed use websearch. \n",
args.spec.goal, args.spec.constraints, args.intent.text);
let repons = prompt_reviewer.prompt(input).await?;
let artifact_extractor = client.extractor::<Artifact>(MODEL).build();
let artifact = artifact_extractor.extract(repons).await;
Ok(artifact?)
}
🤖 Prompt for AI Agents
In src/pipline.rs around lines 82 to 102, the call to
read_artifact(...).await.unwrap() can panic if the artifact is missing or
malformed; change it to propagate errors using the ? operator by awaiting
read_artifact and binding its result to a variable (e.g. let artifact =
read_artifact(...).await?;) and then access artifact.system_prompt, ensuring the
function's Result error type supports the propagated error; remove unwrap() and
handle errors via ? so failures return Err instead of panicking.

}

#[derive(Serialize, Deserialize)]
pub struct WebSearcher;
impl Tool for WebSearcher {
const NAME: &'static str = "WebSearcher";
type Error = ScribeError;
type Args = Webquery;
type Output = String;
async fn definition(&self, _prompt: String) -> ToolDefinition {
let schema = schemars::schema_for!(Webquery);
let parameters = serde_json::to_value(schema).unwrap();
ToolDefinition {
name: "WebSearcher".to_string(),
description: "this tools query will search on web and retern result in one string".to_string(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in tool description.

Typo: "retern" should be "return".

🔎 Proposed fix
-            description: "this tools query  will search on web and retern result in one string".to_string(),
+            description: "This tool queries the web and returns results in one string".to_string(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description: "this tools query will search on web and retern result in one string".to_string(),
description: "This tool queries the web and returns results in one string".to_string(),
🤖 Prompt for AI Agents
In src/pipline.rs around line 117, the tool description contains a typo: change
"this tools query  will search on web and retern result in one
string".to_string() to use correct spelling and grammar by replacing "retern"
with "return" (and optionally fix "this tools" -> "this tool's" or "this tool"
and remove double space) so the description reads clearly, e.g. "this tool's
query will search the web and return results in one string".to_string().

parameters,
}
}
async fn call(&self, args: Self::Args) -> Result<Self::Output> {
println!("[Tool Calling]-> WebSearcher");
let api_key = std::env::var("SERPER_API_KEY").map_err(
|e|
ScribeError::Config(format!("SERPER_API_KEY not set: {}", e))
);
let markdown = get_markdown_for_query(&args.query, &api_key?.to_string()).await;
Comment on lines +123 to +127
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Cross File medium

require_env("SERPER_API_KEY")?;
// .unwrap() is safe here because require_env just checked for presence.
let api_key = std::env::var("SERPER_API_KEY").unwrap();
let markdown = get_markdown_for_query(&args.query, &api_key).await;

I noticed the check for SERPER_API_KEY in WebSearcher::call (src/pipline.rs:123-127) is implemented manually, while other parts of the file use the require_env utility from src/utilities.rs. This creates a separate error handling path for a similar task. To keep the codebase consistent and easier to maintain, could we switch this to use the shared require_env utility? This centralizes the validation logic and ensures all configuration error messages are uniform.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Ok(markdown.unwrap().to_string())
}
Comment on lines +121 to +129
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Inconsistent environment variable validation and error handling.

The WebSearcher tool uses a different pattern for environment variable validation compared to other tools. It also uses .unwrap() on line 128 which can panic. Consider using require_env("SERPER_API_KEY")? for consistency, then std::env::var to get the value.

🔎 Proposed fix
     async fn call(&self, args: Self::Args) -> Result<Self::Output> {
         println!("[Tool Calling]-> WebSearcher");
-        let api_key = std::env::var("SERPER_API_KEY").map_err(
-            |e| 
-                ScribeError::Config(format!("SERPER_API_KEY not set: {}", e))
-        );
-        let markdown = get_markdown_for_query(&args.query, &api_key?.to_string()).await;
-        Ok(markdown.unwrap().to_string())
+        require_env("SERPER_API_KEY")?;
+        let api_key = std::env::var("SERPER_API_KEY")
+            .map_err(|e| ScribeError::Config(format!("SERPER_API_KEY not set: {}", e)))?;
+        let markdown = get_markdown_for_query(&args.query, &api_key)
+            .await
+            .map_err(|e| ScribeError::Config(format!("Web search failed: {:?}", e)))?;
+        Ok(markdown)

Note: This assumes get_markdown_for_query returns a Result. If it returns Option, adjust accordingly.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pipline.rs around lines 121 to 129, the code validates the SERPER_API_KEY
inconsistently and calls unwrap() which can panic; replace the ad-hoc
std::env::var/map_err and the subsequent api_key?.to_string() with the project's
helper require_env("SERPER_API_KEY")? to obtain a validated String, then pass
that String (or &str) into get_markdown_for_query and handle its Result/Option
without unwrap by propagating errors with ? or mapping None to a ScribeError,
returning Ok(markdown) only after safely converting to String.

}
pub async fn optimizer(prompt: Intent) -> Result<Artifact> {
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let system_prompt = read_artifact("data/optimizer.json")
.await
.unwrap()
.system_prompt;

let prompt_officer = client
.agent(MODEL)
.preamble(system_prompt.as_str())
.tool(Deconstructor)
.tool(PromptReviewer)
.tool(WebSearcher)
.build();

let input = format!(
"Follow this workflow to optimize the prompt:
1. Use the Deconstructor tool to analyze the goal and constraints of: '{}'
2. Use the PromptReviewer to check and refine the draft.
3. Use the WebSearcher to find the best practice related task/goal.
4. Finally, provide the optimized system prompt.
Constraint: The final output must be the system prompt only, but you MUST use your tools first to arrive at that result.",
prompt.text
);
let optimized_prompt = prompt_officer
.prompt(input)
.multi_turn(10)
.await
.map_err(map_provider_error)?;
let artifact = Artifact {
system_prompt: optimized_prompt,
signed_by: "".to_string(),
};

Ok(artifact)
}
Comment on lines +131 to +168
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unwrap can cause panic - use proper error handling.

Lines 134-137 use .unwrap() when reading the optimizer artifact, which will panic if the file is missing or malformed. Use the ? operator to propagate errors properly.

🔎 Proposed fix
     let system_prompt = read_artifact("data/optimizer.json")
         .await
-        .unwrap()
+        ?
         .system_prompt;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub async fn optimizer(prompt: Intent) -> Result<Artifact> {
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let system_prompt = read_artifact("data/optimizer.json")
.await
.unwrap()
.system_prompt;
let prompt_officer = client
.agent(MODEL)
.preamble(system_prompt.as_str())
.tool(Deconstructor)
.tool(PromptReviewer)
.tool(WebSearcher)
.build();
let input = format!(
"Follow this workflow to optimize the prompt:
1. Use the Deconstructor tool to analyze the goal and constraints of: '{}'
2. Use the PromptReviewer to check and refine the draft.
3. Use the WebSearcher to find the best practice related task/goal.
4. Finally, provide the optimized system prompt.
Constraint: The final output must be the system prompt only, but you MUST use your tools first to arrive at that result.",
prompt.text
);
let optimized_prompt = prompt_officer
.prompt(input)
.multi_turn(10)
.await
.map_err(map_provider_error)?;
let artifact = Artifact {
system_prompt: optimized_prompt,
signed_by: "".to_string(),
};
Ok(artifact)
}
pub async fn optimizer(prompt: Intent) -> Result<Artifact> {
require_env("GEMINI_API_KEY")?;
let client = Client::from_env();
let system_prompt = read_artifact("data/optimizer.json")
.await?
.system_prompt;
let prompt_officer = client
.agent(MODEL)
.preamble(system_prompt.as_str())
.tool(Deconstructor)
.tool(PromptReviewer)
.tool(WebSearcher)
.build();
let input = format!(
"Follow this workflow to optimize the prompt:
1. Use the Deconstructor tool to analyze the goal and constraints of: '{}'
2. Use the PromptReviewer to check and refine the draft.
3. Use the WebSearcher to find the best practice related task/goal.
4. Finally, provide the optimized system prompt.
Constraint: The final output must be the system prompt only, but you MUST use your tools first to arrive at that result.",
prompt.text
);
let optimized_prompt = prompt_officer
.prompt(input)
.multi_turn(10)
.await
.map_err(map_provider_error)?;
let artifact = Artifact {
system_prompt: optimized_prompt,
signed_by: "".to_string(),
};
Ok(artifact)
}
🤖 Prompt for AI Agents
In src/pipline.rs around lines 131 to 168, the code uses .await.unwrap() when
reading the optimizer artifact which can panic; replace the unwrap with proper
error propagation by using the ? operator: await the read_artifact call into a
local variable (e.g. let opt_artifact =
read_artifact("data/optimizer.json").await?;) and then use
opt_artifact.system_prompt, so the function returns an Err instead of panicking
when the file is missing or malformed.

52 changes: 0 additions & 52 deletions src/tools/deconstructor.rs

This file was deleted.

3 changes: 0 additions & 3 deletions src/tools/mod.rs

This file was deleted.

60 changes: 0 additions & 60 deletions src/tools/prompt_reviewer.rs

This file was deleted.

Loading