Skip to content

Commit 5e85f22

Browse files
authored
search graph and cli tool (#21)
1 parent ed300c6 commit 5e85f22

File tree

27 files changed

+927
-231
lines changed

27 files changed

+927
-231
lines changed

.changeset/cyan-radios-run.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
"@ai-citizens/graph": patch
3+
"@ai-citizens/tools": patch
4+
"@ai-citizens/ava": patch
5+
"@ai-citizens/llm": patch
6+
---
7+
8+
## New Features
9+
10+
- Introduced an AI-powered search command in the CLI for enhanced user querying.
11+
- Added a new module for search functionality, making it publicly accessible.
12+
- Developed comprehensive search mechanisms and state management for structured responses.
13+
- Launched a calculator tool for basic arithmetic operations with input validation.
14+
- Expanded web search capabilities with the addition of a new Tavily search tool.
15+
16+
## Documentation
17+
18+
- Created a README file detailing the voter registration search feature, improving user guidance.
19+
20+
## Tests
21+
22+
- Adds Ava testing
23+
- Implemented unit tests for search functions to ensure reliability and correctness.
24+
- Added tests for the calculator tool to validate arithmetic operations.

.github/workflows/build.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
env:
12+
CI: true
13+
PNPM_CACHE_FOLDER: .pnpm-store
14+
15+
jobs:
16+
build:
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 15
19+
steps:
20+
- name: Checkout code repository
21+
uses: actions/checkout@v3
22+
23+
- name: Setup Node.js
24+
uses: actions/setup-node@v3
25+
with:
26+
node-version: 18
27+
28+
- name: Install pnpm
29+
run: npm i pnpm@latest -g
30+
31+
- name: Setup pnpm config
32+
run: pnpm config set store-dir $PNPM_CACHE_FOLDER
33+
34+
- name: Install dependencies
35+
run: pnpm install
36+
37+
- name: Build project
38+
run: pnpm run build

migrations/001_create_foo_table.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ CREATE TABLE documents (
1515
);
1616

1717
-- Create an index on workspace_id for faster queries
18-
CREATE INDEX idx_acdoc_workspace_id ON acdoc(workspace_id);
18+
CREATE INDEX idx_documents_workspace_id ON documents(workspace_id);

packages/cli/src/commands/search.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Command, Args } from "@oclif/core";
2+
import { getModel, isAllModel } from "@ai-citizens/llm";
3+
import { performSearch } from "@ai-citizens/graph";
4+
5+
export default class Search extends Command {
6+
static override description = "AI powered search";
7+
static override args = {
8+
query: Args.string({
9+
description: "Query to search the graph",
10+
required: true,
11+
}),
12+
};
13+
public async run(): Promise<void> {
14+
const { flags, args } = await this.parse(Search);
15+
let modelName = flags.model || "gpt-4o-mini";
16+
17+
if (!isAllModel(modelName)) {
18+
throw new Error(`Invalid model: ${modelName}`);
19+
}
20+
21+
const config = {
22+
configurable: {
23+
thread_id: "agent-session",
24+
},
25+
};
26+
27+
const response = await performSearch(args.query, config);
28+
console.log(response.messages[1].content);
29+
}
30+
}

packages/db/ava.config.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/graph/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"license": "ISC",
3131
"dependencies": {
3232
"@langchain/core": "^0.2.18",
33-
"@langchain/langgraph": "^0.0.31",
33+
"@langchain/langgraph": "^0.0.34",
3434
"@langchain/openai": "^0.2.5",
3535
"langchain": "^0.2.16",
3636
"pg": "^8.12.0",

packages/graph/src/examples/planning/planning-agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export const executionNode = async (state: PlanExecuteState) => {
191191
const mockedStepResult = `Completed: ${currentStep}`;
192192
return {
193193
plan: state.plan.slice(1), // Remove the executed step from the plan
194-
pastSteps: [[currentStep, mockedStepResult]], // Add the executed step to pastSteps
194+
pastSteps: [[currentStep, mockedStepResult] as [string, string]],
195195
};
196196
};
197197

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import test from "ava";
2+
// import { runGraphGenerator } from "./graph.js";
3+
import "dotenv/config";
4+
5+
test.skip(
6+
"create graph",
7+
async (t) => {
8+
// const userRequest =
9+
// "Create a graph that manages a blog writer, it will need write the article, review the article, reiterate based on feedback and then send back to user for approval";
10+
// const graph = await runGraphGenerator(userRequest, {
11+
// configurable: {
12+
// thread_id: "test",
13+
// },
14+
// });
15+
// t.log(graph.scaffoldedGraph);
16+
t.pass();
17+
},
18+
{ timeout: "5m" }
19+
);

packages/graph/src/graph-creator/graph.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,10 @@ const graphGeneratorGraph = graphGeneratorBuilder.compile({
145145
// @ts-expect-error stupid typing
146146
interruptBefore: ["qaCheck"],
147147
});
148-
const graphImg = generateGraphImg({
149-
app: graphGeneratorGraph,
150-
path: "./graph-generator-graph.png",
151-
});
148+
// const graphImg = generateGraphImg({
149+
// app: graphGeneratorGraph,
150+
// path: "./graph-generator-graph.png",
151+
// });
152152
// Example usage
153153
export const runGraphGenerator = async (
154154
userRequest?: string,

packages/graph/src/graph-creator/prompt/examples.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const nodeCreatorPrompt =
2+
'# Comprehensive Guide to Building Nodes in LangGraph\n\n## 1. Introduction to Nodes in LangGraph\n\nNodes are fundamental components in LangGraph that represent discrete steps or operations within your agent\'s workflow. They are essentially JavaScript/TypeScript functions that receive the current state as input, perform some computation or side-effect, and return an updated state.\n\n## 2. Types of Nodes\n\n### 2.1 Basic Nodes\nSimple functions that process the state and return an update.\n\n### 2.2 LLM-based Nodes\nNodes that incorporate language models for decision-making or text generation.\n\n### 2.3 Tool-calling Nodes\nNodes that interact with external tools or APIs.\n\n### 2.4 Special Nodes\n- START Node: Represents the entry point of the graph.\n- END Node: Represents a terminal node in the graph.\n\n## 3. Creating Basic Nodes\n\nStep-by-step instructions:\n\n1. Define your node function:\n```typescript\nconst myNode = (state: State, config?: RunnableConfig) => {\n // Process state\n // Return state update\n};\n```\n\n2. Add the node to your graph:\n```typescript\ngraphBuilder.addNode("myNode", myNode);\n```\n\n## 4. Advanced Node Configurations\n\n### 4.1 Configurable Nodes\nCreate nodes that can be configured at runtime:\n\n```typescript\nconst configurableNode = (state: State, config?: RunnableConfig) => {\n const customParam = config?.configurable?.customParam;\n // Use customParam in your node logic\n};\n```\n\n### 4.2 Async Nodes\nFor operations that require asynchronous processing:\n\n```typescript\nconst asyncNode = async (state: State, config?: RunnableConfig) => {\n const result = await someAsyncOperation(state.input);\n return { output: result };\n};\n```\n\n## 5. Best Practices for Node Implementation\n\n1. Keep nodes focused on a single responsibility.\n2. Use TypeScript interfaces to define expected state structure.\n3. Implement error handling within nodes.\n4. Use meaningful names for nodes and their functions.\n5. Document the purpose and expected inputs/outputs of each node.\n\n## 6. Common Pitfalls and How to Avoid Them\n\n1. Mutating state directly: Always return a new state object or use reducers.\n2. Ignoring error handling: Implement try-catch blocks for potential errors.\n3. Overcomplicating nodes: Break complex logic into multiple simpler nodes.\n4. Forgetting to compile the graph: Always call `.compile()` before using the graph.\n\n## 7. Integrating Nodes with Other LangGraph Components\n\n### 7.1 Connecting Nodes with Edges\nUse `addEdge` or `addConditionalEdges` to define the flow between nodes:\n\n```typescript\ngraphBuilder.addEdge("nodeA", "nodeB");\ngraphBuilder.addConditionalEdges("nodeC", routingFunction);\n```\n\n### 7.2 Using Nodes with Checkpointers\nImplement checkpointing to enable persistence and human-in-the-loop workflows:\n\n```typescript\nconst graph = graphBuilder.compile({\n checkpointer: new InMemoryCheckpointer()\n});\n```\n\n### 7.3 Streaming from Nodes\nImplement streaming to provide real-time updates:\n\n```typescript\nconst streamingNode = async function* (state: State) {\n yield { status: "Processing" };\n // Perform operations\n yield { status: "Complete", result: someResult };\n};\n```\n\n## 8. Advanced Topics\n\n### 8.1 Implementing Reflection in Nodes\nCreate nodes that can analyze their own output and make decisions:\n\n```typescript\nconst reflectiveNode = async (state: State) => {\n const result = await performOperation(state.input);\n const analysis = await analyzeResult(result);\n return { result, analysis };\n};\n```\n\n### 8.2 Multi-agent Nodes\nDesign nodes that facilitate communication between multiple agents:\n\n```typescript\nconst multiAgentNode = async (state: State) => {\n const agentAResponse = await agentA.process(state.input);\n const agentBResponse = await agentB.process(agentAResponse);\n return { agentAResponse, agentBResponse };\n};\n```\n\n## 9. Conclusion\n\nBuilding effective nodes in LangGraph requires a good understanding of state management, function composition, and the overall graph structure. By following the best practices and avoiding common pitfalls, you can create robust and flexible agent workflows. Remember to leverage LangGraph\'s features like checkpointing, streaming, and conditional routing to build sophisticated agentic applications.';

packages/graph/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./youtube-parser/index.js";
22
export * from "./graph-creator/index.js";
33
export * from "./checkpointer/index.js";
4+
export * from "./search/index.js";

packages/graph/src/search/README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Search Graph
2+
3+
This module implements a state-based graph for performing web searches, extracting key information, and generating responses based on user queries.
4+
5+
![Search Example](./graph.png)
6+
7+
## Key Components
8+
9+
1. **SearchState**: Defines the structure for storing search-related information.
10+
11+
2. **StateGraph**: Utilizes LangChain's StateGraph to manage the flow of operations.
12+
13+
3. **Main Nodes**:
14+
15+
- `performSearchNode`: Executes the web search using the Tavily API.
16+
- `extractKeyPointsNode`: Identifies and extracts key points from search results.
17+
- `generateRelatedQueriesNode`: Creates related queries based on the initial search.
18+
- `generateResponseNode`: Produces a final response and report based on all gathered information.
19+
20+
4. **Utility Functions**:
21+
22+
- `filterSearchResults`: Filters search results based on a minimum score.
23+
- `formatSearchResults`: Formats the search results for further processing.
24+
25+
5. **LLM Integration**: Utilizes GPT models for various natural language processing tasks.
26+
27+
## Workflow
28+
29+
1. The search process begins with a user query.
30+
2. The query is used to perform a web search.
31+
3. Key points are extracted from the search results.
32+
4. Related queries are generated to expand the search scope.
33+
5. A final response and report are generated based on all collected information.
34+
35+
## Usage
36+
37+
The module exports two main functions:
38+
39+
1. `performSearch`: Executes the entire search process and returns the final state.
40+
2. `streamSearchProcess`: Provides a stream of intermediate states during the search process.
41+
42+
## Example Usage
43+
44+
```ts
45+
const result = await performSearch(
46+
"How do I register to vote in Oregon?",
47+
config
48+
);
49+
```
50+
51+
## Example Response
52+
53+
```json
54+
{
55+
"query": "how do I register to vote in Oregon?",
56+
"searchResults": [
57+
"State of Oregon: Elections - Voting in Oregon\n\nRegistering to vote in Oregon is quick and simple. Oregonians can register: Online using My Vote. By mail using a voter registration form.This form also is available in multiple languages . In person at the county elections office or at certain state agencies like the DMV. The deadline to register is 21 days before Election Day.[1]",
58+
"Register to Vote Online in Oregon - Vote.org\n\nOregon. voter registration rulesTo register in Oregon you must: Be a citizen of the United States; Be a resident of Oregon; At least 16 years old (to vote, you must be 18 by Election Day). Oregon. voter registration directionsUse our Register to Vote Tool to fill out the National Voter Registration Form.[2]",
59+
"State of Oregon: Voting - Update Voter Registration Information\n\nElectronically. If you have an Oregon driver license or state ID card, you can update your information entirely online. Go To My Vote. Enter your name and date of birth. Click Submit. Select Update Registration at the bottom of the page. Answer the two eligibility questions on the next screen. Click Continue.[3]",
60+
"How to register in Oregon | Vote.gov\n\nStart or update your registration on Oregon's election website. You can also register to vote by mail or in person on Oregon's election website. Voter registration deadlines. Voter registration deadlines for the Tuesday, November 5, 2024 election. Find state and local election dates. Online registration deadline: Tuesday, October 15, 2024[4]",
61+
"Voter Registration Information - State of Oregon: Voting & Elections\n\nIf you do not have a valid Oregon ID or Social Security number you can find a list of acceptable alternative identification online at oregonvotes.gov. What is the deadline to register? To vote in the May 21, 2024, Primary Election, your completed registration card must be: postmarked by Tuesday, April 30; or; delivered to a county elections ...[5]"
62+
],
63+
"sources": [
64+
"https://sos.oregon.gov/voting/Pages/voteinor.aspx",
65+
"https://www.vote.org/register-to-vote/oregon/",
66+
"https://sos.oregon.gov/voting/Pages/updatevoterregistration.aspx",
67+
"https://vote.gov/register/oregon",
68+
"https://oregonvotes.gov/voters-guide/english/geninfo_voterreginfo.html"
69+
],
70+
"keyPoints": [
71+
"Registering to vote in Oregon is quick and simple, and can be done online, by mail, or in person[^1]",
72+
"To register in Oregon, you must be a citizen of the United States, a resident of Oregon, and at least 16 years old (you must be 18 by Election Day to vote)[^2]",
73+
"The deadline to register to vote is 21 days before Election Day[^1]",
74+
"For the November 5, 2024 election, the online registration deadline is October 15, 2024[^4]",
75+
"If you do not have a valid Oregon ID or Social Security number, you can find acceptable alternative identification online[^5]"
76+
],
77+
"relatedQueries": [
78+
"What are the eligibility requirements to register to vote in Oregon?",
79+
"How can I update my voter registration information in Oregon?",
80+
"What is the deadline for voter registration in Oregon for upcoming elections?",
81+
"Can I register to vote in Oregon if I am not a U.S. citizen?",
82+
"What are the different ways to vote in Oregon after registering?"
83+
],
84+
"report": "## How to Register to Vote in Oregon\n\n### Registration Methods\nOregon offers multiple convenient ways to register to vote:\n- **Online**: \n - Use the [My Vote](https://sos.oregon.gov/voting/Pages/voteinor.aspx) tool if you have an Oregon driver license or state ID.\n- **By Mail**: \n - Download and complete the voter registration form, which is available in various languages.\n- **In Person**: \n - Register at your local county elections office or at designated state agencies like the DMV[^1][^2].\n\n### Eligibility Requirements\nTo register in Oregon, you must meet the following criteria:\n- Be a citizen of the United States.\n- Be a resident of Oregon.\n- Be at least 16 years old (you must be 18 by Election Day to vote) [^2].\n\n### Important Deadlines\n- The deadline to register to vote is **21 days before Election Day**.\n- For the upcoming elections, ensure your registration is completed by the specified deadlines:\n - For the May 21, 2024, Primary Election, your registration must be postmarked by April 30, 2024[^5].\n\n### Updating Your Registration\nIf you need to update your voter registration, you can do so online if you have an Oregon driver license or state ID. Simply visit the My Vote tool, enter your details, and follow the prompts to update your information[^3].\n\n## References\n[^1]: State of Oregon: Elections - Voting in Oregon \n[^2]: Register to Vote Online in Oregon - Vote.org \n[^3]: State of Oregon: Voting - Update Voter Registration Information \n[^4]: How to register in Oregon | Vote.gov \n[^5]: Voter Registration Information - State of Oregon: Voting & Elections",
85+
}
86+
"error": ""
87+
```

packages/graph/src/search/graph.png

18.2 KB
Loading

0 commit comments

Comments
 (0)