Skip to content

Commit

Permalink
feat: Use hosted langmem for reflections
Browse files Browse the repository at this point in the history
  • Loading branch information
bracesproul committed Jan 31, 2025
1 parent 75a1a46 commit 3933b50
Showing 1 changed file with 51 additions and 68 deletions.
119 changes: 51 additions & 68 deletions src/agents/reflection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,11 @@ import {
START,
StateGraph,
} from "@langchain/langgraph";
import { z } from "zod";
import { ChatAnthropic } from "@langchain/anthropic";
import {
getReflectionsPrompt,
putReflectionsPrompt,
} from "../../utils/reflections.js";
import { REFLECTION_PROMPT, UPDATE_RULES_PROMPT } from "./prompts.js";

const newRuleSchema = z.object({
newRule: z.string().describe("The new rule to create."),
});

const updateRulesetSchema = z
.object({
updatedRuleset: z.string().describe("The full updated ruleset."),
})
.describe("The updated ruleset.");
import { Client } from "@langchain/langgraph-sdk";

const ReflectionAnnotation = Annotation.Root({
/**
Expand All @@ -39,75 +27,70 @@ const ReflectionAnnotation = Annotation.Root({
userResponse: Annotation<string>,
});

const UPDATE_INSTRUCTIONS = `Analyze the following to determine if rules prompt updates are needed:
1. Current rules prompt (current_prompt)
2. Generated social media post (session)
3. User feedback on the post (feedback)
If the user's feedback explicitly requests changes:
1. Create or update rules that directly address the feedback
2. Keep each rule clear, specific, and concise
3. If a new rule conflicts with an existing one, use the new rule
4. Only add rules that are explicitly mentioned in the user's feedback
Guidelines for updates:
- Do not infer or assume rules beyond what's explicitly stated
- Do not add rules based on implicit feedback
- Do not overgeneralize the feedback
- Combine existing rules if it improves clarity without losing specificity
Output only the updated rules prompt, with no additional context or instructions.`;

async function reflection(
state: typeof ReflectionAnnotation.State,
config: LangGraphRunnableConfig,
): Promise<Partial<typeof ReflectionAnnotation.State>> {
if (!config.store) {
throw new Error("No store provided");
}
const model = new ChatAnthropic({
model: "claude-3-5-sonnet-latest",
temperature: 0,
});

const generateNewRuleModel = model.bindTools([
{
name: "new_rule",
description:
"Create a new rule based on the provided text. Only call this tool if a new rule is needed.",
schema: newRuleSchema,
},
]);
const formattedPrompt = REFLECTION_PROMPT.replace(
"{ORIGINAL_POST}",
state.originalPost,
)
.replace("{NEW_POST}", state.newPost)
.replace("{USER_RESPONSE}", state.userResponse);

const result = await generateNewRuleModel.invoke([
{
role: "user",
content: formattedPrompt,
},
]);

const toolCalls = result.tool_calls || [];
if (!toolCalls.length) {
// No new rule needed
return {};
}

const newRule = toolCalls[0].args.newRule as string;
if (!newRule) {
// Called tool but didn't return a rule
return {};
}
const langMemClient = new Client({
apiUrl:
"https://langmem-v0-544fccf4898a5e3c87bdca29b5f9ab21.us.langgraph.app",
});

const existingRules = await getReflectionsPrompt(config);

if (!existingRules?.length) {
// No rules exist yet. Create and return early.
await putReflectionsPrompt(config, newRule);
return {};
}
const conversation = [{ role: "assistant", content: state.originalPost }];
const feedback = {
user_feedback: state.userResponse,
};
const threads = [[conversation, feedback]];

const updateRulesetModel = model.withStructuredOutput(updateRulesetSchema, {
name: "update_ruleset",
});
const updateRulesetPrompt = UPDATE_RULES_PROMPT.replace(
"{EXISTING_RULES}",
existingRules,
).replace("{NEW_RULE}", newRule);
const updateRulesetResult = await updateRulesetModel.invoke([
{
role: "user",
content: updateRulesetPrompt,
const { thread_id } = await langMemClient.threads.create();
console.log("BEFORE AWAITING RUN!");
const result = await langMemClient.runs.wait(thread_id, "prompt_optimizer", {
input: {
prompts: [
{
name: "Update Prompt",
prompt: existingRules,
when_to_update: "Whenever the user provides feedback.",
update_instructions: UPDATE_INSTRUCTIONS,
},
],
threads: threads,
},
config: {
configurable: { model: "claude-3-5-sonnet-latest", kind: "metaprompt" },
},
]);
});

console.dir(result, { depth: null });

const updated = (result as Record<string, any>).updated_prompts[0].prompt;

await putReflectionsPrompt(config, updateRulesetResult.updatedRuleset);
await putReflectionsPrompt(config, updated);

return {};
}
Expand Down

0 comments on commit 3933b50

Please sign in to comment.