1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetch } from "https://esm.town/v/std/fetch";
import process from "node:process";
export const runAgent = (async () => {
const { z } = await import("npm:zod");
const { ChatOpenAI } = await import("npm:langchain/chat_models/openai");
const { ChatAnthropic } = await import("npm:langchain/chat_models/anthropic");
const { DynamicTool, Tool, SerpAPI } = await import("npm:langchain/tools");
const { initializeAgentExecutorWithOptions } = await import(
"npm:langchain/agents"
);
const cheerio = await import("npm:cheerio");
const { LLMChain } = await import("npm:langchain/chains");
const { ChatPromptTemplate, HumanMessagePromptTemplate } = await import(
"npm:langchain/prompts"
);
const { StructuredOutputParser, OutputFixingParser } = await import(
"npm:langchain/output_parsers"
);
const model = new ChatOpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "gpt-4",
maxTokens: 2048,
});
const anthropicModel = new ChatAnthropic({
modelName: "claude-v1",
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
temperature: 0,
});
// I had an idea where the agent could scrape individual PR pages, didn't implement
const outputParser = StructuredOutputParser.fromZodSchema(z.array(
z.object({
contributor: z.string().describe(
"The name of the main contributor of the PR",
),
description: z.string().describe(
"A description of what the pull request is for",
),
isFirstContribution: z.boolean().describe(
"Whether it is the contributor's first contribution",
),
pullRequestNumber: z.number().describe("The number of the pull request"),
}).describe("An objects representing a pull request"),
));
const outputFixingParser = OutputFixingParser.fromLLM(model, outputParser);
const tools = [
new DynamicTool({
name: "langchain-release-summarizer",
description:
"Extracts information about the pull requests merged as part of a LangChain release. Takes a GitHub URL as input.",
func: async (input, runManager) => {
const response = await fetch(input.trim());
const pageContent = await response.text();
const $ = cheerio.load(pageContent);
const releaseNotes = $("#repo-content-pjax-container").text();
const prExtractionChain = new LLMChain({
llm: anthropicModel,
prompt: ChatPromptTemplate.fromPromptMessages([
HumanMessagePromptTemplate.fromTemplate(`{query}\n\n{pageContent}`),
]),
outputParser: outputFixingParser,
outputKey: "pullRequests",
});
const summarizationResult = await prExtractionChain.call({
query:
`The following webpage contains the release notes for LangChain, an open source framework for building apps with LLMs.
List all of the pull requests mentioned in the release notes.
Extract the name of the main contributor, a description of the pull request, whether it is their first contribution, and the number of the pull request.
Be extremely verbose!`,
pageContent: releaseNotes,
}, runManager?.getChild());
return JSON.stringify(summarizationResult.pullRequests);
},
}),
new SerpAPI(process.env.SERPAPI_API_KEY, {
location: "Austin,Texas,United States",
hl: "en",
gl: "us",
}),
];
const agent = await initializeAgentExecutorWithOptions(tools, model, {
agentType: "chat-conversational-react-description",
});
const result = await agent.call({
input: `Generate a Twitter thread announcing a new LangChain release.
The release notes are available at this URL: https://github.com/hwchase17/langchainjs/releases/tag/0.0.84.
The release notes include a short description of each merged pull request and the contributor who built the feature.
The thread must start with a header tweet summarizing all the changes in the release.
The thread must contain a tweet for each pull request merged as part of the release that adds a significant feature, and must go into deep detail about what the contribution adds.
If you don't know what something mentioned in the release notes is, look it up with the provided tool so that you can get full context.
Each tweet should also thank the contributor by name, and congratulate them if it is their first contribution and put a medal emoji ๐Ÿฅ‡ next to their name.
Try to avoid repetitive language in your tweets.
Be extremely verbose and descriptive in your final response.
Below is an example of the format that tweets in the final output Twitter thread should follow. Individual tweets should be separated by a "-----" sequence:
-----Header tweet-----
@LangChainAI ๐Ÿฆœ๐Ÿ”— JS/TS 0.0.83 out with loads of @GoogleAI and PaLM!
๐Ÿ’ฌ Google Vertex AI chat model + embeddings
๐Ÿ‘† This is a val. Vals are TypeScript snippets of code, written in the browser and run on our servers. Create scheduled functions, email yourself, and persist small pieces of data โ€” all from the browser.