modular-agent-examples 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/chunking-demo.ts +339 -0
  2. package/cleanup-duplicates.ts +142 -0
  3. package/data/flower.jpg +0 -0
  4. package/generative.ts +128 -0
  5. package/graph/context-example.ts +209 -0
  6. package/graph/data-pipeline/agents.ts +60 -0
  7. package/graph/data-pipeline/fetchers.ts +166 -0
  8. package/graph/data-pipeline/index.ts +282 -0
  9. package/graph/index.ts +154 -0
  10. package/graph/map-example.ts +227 -0
  11. package/graph/metrics-example.ts +238 -0
  12. package/graph/parallel-example.ts +167 -0
  13. package/graph/pipeline-example.ts +225 -0
  14. package/graph/planning-example.ts +406 -0
  15. package/graph/router-example.ts +226 -0
  16. package/graph/sequential-example.ts +141 -0
  17. package/graph/voting-example.ts +159 -0
  18. package/graph-rag/docker-compose.yaml +14 -0
  19. package/graph-rag/index.js +99 -0
  20. package/graph-rag/init-db.sh +7 -0
  21. package/graph-rag/package.json +15 -0
  22. package/history-compression-example.ts +163 -0
  23. package/history-persistence.ts +347 -0
  24. package/index.ts +175 -0
  25. package/ingestion-pipeline.ts +353 -0
  26. package/mcp-airbnb-example.ts +69 -0
  27. package/mcp-http-example.ts +70 -0
  28. package/mcp-stdio-example.ts +63 -0
  29. package/multimodal.ts +144 -0
  30. package/ollama.ts +148 -0
  31. package/openai-compatible.ts +141 -0
  32. package/opensearch-vector-store.ts +342 -0
  33. package/package.json +24 -0
  34. package/pubmed.ts +289 -0
  35. package/reasoning-with-sub-agent.ts +311 -0
  36. package/synchronous/index.ts +48 -0
  37. package/tsconfig.json +8 -0
  38. package/vector-store-filtering.ts +303 -0
  39. package/vector-store.ts +210 -0
  40. package/vectorstore/index.ts +0 -0
  41. package/vectorstore/store/dbService.ts +80 -0
  42. package/voyage-embeddings.ts +99 -0
  43. package/weather-with-sub-agent.ts +276 -0
  44. package/weather.ts +389 -0
package/pubmed.ts ADDED
@@ -0,0 +1,289 @@
1
+ import "dotenv/config";
2
+ import { ClaudeAgent } from "../lib/agents/anthropic/ClaudeAgent";
3
+ import { OpenAiAgent } from "../lib/agents/openai/OpenAiAgent";
4
+ import { Tool } from "../lib/tools/Tool";
5
+ import { createInterface } from "node:readline/promises";
6
+ import { BaseAgent } from "../lib/agents/BaseAgent";
7
+ import { History } from "../lib/history/History";
8
+
9
+ const rl = createInterface({
10
+ input: process.stdin,
11
+ output: process.stdout,
12
+ });
13
+
14
+ // PubMed Search Tool
15
+ const pubmedSearchTool = new Tool({
16
+ name: "pubmedSearch",
17
+ description: `This tool searches PubMed for medical research articles based on search terms and returns metadata for relevant papers.
18
+ It accepts search terms and additional parameters, and returns citation data for matching articles.`,
19
+ inputSchema: {
20
+ type: "object",
21
+ properties: {
22
+ query: {
23
+ type: "string",
24
+ description:
25
+ "Search terms to use for finding medical literature. For best results, use specific medical terminology.",
26
+ },
27
+ maxResults: {
28
+ type: "number",
29
+ description:
30
+ "Maximum number of results to return (default: 10, max: 20).",
31
+ },
32
+ sortBy: {
33
+ type: "string",
34
+ description:
35
+ "How to sort results: 'relevance', 'date' (newest first), or 'cited' (most cited). Default is 'relevance'.",
36
+ },
37
+ },
38
+ required: ["query", "maxResults", "sortBy"],
39
+ },
40
+ execute: async (input): Promise<any> => {
41
+ try {
42
+ // Set defaults and enforce limits
43
+ const maxResults = Math.min(input.maxResults || 10, 20);
44
+ const sortBy = input.sortBy || "relevance";
45
+
46
+ // Use PubMed's E-utilities API
47
+ // First, search for IDs matching the query
48
+ const searchUrl = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&retmode=json&term=${encodeURIComponent(
49
+ input.query
50
+ )}&retmax=${maxResults}&sort=${
51
+ sortBy === "date"
52
+ ? "pub+date"
53
+ : sortBy === "cited"
54
+ ? "most+cited"
55
+ : "relevance"
56
+ }`;
57
+ // console.log(searchUrl);
58
+ const searchResponse = await fetch(searchUrl);
59
+ const searchData = await searchResponse.json();
60
+
61
+ if (
62
+ !searchData.esearchresult ||
63
+ !searchData.esearchresult.idlist ||
64
+ searchData.esearchresult.idlist.length === 0
65
+ ) {
66
+ return {
67
+ count: 0,
68
+ message: "No results found for your query.",
69
+ articles: [],
70
+ };
71
+ }
72
+
73
+ const ids = searchData.esearchresult.idlist;
74
+
75
+ // Then, fetch summary data for these IDs
76
+ const summaryUrl = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id=${ids.join(
77
+ ","
78
+ )}`;
79
+ const summaryResponse = await fetch(summaryUrl);
80
+ const summaryData = await summaryResponse.json();
81
+
82
+ // Process and format results
83
+ const articles = ids
84
+ .map((id: string) => {
85
+ const article = summaryData.result[id];
86
+ if (!article) return null;
87
+
88
+ return {
89
+ pmid: id,
90
+ title: article.title,
91
+ authors: article.authors
92
+ ? article.authors.map((a: any) => `${a.name}`)
93
+ : ["No authors listed"],
94
+ journal:
95
+ article.fulljournalname || article.source || "Unknown journal",
96
+ publicationDate: article.pubdate || "Unknown date",
97
+ // abstract: article.abstract || "No abstract available",
98
+ doi: article.elocationid
99
+ ? article.elocationid.replace("doi: ", "")
100
+ : null,
101
+ url: `https://pubmed.ncbi.nlm.nih.gov/${id}/`,
102
+ };
103
+ })
104
+ .filter((a: any) => a !== null);
105
+ // console.log({
106
+ // count: articles.length,
107
+ // query: input.query,
108
+ // articles,
109
+ // });
110
+ return {
111
+ count: articles.length,
112
+ query: input.query,
113
+ articles,
114
+ };
115
+ } catch (error: any) {
116
+ console.error("Error searching PubMed:", error);
117
+ return {
118
+ error: "Failed to search PubMed: " + error.message,
119
+ };
120
+ }
121
+ },
122
+ });
123
+
124
+ // PubMed Abstract Fetcher Tool
125
+ const pubmedAbstractTool = new Tool({
126
+ name: "pubmedGetAbstract",
127
+ description: `This tool fetches the full abstract for a specific PubMed article by its ID (PMID).`,
128
+ inputSchema: {
129
+ type: "object",
130
+ properties: {
131
+ pmid: {
132
+ type: "string",
133
+ description:
134
+ "PubMed ID (PMID) of the article to retrieve the abstract for.",
135
+ },
136
+ },
137
+ required: ["pmid"],
138
+ },
139
+ execute: async (input): Promise<any> => {
140
+ try {
141
+ const url = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=${input.pmid}&retmode=json&rettype=abstract`;
142
+ const response = await fetch(url);
143
+
144
+ // PubMed efetch returns XML by default, so we'll manually extract the abstract
145
+ const text = await response.text();
146
+ // console.log({
147
+ // pmid: input.pmid,
148
+ // abstract: text,
149
+ // fullText: false, // PubMed doesn't provide full text, only abstracts
150
+ // url: `https://pubmed.ncbi.nlm.nih.gov/${input.pmid}/`,
151
+ // });
152
+
153
+ return {
154
+ pmid: input.pmid,
155
+ abstract: text,
156
+ fullText: false, // PubMed doesn't provide full text, only abstracts
157
+ url: `https://pubmed.ncbi.nlm.nih.gov/${input.pmid}/`,
158
+ };
159
+ } catch (error: any) {
160
+ return {
161
+ error: "Failed to retrieve abstract: " + error.message,
162
+ };
163
+ }
164
+ },
165
+ });
166
+
167
+ const history = new History();
168
+
169
+ const medicalResearchAgent = new ClaudeAgent(
170
+ {
171
+ id: "medical-research",
172
+ name: "Medical Research Assistant",
173
+ description: `You are a medical research expert specializing in coming up with novel and in-depth knowledge based on literature research and extensive experience.
174
+
175
+ You have access to PubMed, a database of medical research papers. Your goal is to help users:
176
+ - Find relevant medical research for their questions
177
+ - Summarize findings from medical literature
178
+ - Explain medical concepts from research in clear, understandable terms
179
+ - Identify patterns and consensus across multiple papers
180
+ - Come up with novel strategies and thinking
181
+ - Try to dive deep in the subject and cast a wide net
182
+ - ALWAYS list sources
183
+
184
+ When responding:
185
+ 1. Use the pubmedSearch tool to find relevant papers before providing any medical information
186
+ 2. ALWAYS cite your sources with PMID numbers and links
187
+ 3. Be clear about the strength of evidence (e.g., systematic review vs. single study)
188
+ 4. Highlight limitations of studies when appropriate
189
+
190
+ You can use the pubmedGetAbstract tool to read full abstracts for the most relevant papers.`,
191
+ tools: [pubmedSearchTool, pubmedAbstractTool],
192
+ apiKey: process.env.ANTHROPIC_API_KEY as string,
193
+ // Using Opus for better medical knowledge and reasoning
194
+ model: "claude-3-5-haiku-latest",
195
+ maxTokens: 8000,
196
+ temperature: 0.4,
197
+ },
198
+ history
199
+ );
200
+
201
+ // Alternative using OpenAI
202
+ const openAiMedicalAgent = new OpenAiAgent(
203
+ {
204
+ id: "openai-medical-research",
205
+ name: "Medical Research Assistant",
206
+ description: `You are a medical research expert specializing in coming up with novel and in-depth knowledge based on literature research and extensive experience.
207
+
208
+ You have access to PubMed, a database of medical research papers. Your goal is to help users:
209
+ - Find relevant medical research for their questions
210
+ - Summarize findings from medical literature
211
+ - Explain medical concepts from research in clear, understandable terms
212
+ - Identify patterns and consensus across multiple papers
213
+ - Come up with novel strategies and thinking
214
+ - Try to dive deep in the subject and cast a wide net
215
+
216
+ When responding:
217
+ 1. Use the pubmedSearch tool to find relevant papers before providing any medical information
218
+ 2. ALWAYS cite your sources with PMID numbers and links
219
+ 3. Be clear about the strength of evidence (e.g., systematic review vs. single study)
220
+ 4. Highlight limitations of studies when appropriate
221
+
222
+ You can use the pubmedGetAbstract tool to read full abstracts for the most relevant papers.`,
223
+ tools: [pubmedSearchTool, pubmedAbstractTool],
224
+ apiKey: process.env.OPENAI_API_KEY as string,
225
+ model: "gpt-4o",
226
+ },
227
+ history
228
+ );
229
+
230
+ async function runMedicalResearchExample() {
231
+ try {
232
+ let running = true;
233
+ let agent: BaseAgent = medicalResearchAgent; // Default to Claude
234
+ // pubmedSearchTool.on(ToolEvent.EXECUTE, console.log);
235
+ // pubmedSearchTool.on(ToolEvent.RESULT, console.log);
236
+ // pubmedAbstractTool.on(ToolEvent.EXECUTE, console.log);
237
+ // Ask which model to use
238
+ const modelChoice = await rl.question(
239
+ "Which model would you like to use? [1] Claude (default) or [2] OpenAI: "
240
+ );
241
+
242
+ if (modelChoice === "2") {
243
+ agent = openAiMedicalAgent;
244
+ console.log("Using OpenAI model");
245
+ } else {
246
+ console.log("Using Claude model");
247
+ }
248
+
249
+ console.log("\n----- Medical Research Assistant -----");
250
+ console.log(
251
+ "Ask medical research questions and the assistant will search PubMed for you."
252
+ );
253
+ console.log("Type 'exit' to quit.");
254
+ console.log("---------------------------------------\n");
255
+
256
+ while (running) {
257
+ const question = await rl.question(
258
+ "\nWhat medical topic would you like to research? \n"
259
+ );
260
+
261
+ if (question.toLowerCase() === "exit") {
262
+ running = false;
263
+ continue;
264
+ }
265
+
266
+ console.log("\nSearching medical literature...");
267
+ const result = await agent.execute(question);
268
+
269
+ console.log("\n" + result);
270
+
271
+ // Ask if the user wants to continue
272
+ const continueResponse = await rl.question(
273
+ "\nWould you like to ask another question? (y/n): "
274
+ );
275
+ if (continueResponse.toLowerCase() !== "y") {
276
+ running = false;
277
+ }
278
+ }
279
+
280
+ rl.close();
281
+ process.exit(0);
282
+ } catch (error) {
283
+ console.error("Error:", error);
284
+ rl.close();
285
+ process.exit(1);
286
+ }
287
+ }
288
+
289
+ runMedicalResearchExample();
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Reasoning with Sub-Agent Example
3
+ *
4
+ * This example demonstrates using an agent as a reasoning assistant for another agent.
5
+ * A focused "reasoner" agent breaks down complex questions and analyzes them step-by-step,
6
+ * while a main agent coordinates and provides the final synthesized answer.
7
+ *
8
+ * Architecture:
9
+ * Main Agent (coordinator, no specialized tools)
10
+ * └── Reasoner Agent (specialized in analytical thinking and problem decomposition)
11
+ */
12
+
13
+ import "dotenv/config";
14
+ import { createInterface } from "node:readline/promises";
15
+ import { ClaudeAgent } from "../lib/agents/anthropic/ClaudeAgent";
16
+ import { OpenAiAgent } from "../lib/agents/openai/OpenAiAgent";
17
+ import { MistralAgent } from "../lib/agents/mistral/MistralAgent";
18
+ import { BaseAgent } from "../lib/agents/BaseAgent";
19
+ import { Tool } from "../lib/tools/Tool";
20
+ import { AgentEvent } from "../lib/agents/AgentEvent";
21
+
22
+ const rl = createInterface({
23
+ input: process.stdin,
24
+ output: process.stdout,
25
+ });
26
+
27
+ // =============================================================================
28
+ // Reasoning Tools (used by the reasoner sub-agent)
29
+ // =============================================================================
30
+
31
+ const decomposeQuestionTool = new Tool({
32
+ name: "decompose_question",
33
+ description: `Break down a complex question into smaller, manageable sub-questions.
34
+ Returns a list of sub-questions that need to be answered to fully address the main question.`,
35
+ inputSchema: {
36
+ type: "object",
37
+ properties: {
38
+ question: {
39
+ type: "string",
40
+ description: "The complex question to decompose",
41
+ },
42
+ },
43
+ required: ["question"],
44
+ },
45
+ execute: async (input: { question: string }): Promise<unknown> => {
46
+ // This is a simulated tool - in a real system, this might use LLM or rules
47
+ return {
48
+ originalQuestion: input.question,
49
+ subQuestions: [
50
+ `What are the key concepts involved in: "${input.question}"?`,
51
+ `What assumptions are being made in: "${input.question}"?`,
52
+ `What are the possible approaches to answer: "${input.question}"?`,
53
+ ],
54
+ timestamp: new Date().toISOString(),
55
+ };
56
+ },
57
+ });
58
+
59
+ const analyzeAssumptionsTool = new Tool({
60
+ name: "analyze_assumptions",
61
+ description: `Identify and analyze the assumptions underlying a question or statement.
62
+ Returns a list of implicit and explicit assumptions that should be considered.`,
63
+ inputSchema: {
64
+ type: "object",
65
+ properties: {
66
+ statement: {
67
+ type: "string",
68
+ description: "The statement or question to analyze for assumptions",
69
+ },
70
+ },
71
+ required: ["statement"],
72
+ },
73
+ execute: async (input: { statement: string }): Promise<unknown> => {
74
+ return {
75
+ analyzedStatement: input.statement,
76
+ assumptions: {
77
+ implicit: [
78
+ "The question has a definitive answer",
79
+ "Current information is complete and accurate",
80
+ ],
81
+ explicit: ["The context provided is sufficient"],
82
+ needsValidation: ["Check if all terms are clearly defined"],
83
+ },
84
+ timestamp: new Date().toISOString(),
85
+ };
86
+ },
87
+ });
88
+
89
+ const evaluateLogicTool = new Tool({
90
+ name: "evaluate_logic",
91
+ description: `Evaluate the logical structure of an argument or reasoning chain.
92
+ Returns an analysis of logical validity, potential fallacies, and strength of reasoning.`,
93
+ inputSchema: {
94
+ type: "object",
95
+ properties: {
96
+ argument: {
97
+ type: "string",
98
+ description: "The argument or reasoning to evaluate",
99
+ },
100
+ context: {
101
+ type: "string",
102
+ description: "Additional context for the argument (optional)",
103
+ },
104
+ },
105
+ required: ["argument"],
106
+ },
107
+ execute: async (input: {
108
+ argument: string;
109
+ context?: string;
110
+ }): Promise<unknown> => {
111
+ return {
112
+ argument: input.argument,
113
+ context: input.context || "No additional context provided",
114
+ logicalStructure: {
115
+ isValid: true,
116
+ strength: "moderate",
117
+ potentialFallacies: [],
118
+ recommendations: [
119
+ "Consider alternative perspectives",
120
+ "Verify factual claims",
121
+ ],
122
+ },
123
+ timestamp: new Date().toISOString(),
124
+ };
125
+ },
126
+ });
127
+
128
+ // =============================================================================
129
+ // Sub-Agent Creation (the analytical reasoner)
130
+ // =============================================================================
131
+
132
+ const REASONER_DESCRIPTION = `You are an analytical reasoning specialist. Your job is to:
133
+ 1. Break down complex questions into manageable parts
134
+ 2. Identify assumptions and logical structures
135
+ 3. Evaluate different perspectives and approaches
136
+ 4. Provide structured analytical insights
137
+
138
+
139
+ Be thorough but concise, you only have 2000 tokens. Focus on clarity and logical rigor in a few lines.`;
140
+
141
+ function createReasonerAgent(
142
+ provider: "claude" | "openai" | "mistral"
143
+ ): BaseAgent {
144
+ const config = {
145
+ id: "reasoner",
146
+ name: "Analytical Reasoner",
147
+ description: REASONER_DESCRIPTION,
148
+ tools: [],
149
+ maxTokens: 2048,
150
+ };
151
+
152
+ if (provider === "openai") {
153
+ return new OpenAiAgent({
154
+ ...config,
155
+ apiKey: process.env.OPENAI_API_KEY as string,
156
+ model: "gpt-4o-mini", // Fast and cost-effective, no reasoning overhead
157
+ // Note: For reasoning models (gpt-5-nano, o1, etc.), either:
158
+ // - Set disableReasoning: true to disable extended thinking
159
+ // - Or increase maxTokens (e.g., 8192) to accommodate reasoning tokens
160
+ });
161
+ }
162
+
163
+ if (provider === "mistral") {
164
+ return new MistralAgent({
165
+ ...config,
166
+ apiKey: process.env.MISTRAL_API_KEY as string,
167
+ model: "mistral-small-latest", // Efficient model for structured reasoning
168
+ });
169
+ }
170
+
171
+ return new ClaudeAgent({
172
+ ...config,
173
+ apiKey: process.env.ANTHROPIC_API_KEY as string,
174
+ model: "claude-haiku-4-5", // Fast and efficient for analytical tasks
175
+ });
176
+ }
177
+
178
+ // =============================================================================
179
+ // Main Agent Creation (the coordinator)
180
+ // =============================================================================
181
+
182
+ const MAIN_AGENT_DESCRIPTION = `You are a thoughtful assistant that helps users reason through complex questions.
183
+ You have access to an analytical reasoner who can break down questions, analyze assumptions, and evaluate logic.
184
+
185
+ When the user asks a complex question:
186
+ 1. Use the reasoner to analyze the question thoroughly
187
+ 2. Synthesize the analysis into a clear, helpful response
188
+ 3. Provide insights and perspectives that address the core question
189
+ 4. Acknowledge uncertainty where appropriate
190
+
191
+ Be clear, thoughtful, and educational. Help the user understand not just the answer, but the reasoning process itself.`;
192
+
193
+ function createMainAgent(
194
+ provider: "claude" | "openai" | "mistral",
195
+ reasonerTool: Tool<string>
196
+ ): BaseAgent {
197
+ const config = {
198
+ id: "main",
199
+ name: "Reasoning Assistant",
200
+ description: MAIN_AGENT_DESCRIPTION,
201
+ tools: [reasonerTool],
202
+ maxTokens: 3072,
203
+ };
204
+
205
+ if (provider === "openai") {
206
+ return new OpenAiAgent({
207
+ ...config,
208
+ apiKey: process.env.OPENAI_API_KEY as string,
209
+ model: "gpt-4o-mini", // More capable model for synthesis and coordination
210
+ });
211
+ }
212
+
213
+ if (provider === "mistral") {
214
+ return new MistralAgent({
215
+ ...config,
216
+ apiKey: process.env.MISTRAL_API_KEY as string,
217
+ model: "mistral-large-latest",
218
+ });
219
+ }
220
+
221
+ return new ClaudeAgent({
222
+ ...config,
223
+ apiKey: process.env.ANTHROPIC_API_KEY as string,
224
+ model: "claude-haiku-4-5",
225
+ });
226
+ }
227
+
228
+ // =============================================================================
229
+ // Main
230
+ // =============================================================================
231
+
232
+ async function main() {
233
+ console.log("=== Reasoning Assistant with Sub-Agent ===\n");
234
+ console.log(
235
+ "This example uses a specialized 'reasoner' agent to analyze questions,"
236
+ );
237
+ console.log(
238
+ "while a coordinator agent synthesizes the analysis into helpful responses.\n"
239
+ );
240
+
241
+ // Choose provider
242
+ const providerChoice = await rl.question(
243
+ "Which provider? [1] Claude (default), [2] OpenAI, or [3] Mistral: "
244
+ );
245
+ let provider: "claude" | "openai" | "mistral" = "claude";
246
+ if (providerChoice === "2") {
247
+ provider = "openai";
248
+ } else if (providerChoice === "3") {
249
+ provider = "mistral";
250
+ }
251
+ console.log(`Using ${provider}\n`);
252
+
253
+ // Create the reasoner sub-agent
254
+ const reasonerAgent = createReasonerAgent(provider);
255
+ console.log(
256
+ "Created reasoner sub-agent (specialized in analytical thinking)"
257
+ );
258
+
259
+ // Wrap the reasoner agent as a tool
260
+ const reasonerTool = Tool.fromAgent(
261
+ reasonerAgent,
262
+ `Use this analytical reasoner to break down complex questions, identify assumptions, and evaluate logic.
263
+ Provide the question or problem you want analyzed, and it will return structured analytical insights.`
264
+ );
265
+ console.log("Wrapped reasoner as a tool for the main agent");
266
+
267
+ // Create the main agent with the reasoner tool
268
+ const mainAgent = createMainAgent(provider, reasonerTool);
269
+ console.log("Created main agent (coordinator for synthesis)\n");
270
+
271
+ // Interactive loop for questions
272
+ console.log(
273
+ "Ask me any complex question and I'll reason through it with you."
274
+ );
275
+ console.log("Type 'quit' or 'exit' to end the conversation.\n");
276
+
277
+ while (true) {
278
+ const question = await rl.question("> ");
279
+
280
+ if (
281
+ question.toLowerCase() === "quit" ||
282
+ question.toLowerCase() === "exit"
283
+ ) {
284
+ console.log("\nGoodbye!");
285
+ break;
286
+ }
287
+
288
+ if (!question.trim()) {
289
+ continue;
290
+ }
291
+
292
+ console.log("\n--- Reasoning Process ---");
293
+
294
+ try {
295
+ reasonerAgent.on(AgentEvent.AFTER_EXECUTE, console.log);
296
+ reasonerAgent.on(AgentEvent.BEFORE_EXECUTE, console.log);
297
+ const result = await mainAgent.execute(question);
298
+
299
+ console.log("\n--- Response ---");
300
+ console.log(result);
301
+ console.log("\n");
302
+ } catch (error) {
303
+ console.error("Error:", error);
304
+ }
305
+ }
306
+
307
+ rl.close();
308
+ process.exit(0);
309
+ }
310
+
311
+ main().catch(console.error);
@@ -0,0 +1,48 @@
1
+ import "dotenv/config";
2
+ import { OpenAiAgent } from "../../lib/agents/openai/OpenAiAgent";
3
+ import { AgentGraph } from "../../lib/graph/AgentGraph";
4
+ import { AgentEvent } from "../../lib/agents/AgentEvent";
5
+ export const agent1 = new OpenAiAgent({
6
+ id: "medical-research",
7
+ name: "Deep thinker agent",
8
+ description: `You write code for a problem that the user has`,
9
+ tools: [],
10
+ apiKey: process.env.OPENAI_API_KEY as string,
11
+ temperature: 1,
12
+ model: "gpt-4o-mini",
13
+ maxTokens: 8000,
14
+ });
15
+
16
+ export const agent2 = new OpenAiAgent({
17
+ id: "medical-research",
18
+ name: "Deep feedback agent",
19
+ description: `You review code and write tests. Return both the code and the tests.`,
20
+ tools: [],
21
+ apiKey: process.env.OPENAI_API_KEY as string,
22
+ model: "gpt-4o-mini",
23
+ temperature: 0,
24
+ maxTokens: 8000,
25
+ });
26
+
27
+ const graph = AgentGraph.synchronous(agent1, agent2);
28
+
29
+ agent1.on(AgentEvent.AFTER_EXECUTE, (event: AgentEvent) => {
30
+ console.log(JSON.stringify(event, undefined, " "));
31
+ });
32
+ agent2.on(AgentEvent.AFTER_EXECUTE, (event: AgentEvent) => {
33
+ console.log(JSON.stringify(event, null, " "));
34
+ });
35
+
36
+ function run() {
37
+ graph
38
+ .execute(
39
+ `Write a TS class that supports Agents working together in a graph.
40
+ An initial execute command will add to the input of the first agent the choice of connected agents.
41
+ interface Agent{
42
+ execute(input:string):Promise<string>
43
+ }
44
+ `
45
+ )
46
+ .then(console.log);
47
+ }
48
+ run();
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "strictPropertyInitialization": false,
5
+ "noEmit": true
6
+ },
7
+ "include": ["./**/*", "../lib/**/*"]
8
+ }