Skip to content

Instantly share code, notes, and snippets.

@tydev-new
Last active January 3, 2026 16:24
Show Gist options
  • Select an option

  • Save tydev-new/1e994191a96bb502c53967c24c426940 to your computer and use it in GitHub Desktop.

Select an option

Save tydev-new/1e994191a96bb502c53967c24c426940 to your computer and use it in GitHub Desktop.
Agent Design Playground - Ch.4 Reflection (by sys2)
/**
* CHAPTER 4: REFLECTION (VANILLA JS)
*
* This pattern forces the agent to critique and refine its own output in a loop before showing the final answer to the user. It is used to catch hallucinations, logic errors, or safety violations that often occur in a "first draft" generation.
*
* The agent generates an initial output, explicitly critiques it
* to identify flaws (bugs, tone, edge cases), and then generates
* a refined version based on that self-correction.
*
* This improves robustness compared to a "zero-shot" generation.
*/
// --- CONFIGURATION ---
const API_KEY = process.env.API_KEY;
const MODEL_ID = "gemini-2.5-flash";
// --- TRACER & DAG UTILITIES ---
class SimpleTracer {
constructor() {
this.spans = [];
}
startSpan(name, input = null, parentId = null) {
const span = {
id: crypto.randomUUID(),
name,
parentId,
input,
output: null,
status: 'RUNNING',
startTime: Date.now()
};
this.spans.push(span);
console.debug(`[Tracer] Started span: ${name}`);
return span;
}
endSpan(spanId, output) {
const span = this.spans.find(s => s.id === spanId);
if (span) {
span.output = output;
span.status = 'COMPLETED';
span.endTime = Date.now();
console.debug(`[Tracer] Ended span: ${span.name}`);
}
}
publishGraph() {
console.log("\n--- 📊 TRACE COMPLETE: UPDATING DIAGRAM ---");
if (window.__setGraphDefinition) {
window.__setGraphDefinition(JSON.stringify(this.spans));
}
}
}
const tracer = new SimpleTracer();
// --- CORE API LOGIC ---
async function callGemini(textPrompt, temperature = 0) {
const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL_ID}:generateContent?key=${API_KEY}`;
const payload = {
contents: [{ parts: [{ text: textPrompt }] }],
generationConfig: { temperature }
};
const response = await fetch(API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`API Error: ${response.status}`);
const data = await response.json();
return data.candidates?.[0]?.content?.parts?.[0]?.text || "";
}
// --- STEP DEFINITIONS ---
// Step 1: Generate a quick, initial draft
async function generateDraft(goal, parentId) {
const span = tracer.startSpan('generateDraft', { goal }, parentId);
try {
console.log("[Generator] Drafting initial solution...");
const prompt = `Write a Python function for this goal. Keep it simple, do not worry about optimization yet.
Goal: ${goal}`;
const response = await callGemini(prompt, 0.7);
tracer.endSpan(span.id, response);
return { result: response, spanId: span.id };
} catch(e) { throw e; }
}
// Step 2: Critique the draft (The Reflection)
async function critiqueCode(code, parentId) {
const span = tracer.startSpan('critiqueCode', { code }, parentId);
try {
console.log("[Critic] Reviewing code for efficiency and edge cases...");
const prompt = `Review this Python code. Identify any performance issues (Big O) or missing edge cases.
Be critical.
Code:
${code}`;
const response = await callGemini(prompt, 0);
tracer.endSpan(span.id, response);
return { result: response, spanId: span.id };
} catch(e) { throw e; }
}
// Step 3: Refine based on critique
async function refineCode(originalCode, critique, parentId) {
const span = tracer.startSpan('refineCode', { originalCode, critique }, parentId);
try {
console.log("[Generator] Rewriting code based on feedback...");
const prompt = `Rewrite the following Python code to address the critique.
Original Code:
${originalCode}
Critique:
${critique}
Provide ONLY the optimized Python code.`;
const response = await callGemini(prompt, 0.2);
tracer.endSpan(span.id, response);
return { result: response, spanId: span.id };
} catch(e) { throw e; }
}
// --- EXECUTION FLOW ---
console.log("Starting Reflection Agent...");
// A classic problem where naive recursion is terrible (O(2^n))
const inputTask = "Calculate the nth Fibonacci number.";
console.info("--- INPUT TASK ---");
console.info(inputTask);
try {
if (!API_KEY) throw new Error("API_KEY missing.");
// 1. Initial Draft
const draft = await generateDraft(inputTask, null);
console.log("--- 1. INITIAL DRAFT (Intermediate) ---");
console.log(draft.result);
// 2. Reflection (Critique)
// We link this to the draft's spanId
const critique = await critiqueCode(draft.result, draft.spanId);
console.log("--- 2. CRITIQUE (Intermediate) ---");
console.log(critique.result);
// 3. Refinement
// We link this to the critique's spanId
const final = await refineCode(draft.result, critique.result, critique.spanId);
console.info("--- 3. REFINED SOLUTION (Final) ---");
console.info(final.result);
tracer.publishGraph();
} catch (e) {
console.error("Execution failed:", e);
}
/**
* CHAPTER 1: PROMPT CHAINING (VANILLA JS)
*
This pattern decomposes a complex workflow into a sequence of smaller, manageable sub-prompts where the output of one step becomes the input for the next. It prevents the model from losing focus on long tasks and allows for intermediate validation between steps.
*
* Key Benefit: Solves the "Cognitive Load" problem. By enforcing a structured linear flow, it dramatically increases reliability compared to a single, overloaded prompt.
* Flow:
* Step 1. EXTRACT: Isolate key technical specs from raw marketing text.
* Step 2. FORMAT: Convert the natural language specs into strict, usable JSON.
*/
// --- 1. CONFIGURATION ---
const API_KEY = process.env.API_KEY;
const MODEL_ID = "gemini-3-flash-preview";
const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL_ID}:generateContent?key=${API_KEY}`;
// --- 2. TRACER & DAG UTILITIES (Mini Observability Layer) ---
class SimpleTracer {
constructor() {
this.spans = [];
this.startTime = Date.now();
}
startSpan(name, input = null, parentId = null) {
const span = {
id: crypto.randomUUID(),
name,
parentId, // Tracks the 'Edge'
input,
output: null,
status: 'RUNNING',
startTime: Date.now()
};
this.spans.push(span);
console.debug(`[Tracer] Started span: ${name}`);
return span;
}
endSpan(spanId, output) {
const span = this.spans.find(s => s.id === spanId);
if (span) {
span.output = output;
span.status = 'COMPLETED';
span.endTime = Date.now();
console.debug(`[Tracer] Ended span: ${span.name}`);
}
}
publishGraph() {
console.log("\n--- 📊 TRACE COMPLETE: UPDATING DIAGRAM ---");
// Send raw spans to UI for rendering
if (window.__setGraphDefinition) {
window.__setGraphDefinition(JSON.stringify(this.spans));
} else {
console.warn("Graph visualization hook not found.");
}
}
}
// Initialize Global Tracer
const tracer = new SimpleTracer();
// --- 3. CORE API LOGIC ---
// Helper: Native Fetch Wrapper
async function callGemini(textPrompt) {
const payload = {
contents: [{ parts: [{ text: textPrompt }] }]
};
const response = await fetch(API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`API Request Failed: ${response.status} ${response.statusText}`);
}
const data = await response.json();
return data.candidates?.[0]?.content?.parts?.[0]?.text || "";
}
// --- 4. STEP DEFINITIONS (WRAPPED WITH TRACER) ---
async function extractTechnicalSpecs(rawText) {
// START SPAN
const span = tracer.startSpan('extractTechnicalSpecs', { rawText });
try {
console.log("[Step 1] Extracting specifications...");
const prompt = `Extract the technical specifications from: ${rawText}`;
// Core Logic
const result = await callGemini(prompt);
// END SPAN
tracer.endSpan(span.id, result);
return { result, spanId: span.id }; // Return ID to link next step
} catch (e) {
console.error("Step 1 Failed", e);
throw e;
}
}
async function formatToJson(specsText, parentSpanId) {
// START SPAN (Linked to Parent)
const span = tracer.startSpan('formatToJson', { specsText }, parentSpanId);
try {
console.log("[Step 2] Formatting to JSON...");
const prompt = `Transform specs to JSON keys (cpu, memory, storage) only: ${specsText}`;
// Core Logic
const result = await callGemini(prompt);
const cleaned = result.replace(/\`\`\`json/g, "").replace(/\`\`\`/g, "").trim();
// END SPAN
tracer.endSpan(span.id, cleaned);
return { result: cleaned, spanId: span.id };
} catch (e) {
console.error("Step 2 Failed", e);
throw e;
}
}
// --- 5. EXECUTION FLOW ---
console.log("Starting Vanilla JS Chain with Active Tracing...");
const inputData = "The new laptop model features a 3.5 GHz octa-core processor, 16GB of RAM, and a 1TB NVMe SSD.";
console.info("\n--- INPUT ---");
console.info(inputData);
try {
if (!API_KEY) throw new Error("API_KEY missing.");
// Execute Step A
const step1 = await extractTechnicalSpecs(inputData);
console.log("[Result 1]", step1.result);
// Execute Step B (Pass ID to link edges)
const step2 = await formatToJson(step1.result, step1.spanId);
console.info("\n--- FINAL OUTPUT (JSON) ---");
console.info(step2.result);
// Finalize Visualization
tracer.publishGraph();
} catch (error) {
console.error("Chain failed:", error);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment