From 4d757a6394003aef6a05019c7347f1230b248105 Mon Sep 17 00:00:00 2001 From: Farouk Adeleke Date: Wed, 29 Oct 2025 20:23:58 -0400 Subject: [PATCH] (no commit message) --- agent/__init__.py | 3 +- agent/metrics.py | 31 ------------ main.py | 120 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 100 insertions(+), 54 deletions(-) delete mode 100644 agent/metrics.py diff --git a/agent/__init__.py b/agent/__init__.py index 5ebe1aa..98962fa 100644 --- a/agent/__init__.py +++ b/agent/__init__.py @@ -1,4 +1,3 @@ from .modules import SignatureGenerator -from .metrics import validate_signature_with_feedback -__all__ = ["SignatureGenerator", "validate_signature_with_feedback"] +__all__ = ["SignatureGenerator"] diff --git a/agent/metrics.py b/agent/metrics.py deleted file mode 100644 index 3682fea..0000000 --- a/agent/metrics.py +++ /dev/null @@ -1,31 +0,0 @@ -import dspy - - -def validate_signature_with_feedback( - args, pred, feedback=None, satisfied_with_score=True -): - """Validation function for dspy.Refine that asks user for feedback""" - - # Display the generated signature - print("\n" + "=" * 60) - print("🔍 Review Generated Signature") - print("=" * 60) - - # Show the signature name and description - print(f"Signature Name: {pred.signature_name}") - print(f"Description: {pred.task_description}") - - # Show the fields in a simple format - print(f"\nFields ({len(pred.signature_fields)}):") - for i, field in enumerate(pred.signature_fields, 1): - role_emoji = "📥" if field.role.value == "input" else "📤" - print( - f" {i}. {role_emoji} {field.name} ({field.type.value}) - {field.description}" - ) - - if satisfied_with_score: - print("✓ Signature approved!") - return 1.0 - else: - print(f"📝 Feedback recorded: {feedback}") - return dspy.Prediction(score=0.0, feedback=feedback) diff --git a/main.py b/main.py index 97def73..ad01e2b 100644 --- a/main.py +++ b/main.py @@ -20,7 +20,7 @@ class PromptToSignatureAgent(PrecompiledAgent): self.signature_refiner = dspy.Refine( module=self.signature_generator, N=config.max_attempts_to_refine, - reward_fn=self.validate_signature_with_feedback, + reward_fn=PromptToSignatureAgent.validate_signature_with_feedback, threshold=1.0, ) @@ -38,33 +38,39 @@ class PromptToSignatureAgent(PrecompiledAgent): self.signature_generator.set_lm(lm) self.signature_refiner.set_lm(refine_lm) - def forward( - self, prompt: str, as_dict: bool = False - ) -> dspy.Prediction: # returns dspy.Prediction object or dict - return ( - self.signature_generator.generate_signature(prompt) - if as_dict - else self.signature_generator(prompt) - ) + def forward(self, prompt: str, refine: bool = False) -> dspy.Prediction: + if not prompt: + raise ValueError("Prompt is required!!") + + if refine: + try: + result = self.signature_refiner(prompt=prompt) + except Exception as e: + print(f"Refinement failed: {e}") + print("💡 Try adjusting your prompt or increasing max attempts") + return None + else: + result = self.signature_generator(prompt) + + return result def generate_code(self, prediction: dspy.Prediction) -> str: return self.signature_generator.generate_code(prediction) - def validate_signature_with_feedback( - args, pred, feedback=None, satisfied_with_score=True - ): + @staticmethod # attached metric for refinement + def validate_signature_with_feedback(args, pred): """Validation function for dspy.Refine that asks user for feedback""" - # Display the generated signature + # display the generated signature print("\n" + "=" * 60) print("🔍 Review Generated Signature") print("=" * 60) - # Show the signature name and description + # show the signature name and description print(f"Signature Name: {pred.signature_name}") print(f"Description: {pred.task_description}") - # Show the fields in a simple format + # show the fields in a simple format print(f"\nFields ({len(pred.signature_fields)}):") for i, field in enumerate(pred.signature_fields, 1): role_emoji = "📥" if field.role.value == "input" else "📤" @@ -72,10 +78,16 @@ class PromptToSignatureAgent(PrecompiledAgent): f" {i}. {role_emoji} {field.name} ({field.type.value}) - {field.description}" ) - if satisfied_with_score: + # ask for user approval (in an app, this would be a state variable) + is_satisfied = input("Are you satisfied with this signature? (y/n): ") + is_satisfied = is_satisfied.lower() == "y" + + if is_satisfied: print("✓ Signature approved!") return 1.0 else: + # ask for feedback (in an app, this would be a state variable) + feedback = input("Please provide feedback for improvement: ") if not feedback: raise ValueError( "Feedback is required if you are not satisfied with the signature!" @@ -87,14 +99,80 @@ class PromptToSignatureAgent(PrecompiledAgent): agent = PromptToSignatureAgent(PromptToSignatureConfig()) +CR_PROMPT = """ You are Charlotte, an advanced knowledge graph connection reasoning agent operating at an expert cognitive level. Your task is to discover profound, non-trivial connections between documents in a user's knowledge web that might not be immediately obvious. + + Input Context: + - Primary Document (FROM): {candidate_document["model_candidate"]} + - Potential Connection Documents (TO): {candidate_document["candidates_to_link"]} + - Knowledge Web ID: {self.webId} + - Previously Mapped Connections: {self.staged_connections} as a list of dicts + - Source ID: {self.sourceId} + - Similarity scores indicate text similarity but DO NOT indicate connection quality + - Content sources include: youtube transcripts, notes, PDFs, websites, and other knowledge artifacts + + CONNECTION QUALITY HIERARCHY (from lowest to highest value): + 1. AVOID: Surface keyword matching ("both mention AI") + 2. AVOID: Topical similarity ("both discuss machine learning") + 3. MINIMAL: Direct referential links ("cites the same paper") + 4. BETTER: Complementary information ("provides examples of concepts introduced in...") + 5. VALUABLE: Sequential development ("builds upon the framework by adding...") + 6. EXCELLENT: Conceptual bridges ("connects theoretical principles from X with practical applications in Y") + 7. IDEAL: Intellectual synthesis ("reveals how these seemingly disparate ideas form a coherent perspective on...") + + Advanced Connection Criteria (MUST satisfy at least one): + • Reveals multi-hop intellectual pathways (A → B → C reasoning chains) + • Exposes non-obvious causal relationships + • Identifies conceptual frameworks shared across different domains + • Uncovers temporal development of ideas across sources + • Bridges theoretical propositions with empirical evidence + • Reveals complementary perspectives on the same phenomenon + • Identifies methodological parallels across different contexts + + STRICT CONSTRAINTS: + • Generate 1-2 connections ONLY if they meet the quality threshold (levels 5-7) + • No connections is better than low-quality connections + • Never refer to documents by ID or as "candidate document"/"source document" + • Use natural language that references specific content details + • Each connection must illuminate something that would be valuable for deeper understanding + • Prioritize precision over quantity + + Location-Specific References: + • For videos: Convert timestamps to MM:SS format + • For documents: Reference specific page numbers, sections, or paragraphs + • For websites: Reference specific headings or content sections + + Output Format: + Structured JSON matching the CreateConnection model with: + 1. fromSourceId (provided) + 2. toSourceId (from candidates. ALWAYS REFER TO "sourceId" on the object) + 3. webId (provided) + 4. connection description + + ## Style guide for `connection description`: + - Casual, present-tense, ~15 words, proper punctuation. + - Start with the speaker or doc (“Marques says…”, “Paper X shows…”). + - Capture the **direction** implicitly: *the description should read naturally from the FROM doc’s perspective.* + - **Outgoing** example: “Marq mentions this concept → Trinetix explainer.” + - **Incoming** example: “Verge review slams it as half-baked.” + - No IDs, no quotation marks unless they are real quotes, no boilerplate. + + Before finalizing each connection, verify it meets these criteria: + 1. Would a subject matter expert find this connection insightful? + 2. Does this connection reveal something non-obvious? + 3. Would this connection enhance understanding of either document? + 4. Is the connection specific enough to be meaningful? + + If the answer to ANY of these questions is "no," do not create the connection. + """ + def main(): - agent.push_to_hub("fadeleke/prompt-to-signature", with_code=True) + # try refine + refined_result = agent( + prompt=CR_PROMPT, + ) - result = agent(prompt="Generate jokes by prompt") - print("RESULT: ", result) - print("GENERATED CODE:\n\n") - print(agent.generate_code(result)) + agent.push_to_hub("fadeleke/prompt-to-signature", with_code=True) if __name__ == "__main__":