diff --git a/examples/authorization-for-rag/genkit/.env.example b/examples/authorization-for-rag/genkit/.env.example new file mode 100644 index 0000000..b5f2690 --- /dev/null +++ b/examples/authorization-for-rag/genkit/.env.example @@ -0,0 +1,11 @@ +# OpenAI +OPENAI_API_KEY= + + +# Okta FGA +FGA_STORE_ID= +FGA_CLIENT_ID= +FGA_CLIENT_SECRET= +# Required only for non-US regions +FGA_API_URL=https://api.xxx.fga.dev +FGA_API_AUDIENCE=https://api.xxx.fga.dev/ diff --git a/examples/authorization-for-rag/genkit/README.md b/examples/authorization-for-rag/genkit/README.md index 5a4ee39..140978b 100644 --- a/examples/authorization-for-rag/genkit/README.md +++ b/examples/authorization-for-rag/genkit/README.md @@ -18,9 +18,8 @@ OPENAI_API_KEY=xx-xxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_STORE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_CLIENT_SECRET=xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx -# Optional +# Required only for non-US regions FGA_API_URL=https://api.xxx.fga.dev -FGA_API_TOKEN_ISSUER=auth.fga.dev FGA_API_AUDIENCE=https://api.xxx.fga.dev/ ``` diff --git a/examples/authorization-for-rag/langchain/.env.example b/examples/authorization-for-rag/langchain/.env.example new file mode 100644 index 0000000..b5f2690 --- /dev/null +++ b/examples/authorization-for-rag/langchain/.env.example @@ -0,0 +1,11 @@ +# OpenAI +OPENAI_API_KEY= + + +# Okta FGA +FGA_STORE_ID= +FGA_CLIENT_ID= +FGA_CLIENT_SECRET= +# Required only for non-US regions +FGA_API_URL=https://api.xxx.fga.dev +FGA_API_AUDIENCE=https://api.xxx.fga.dev/ diff --git a/examples/authorization-for-rag/langchain/README.md b/examples/authorization-for-rag/langchain/README.md index 8eea560..99411c3 100644 --- a/examples/authorization-for-rag/langchain/README.md +++ b/examples/authorization-for-rag/langchain/README.md @@ -21,9 +21,8 @@ This example demonstrates how to combine [LangChain](https://js.langchain.com/do FGA_STORE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_CLIENT_SECRET=xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx - # Optional + # Required only for non-US regions FGA_API_URL=https://api.xxx.fga.dev - FGA_API_TOKEN_ISSUER=auth.fga.dev FGA_API_AUDIENCE=https://api.xxx.fga.dev/ ``` diff --git a/examples/authorization-for-rag/langchain/helpers/langchain.ts b/examples/authorization-for-rag/langchain/helpers/langchain.ts index 6d148e2..e5f29d7 100644 --- a/examples/authorization-for-rag/langchain/helpers/langchain.ts +++ b/examples/authorization-for-rag/langchain/helpers/langchain.ts @@ -1,12 +1,12 @@ import { createStuffDocumentsChain } from "langchain/chains/combine_documents"; import { createRetrievalChain } from "langchain/chains/retrieval"; -import { MemoryVectorStore } from "langchain/vectorstores/memory"; -import { Document, DocumentInterface } from "@langchain/core/documents"; +import { DocumentInterface } from "@langchain/core/documents"; import { ChatPromptTemplate } from "@langchain/core/prompts"; import { BaseRetrieverInterface } from "@langchain/core/retrievers"; import { Runnable, RunnableInterface } from "@langchain/core/runnables"; -import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai"; +import { ChatOpenAI } from "@langchain/openai"; +import { LanguageModelLike } from "@langchain/core/language_models/base"; /** * Represents a chain that uses a retriever to gather relevant documents @@ -36,7 +36,10 @@ export class RetrievalChain { `Answer the user's question: {input} based on the following context {context}. Only use the information provided in the context. If you need more information, ask for it.` ); const combineDocsChain = await createStuffDocumentsChain({ - llm: new ChatOpenAI({ temperature: 0, modelName: "gpt-4o-mini" }), + llm: new ChatOpenAI({ + temperature: 0, + model: "gpt-4o-mini", + }) as unknown as LanguageModelLike, prompt, }); const retrievalChain = await createRetrievalChain({ @@ -48,39 +51,11 @@ export class RetrievalChain { } // Query the retrieval chain with a user question - async query({ query }: { query: string }) { - const response = await this.engine.invoke({ + async query(query: string) { + const { answer } = await this.engine.invoke({ input: query, }); - return response; - } -} - -/** - * Represents an in-memory store for the vector embeddings of the documents. - * - * @remarks - * This store is used to create a vector store retriever for the retrieval chain. - */ -export class MemoryStore { - private store: MemoryVectorStore; - - private constructor(store: MemoryVectorStore) { - this.store = store; - } - - static async fromDocuments(documents: Document>[]) { - const embeddings = new OpenAIEmbeddings(); - const vectorStore = await MemoryVectorStore.fromDocuments( - documents, - embeddings - ); - - return new MemoryStore(vectorStore); - } - - asRetriever() { - return this.store.asRetriever(); + return answer; } } diff --git a/examples/authorization-for-rag/langchain/index.ts b/examples/authorization-for-rag/langchain/index.ts index 49808a8..6193446 100644 --- a/examples/authorization-for-rag/langchain/index.ts +++ b/examples/authorization-for-rag/langchain/index.ts @@ -1,13 +1,13 @@ /** * LangChain Example: Retrievers with Okta FGA (Fine-Grained Authorization) - * - * */ import "dotenv/config"; import { FGARetriever } from "@auth0/ai-langchain"; -import { MemoryStore, RetrievalChain } from "./helpers/langchain"; +import { RetrievalChain } from "./helpers/langchain"; import { readDocuments } from "./helpers/read-documents"; +import { MemoryVectorStore } from "langchain/vectorstores/memory"; +import { OpenAIEmbeddings } from "@langchain/openai"; /** * Demonstrates the usage of the Okta FGA (Fine-Grained Authorization) @@ -32,7 +32,10 @@ async function main() { // 1. Read and load documents from the assets folder const documents = await readDocuments(); // 2. Create an in-memory vector store from the documents for OpenAI models. - const vectorStore = await MemoryStore.fromDocuments(documents); + const vectorStore = await MemoryVectorStore.fromDocuments( + documents, + new OpenAIEmbeddings({ model: "text-embedding-3-small" }) + ); // 3. Create a retrieval chain with root prompt and OpenAI model configuration const retrievalChain = await RetrievalChain.create({ // 4. Chain the retriever with the FGARetriever to check the permissions. @@ -47,9 +50,7 @@ async function main() { }), }); // 5. Query the retrieval chain with a prompt - const { answer } = await retrievalChain.query({ - query: "Show me forecast for ZEKO?", - }); + const answer = await retrievalChain.query("Show me forecast for ZEKO?"); /** * Output: `The provided context does not include specific financial forecasts...` diff --git a/examples/authorization-for-rag/langchain/package.json b/examples/authorization-for-rag/langchain/package.json index 8ac5f47..61b1ee3 100644 --- a/examples/authorization-for-rag/langchain/package.json +++ b/examples/authorization-for-rag/langchain/package.json @@ -1,7 +1,7 @@ { "name": "langchain-retrievers-with-fga", "version": "0.0.0", - "description": "Demonstrates the usage of the Okta FGA with a langchain to query documents with permission checks.", + "description": "Demonstrates the usage of the Okta FGA with LangChain to query documents with permission checks.", "x-type": "module", "main": "index.js", "author": { @@ -15,12 +15,12 @@ }, "dependencies": { "@auth0/ai-langchain": "*", - "@langchain/openai": "^0.3.16", + "@langchain/openai": "^0.3.17", "@openfga/sdk": "^0.8.0", - "dotenv": "16.4.7", - "langchain": "^0.3.11" + "dotenv": "^16.4.7", + "langchain": "^0.3.12" }, "devDependencies": { - "@types/node": "^22.10.6" + "@types/node": "^22.10.7" } } diff --git a/examples/authorization-for-rag/langgraph-agentic/.env.example b/examples/authorization-for-rag/langgraph-agentic/.env.example new file mode 100644 index 0000000..b5f2690 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/.env.example @@ -0,0 +1,11 @@ +# OpenAI +OPENAI_API_KEY= + + +# Okta FGA +FGA_STORE_ID= +FGA_CLIENT_ID= +FGA_CLIENT_SECRET= +# Required only for non-US regions +FGA_API_URL=https://api.xxx.fga.dev +FGA_API_AUDIENCE=https://api.xxx.fga.dev/ diff --git a/examples/authorization-for-rag/langgraph-agentic/.gitignore b/examples/authorization-for-rag/langgraph-agentic/.gitignore new file mode 100644 index 0000000..8e5a1ef --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/.gitignore @@ -0,0 +1,32 @@ +# Security +.env +.temp.md +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# TypeScript +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# dotenv environment variables file +.env.test +.env.production + +# Optional VS Code settings +.vscode/* +# for local testing +helpers/fga-retriever.ts diff --git a/examples/authorization-for-rag/langgraph-agentic/README.md b/examples/authorization-for-rag/langgraph-agentic/README.md new file mode 100644 index 0000000..ae3f4ec --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/README.md @@ -0,0 +1,72 @@ +# LangChain Retrievers + LangGraph Agents + Okta FGA + +This example demonstrates how to combine [LangChain](https://js.langchain.com/) RAG methods and [LangGraph](https://langchain-ai.github.io/langgraphjs/) agents with robust authorization controls for RAG workflows. Using [Okta FGA](https://docs.fga.dev/), it ensures that users can only access documents they are authorized to view. The example retrieves relevant documents, enforces access permissions, and generates responses based only on authorized data, maintaining strict data security and preventing unauthorized access. + +## Getting Started + +### Prerequisites + +- An Okta FGA account, you can create one [here](https://dashboard.fga.dev). +- An OpenAI account and API key create one [here](https://platform.openai.com). + +### Setup + +1. Create a `.env` file by renaming the included `.env.example` file. It should look like this: + + ```sh + # OpenAI + OPENAI_API_KEY=xx-xxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx + + # Okta FGA + FGA_STORE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx + FGA_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx + FGA_CLIENT_SECRET=xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx + # Required only for non-US regions + FGA_API_URL=https://api.xxx.fga.dev + FGA_API_AUDIENCE=https://api.xxx.fga.dev/ + ``` + +#### Obtain OpenAI API Key + +[Use this page for instructions on how to find your OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key). Once you have your key, update the `.env` file accordingly. + +#### Configure Okta FGA + +1. **Create a client** + + Navigate to _Settings_ and in the _Authorized Clients_ section click **+ Create Client** button. On the new page give your client a name and mark all three client permissions then click **Create**. + +2. Copy the information on the modal and update your `.env` file with the values you now have for `FGA_STORE_ID`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`. Click **Continue** to get values for `FGA_API_URL` and `FGA_API_AUDIENCE`. + +### How to run it + +1. Install dependencies. + + ```sh + $ npm install + ``` + +2. Initialize the FGA model and tuples + + ```sh + $ npm run fga:init + ``` + +3. Running the example + + ```sh + npm start + ``` + +--- + +

+ + + + Auth0 Logo + +

+

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

+

+This project is licensed under the Apache 2.0 license. See the LICENSE file for more info.

diff --git a/examples/authorization-for-rag/langgraph-agentic/assets/docs/private-doc.md b/examples/authorization-for-rag/langgraph-agentic/assets/docs/private-doc.md new file mode 100644 index 0000000..2ed6baa --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/assets/docs/private-doc.md @@ -0,0 +1,36 @@ +**Zeko Advanced Systems Inc. (Ticker: ZEKO)** +**Forecast for Fiscal Year 2025** + +**Executive Summary:** + +As we look ahead to fiscal year 2025, we maintain a bearish outlook on Zeko Advanced Systems Inc. (ZEKO). Despite the company's stable performance in recent quarters, several factors suggest that ZEKO may underperform the broader market in the coming year. Our analysis considers the company's financial performance, market dynamics, and strategic positioning, which collectively indicate potential headwinds that could hinder growth and profitability. + +**Revenue Growth Challenges:** + +While Zeko reported a modest 2.3% increase in revenue for Q3 2024, this growth rate lags behind industry peers and suggests potential challenges in sustaining momentum. The company's reliance on digital health solutions and AI-driven patient monitoring devices, while innovative, may face increased competition from both established players and new entrants. Additionally, economic uncertainties and geopolitical tensions could dampen demand in key emerging markets, particularly in Asia and the Middle East, where Zeko is focusing its expansion efforts. + +**Margin Pressures:** + +Zeko's gross margin declined slightly to 55% in Q3 2024, primarily due to rising raw material costs and ongoing supply chain disruptions. These pressures are expected to persist into 2025, further compressing margins and impacting profitability. Additionally, the company's significant investment in research and development, while necessary for innovation, may not yield immediate returns, thereby straining operating margins. + +**Operational and Strategic Concerns:** + +Despite Zeko's commitment to innovation and strategic partnerships, the pace of product development and market adoption may not be sufficient to drive significant revenue growth. The introduction of new AI-driven platforms and minimally invasive surgical technologies, while promising, may face regulatory hurdles and require extensive validation before achieving widespread adoption. Furthermore, the company's expansion into emerging markets presents inherent risks, including currency fluctuations and regulatory challenges. + +**Financial Outlook:** + +- **Revenue:** We project Zeko's revenue growth to remain subdued, with an estimated increase of 2-3% for fiscal year 2025. This projection reflects the anticipated competitive pressures and macroeconomic uncertainties that could limit market expansion. + +- **Net Income:** Net income growth is expected to be modest, with potential headwinds from increased operational costs and margin pressures. We forecast a net income increase of 1-2% year-over-year. + +- **Earnings Per Share (EPS):** Given the expected challenges in revenue and net income growth, we anticipate EPS to grow at a similar rate of 1-2%, potentially reaching $1.64 to $1.65 for fiscal year 2025. + +- **Gross Margin:** Gross margin is likely to remain under pressure, potentially declining further to 54-55% as cost challenges persist. + +**Conclusion:** + +In conclusion, while Zeko Advanced Systems Inc. continues to demonstrate resilience and a commitment to innovation, the company faces significant challenges that may impede its ability to outperform the market in fiscal year 2025. Investors should remain cautious and consider these potential headwinds when evaluating ZEKO as an investment opportunity. The company's strategic focus on emerging markets and new product development, while commendable, may not deliver the desired financial performance in the near term. As such, we maintain a bearish outlook on Zeko's prospects for the upcoming fiscal year. + +--- + +**Note:** This document is purely fictional and is generated for the purpose of a mock or example use case. All names, technologies, and concepts mentioned are invented. diff --git a/examples/authorization-for-rag/langgraph-agentic/assets/docs/public-doc.md b/examples/authorization-for-rag/langgraph-agentic/assets/docs/public-doc.md new file mode 100644 index 0000000..bbc44cb --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/assets/docs/public-doc.md @@ -0,0 +1,127 @@ +# Zeko Advanced Systems Inc. Documentation + +## Table of Contents + +1. **Introduction** +2. **Company Overview** +3. **Core Technologies** +4. **Products & Services** +5. **Research & Development** +6. **Corporate Governance** + +--- + +## 1. **Introduction** + +Welcome to the official documentation for **Zeko Advanced Systems Inc.**. This document provides an overview of our company, the technologies we develop, the products we offer, and our corporate structure. Zeko Advanced Systems Inc. is a pioneering organization at the cutting edge of technological innovation, specializing in high-performance computing, artificial intelligence, and advanced robotics. + +--- + +## 2. **Company Overview** + +**Zeko Advanced Systems Inc.** (ZAS) was founded in 2011 by a group of visionary engineers and entrepreneurs dedicated to creating the next generation of intelligent systems. Based in Silicon Valley, California, Zeko has grown into a leading force in the tech industry, delivering groundbreaking solutions in multiple sectors including aerospace, defense, healthcare, and consumer technology. + +### Mission Statement + +Our mission is to revolutionize industries by delivering advanced systems that combine artificial intelligence, machine learning, and quantum computing. We aim to enhance human capability and improve the quality of life for people around the world. + +### Vision + +We envision a future where intelligent systems drive progress in every field, from autonomous vehicles to personalized healthcare, making the impossible possible. + +--- + +## 3. **Core Technologies** + +At Zeko Advanced Systems Inc., we specialize in developing a suite of cutting-edge technologies that push the boundaries of what is possible. + +### **Quantum Computing** + +Our quantum computing division is at the forefront of developing scalable, fault-tolerant quantum processors. Zeko's proprietary QuantumFusion™ technology promises to revolutionize industries by enabling unprecedented computational power for complex simulations, cryptography, and data analysis. + +### **Artificial Intelligence** + +Our AI platforms leverage deep learning, neural networks, and natural language processing to deliver innovative solutions for automation, predictive analytics, and intelligent decision-making. Zeko’s AI systems are deployed in sectors such as financial services, manufacturing, and autonomous driving. + +### **Autonomous Robotics** + +Zeko’s robotics division specializes in creating highly intelligent, autonomous robots capable of performing complex tasks in dynamic environments. Our robots are utilized in various fields, including logistics, healthcare, and hazardous material handling. + +### **Cybersecurity Solutions** + +Zeko Advanced Systems Inc. offers a comprehensive range of cybersecurity products designed to protect enterprises against emerging threats. Our ZeroTrust™ security architecture provides multi-layered protection across cloud infrastructure, endpoints, and internal networks. + +--- + +## 4. **Products & Services** + +Zeko Advanced Systems Inc. provides a diverse array of products and services tailored to meet the specific needs of different industries. + +### **Zeko Axiom™ (Quantum Processor)** + +The Zeko Axiom™ is a state-of-the-art quantum processor designed for high-performance computing tasks, capable of solving complex problems that would take traditional supercomputers millennia to process. + +### **Zeko NeuralNet™ (AI Platform)** + +Our Zeko NeuralNet™ platform is an all-in-one artificial intelligence suite that helps businesses streamline operations, optimize decision-making, and build smarter systems. It includes machine learning models, pre-trained algorithms, and customizable templates for deployment. + +### **Zeko RoboFleet™ (Autonomous Vehicles)** + +The Zeko RoboFleet™ is a fleet of autonomous, electric vehicles designed for commercial applications, including logistics, delivery, and public transportation. Equipped with cutting-edge sensors and AI, RoboFleet™ operates safely in urban environments. + +### **Zeko SecureShield™ (Cybersecurity Suite)** + +Zeko SecureShield™ is an enterprise-grade cybersecurity solution that integrates artificial intelligence with advanced encryption technologies to safeguard your data against the latest threats. With real-time threat detection and response, it provides a 360-degree defense perimeter for your organization. + +### **Zeko CloudX™ (Cloud Computing Services)** + +Zeko CloudX™ is our scalable cloud infrastructure platform that powers businesses with reliable storage, processing power, and seamless data management. Optimized for AI workloads and quantum computing, CloudX™ offers a flexible environment for developing and deploying next-gen applications. + +--- + +## 5. **Research & Development** + +Zeko Advanced Systems Inc. is committed to continuous innovation. Our R&D department plays a pivotal role in ensuring that our technologies remain on the cutting edge. We invest over 30% of our annual revenue into R&D to explore new solutions, improve existing products, and identify future industry needs. + +### Key R&D Focus Areas: + +- **Quantum Machine Learning:** We are developing quantum-enhanced machine learning models that can outperform classical systems in data analysis and pattern recognition. +- **AI-Driven Robotics:** Our team is working on next-gen autonomous robots that can adapt in real-time to changing environments and learn from experience. +- **Advanced Materials for Quantum Hardware:** Our materials science team is exploring novel compounds for the development of more stable, energy-efficient quantum processors. + +--- + +## 6. **Corporate Governance** + +Zeko Advanced Systems Inc. is governed by a team of seasoned executives and industry experts. Our leadership is dedicated to ensuring the long-term growth of the company, while maintaining high standards of ethics and responsibility. + +### **Board of Directors:** + +- **Elliott Zeko** - CEO & Founder +- **Dr. Helena Wong** - Chief Technology Officer (CTO) +- **Sarah Perez** - Chief Financial Officer (CFO) +- **Dr. Alan Tan** - Chief Operating Officer (COO) +- **Rebecca Knight** - Chief Marketing Officer (CMO) + +### **Executive Leadership Team:** + +- **John Carver** - Senior Vice President of Research & Development +- **Samantha Lee** - Vice President of AI & Robotics +- **Marcus Holt** - Vice President of Cloud & Cybersecurity Solutions +- **Emily Jordan** - Vice President of Strategic Partnerships + +--- + +## 7. **Partnerships & Collaborations** + +Zeko Advanced Systems Inc. is proud to collaborate with a variety of industry leaders, research institutions, and government agencies. Our strategic partnerships allow us to leverage combined expertise and drive forward-thinking solutions. + +### Notable Partnerships: + +- **NASA**: Joint development of autonomous systems for space exploration missions. +- **MIT AI Lab**: Collaborative research into artificial general intelligence (AGI) and machine learning. +- **Tesla**: Integration of Zeko’s AI platform into Tesla's autonomous driving systems. + +--- + +**Note:** This document is purely fictional and is generated for the purpose of a mock or example use case. All names, technologies, and concepts mentioned are invented. diff --git a/examples/authorization-for-rag/langgraph-agentic/helpers/langchain.ts b/examples/authorization-for-rag/langgraph-agentic/helpers/langchain.ts new file mode 100644 index 0000000..51ae7fe --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/helpers/langchain.ts @@ -0,0 +1,41 @@ +import { StructuredToolInterface } from "@langchain/core/tools"; +import { createReactAgent } from "@langchain/langgraph/prebuilt"; +import { ChatOpenAI } from "@langchain/openai"; + +export class RetrievalAgent { + private agent; + + private constructor(agent) { + this.agent = agent; + } + + // Create a retrieval agent with a retriever tool and a language model + static create(tools: StructuredToolInterface[]) { + // Create a retrieval agent that has access to the retrieval tool. + const retrievalAgent = createReactAgent({ + llm: new ChatOpenAI({ temperature: 0, model: "gpt-4o-mini" }), + tools, + stateModifier: [ + "Answer the user's question only based on context retrieved from provided tools.", + "Only use the information provided by the tools.", + "If you need more information, ask for it.", + ].join(" "), + }); + + return new RetrievalAgent(retrievalAgent); + } + + // Query the retrieval agent with a user question + async query(query: string) { + const { messages } = await this.agent.invoke({ + messages: [ + { + role: "user", + content: query, + }, + ], + }); + + return messages.at(-1)?.content; + } +} diff --git a/examples/authorization-for-rag/langgraph-agentic/helpers/read-documents.ts b/examples/authorization-for-rag/langgraph-agentic/helpers/read-documents.ts new file mode 100644 index 0000000..a24dbeb --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/helpers/read-documents.ts @@ -0,0 +1,25 @@ +import fs from "node:fs/promises"; + +import { Document } from "@langchain/core/documents"; + +async function readDoc(path: string) { + return await fs.readFile(path, "utf-8"); +} + +/* Reads documents from the assets folder and converts them to langChain Documents */ +export async function readDocuments() { + const folderPath = "./assets/docs"; + const files = await fs.readdir(folderPath); + const documents: Document[] = []; + + for (const file of files) { + documents.push( + new Document({ + pageContent: await readDoc(`${folderPath}/${file}`), + metadata: { id: file.slice(0, file.lastIndexOf(".")) }, + }) + ); + } + + return documents; +} diff --git a/examples/authorization-for-rag/langgraph-agentic/index.ts b/examples/authorization-for-rag/langgraph-agentic/index.ts new file mode 100644 index 0000000..37dc30c --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/index.ts @@ -0,0 +1,72 @@ +/** + * LangChain + LangGraph Agents Example: Agentic Retrieval with Okta FGA (Fine-Grained Authorization) + */ +import "dotenv/config"; + +import { OpenAIEmbeddings } from "@langchain/openai"; +import { MemoryVectorStore } from "langchain/vectorstores/memory"; +import { FGARetriever } from "@auth0/ai-langchain"; + +import { readDocuments } from "./helpers/read-documents"; +import { RetrievalAgent } from "./helpers/langchain"; + +/** + * Demonstrates the usage of the Okta FGA (Fine-Grained Authorization) + * with a vector store index to query documents with permission checks. + * + * The FGARetriever checks if the user has the "viewer" relation to the document + * based on predefined tuples in Okta FGA. + * + * Example: + * - A tuple {user: "user:*", relation: "viewer", object: "doc:public-doc"} allows all users to view "public-doc". + * - A tuple {user: "user:user1", relation: "viewer", object: "doc:private-doc"} allows "user1" to view "private-doc". + * + * The output of the query depends on the user's permissions to view the documents. + */ +async function main() { + console.info( + "\n..:: LangChain + LangGraph Agents Example: Agentic Retrieval with Okta FGA (Fine-Grained Authorization)\n\n" + ); + + // UserID + const user = "user1"; + // 1. Read and load documents from the assets folder + const documents = await readDocuments(); + // 2. Create an in-memory vector store from the documents for OpenAI models. + const vectorStore = await MemoryVectorStore.fromDocuments( + documents, + new OpenAIEmbeddings({ model: "text-embedding-3-small" }) + ); + // 3. Create a retriever that uses FGA to gate fetching documents on permissions. + const retriever = FGARetriever.create({ + retriever: vectorStore.asRetriever(), + // FGA tuple to query for the user's permissions + buildQuery: (doc) => ({ + user: `user:${user}`, + object: `doc:${doc.metadata.id}`, + relation: "viewer", + }), + }); + // 4. Convert the retriever into a tool for an agent. + const fgaTool = retriever.asJoinedStringTool(); + // 5. The agent will call the tool, rephrasing the original question and + // populating the "query" argument, until it can answer the user's question. + const retrievalAgent = RetrievalAgent.create([fgaTool]); + // 6. Query the retrieval agent with a prompt + const answer = await retrievalAgent.query("Show me forecast for ZEKO?"); + + /** + * Output: `The provided context does not include specific financial forecasts...` + */ + console.info(answer); + + /** + * If we add the following tuple to the Okta FGA: + * + * { user: "user:user1", relation: "viewer", object: "doc:private-doc" } + * + * Then, the output will be: `The forecast for Zeko Advanced Systems Inc. (ZEKO) for fiscal year 2025...` + */ +} + +main().catch(console.error); diff --git a/examples/authorization-for-rag/langgraph-agentic/package-lock.json b/examples/authorization-for-rag/langgraph-agentic/package-lock.json new file mode 100644 index 0000000..1241ca9 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/package-lock.json @@ -0,0 +1,849 @@ +{ + "name": "auth0-langchain-rag-js", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "auth0-langchain-rag-js", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "@langchain/core": "^0.3.32", + "@langchain/langgraph": "^0.2.41", + "@langchain/openai": "^0.3.17", + "@openfga/sdk": "^0.8.0", + "dotenv": "^16.4.7", + "langchain": "^0.3.12", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/node": "^22.10.6" + } + }, + "node_modules/@cfworker/json-schema": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.0.3.tgz", + "integrity": "sha512-ZykIcDTVv5UNmKWSTLAs3VukO6NDJkkSKxrgUTDPBkAlORVT3H9n5DbRjRl8xIotklscHdbLIa0b9+y3mQq73g==", + "license": "MIT" + }, + "node_modules/@langchain/core": { + "version": "0.3.32", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.32.tgz", + "integrity": "sha512-QesrB7qPrvdIKgCL6/hfa1e7+5dCCgunN5nRGvr0LYWEVuLBrUd93PDvpPP9Fk43+HZnS16adTCYOwX0Jad5Bw==", + "license": "MIT", + "dependencies": { + "@cfworker/json-schema": "^4.0.2", + "ansi-styles": "^5.0.0", + "camelcase": "6", + "decamelize": "1.2.0", + "js-tiktoken": "^1.0.12", + "langsmith": ">=0.2.8 <0.4.0", + "mustache": "^4.2.0", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^10.0.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@langchain/langgraph": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-0.2.41.tgz", + "integrity": "sha512-NeNizWP4k9voEwJxuFtfopF02Lx1isuEsdZKYCN3ueJpOnkVg0iGx8woPBsQpYcrWcySkIt3zOkgtUsrNHqo3g==", + "license": "MIT", + "dependencies": { + "@langchain/langgraph-checkpoint": "~0.0.13", + "@langchain/langgraph-sdk": "~0.0.32", + "uuid": "^10.0.0", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.36 <0.3.0 || >=0.3.9 < 0.4.0" + } + }, + "node_modules/@langchain/langgraph-checkpoint": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.13.tgz", + "integrity": "sha512-amdmBcNT8a9xP2VwcEWxqArng4gtRDcnVyVI4DsQIo1Aaz8e8+hH17zSwrUF3pt1pIYztngIfYnBOim31mtKMg==", + "license": "MIT", + "dependencies": { + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.31 <0.4.0" + } + }, + "node_modules/@langchain/langgraph-sdk": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.36.tgz", + "integrity": "sha512-KkAZM0uXBaMcD/dpGTBppOhbvNX6gz+Y1zFAC898OblegFkSvICrkd0oRQ5Ro/GWK/NAoDymnMUDXeZDdUkSuw==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0" + } + }, + "node_modules/@langchain/langgraph-sdk/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@langchain/openai": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.3.17.tgz", + "integrity": "sha512-uw4po32OKptVjq+CYHrumgbfh4NuD7LqyE+ZgqY9I/LrLc6bHLMc+sisHmI17vgek0K/yqtarI0alPJbzrwyag==", + "license": "MIT", + "dependencies": { + "js-tiktoken": "^1.0.12", + "openai": "^4.77.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.3.29 <0.4.0" + } + }, + "node_modules/@langchain/textsplitters": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@langchain/textsplitters/-/textsplitters-0.1.0.tgz", + "integrity": "sha512-djI4uw9rlkAb5iMhtLED+xJebDdAG935AdP4eRTB02R7OB/act55Bj9wsskhZsvuyQRpO4O1wQOp85s6T6GWmw==", + "license": "MIT", + "dependencies": { + "js-tiktoken": "^1.0.12" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.21 <0.4.0" + } + }, + "node_modules/@openfga/sdk": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@openfga/sdk/-/sdk-0.8.0.tgz", + "integrity": "sha512-tFd5oQ6a3ps8Qbj9V8VhETyKnl7QtQa0o9G9464yI6KAih0FhMg/5e1/T701j6hkeGqGGJCmv1csD/OXyGCpFQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "axios": "^1.7.9", + "tiny-async-pool": "^2.1.0" + }, + "engines": { + "node": ">=16.15.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.6.tgz", + "integrity": "sha512-qNiuwC4ZDAUNcY47xgaSuS92cjf8JbSUoaKS77bmLG1rU7MlATVSiw/IlrjtIyyskXBZ8KkNfjK/P5na7rgXbQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/js-tiktoken": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.16.tgz", + "integrity": "sha512-nUVdO5k/M9llWpiaZlBBDdtmr6qWXwSD6fgaDu2zM8UP+OXxx9V37lFkI6w0/1IuaDx7WffZ37oYd9KvcWKElg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.5.1" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/langchain": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.3.12.tgz", + "integrity": "sha512-BjdQ/f/66W05L8nRgX74bf5QvJIphpg+K5ZTmQwGE8Gk3umtzHp8T4YIRFYjvTxU4XQrGXOgWk1Y9rk5uBbjKA==", + "license": "MIT", + "dependencies": { + "@langchain/openai": ">=0.1.0 <0.4.0", + "@langchain/textsplitters": ">=0.0.0 <0.2.0", + "js-tiktoken": "^1.0.12", + "js-yaml": "^4.1.0", + "jsonpointer": "^5.0.1", + "langsmith": ">=0.2.8 <0.4.0", + "openapi-types": "^12.1.3", + "p-retry": "4", + "uuid": "^10.0.0", + "yaml": "^2.2.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/anthropic": "*", + "@langchain/aws": "*", + "@langchain/cerebras": "*", + "@langchain/cohere": "*", + "@langchain/core": ">=0.2.21 <0.4.0", + "@langchain/google-genai": "*", + "@langchain/google-vertexai": "*", + "@langchain/google-vertexai-web": "*", + "@langchain/groq": "*", + "@langchain/mistralai": "*", + "@langchain/ollama": "*", + "axios": "*", + "cheerio": "*", + "handlebars": "^4.7.8", + "peggy": "^3.0.2", + "typeorm": "*" + }, + "peerDependenciesMeta": { + "@langchain/anthropic": { + "optional": true + }, + "@langchain/aws": { + "optional": true + }, + "@langchain/cerebras": { + "optional": true + }, + "@langchain/cohere": { + "optional": true + }, + "@langchain/google-genai": { + "optional": true + }, + "@langchain/google-vertexai": { + "optional": true + }, + "@langchain/google-vertexai-web": { + "optional": true + }, + "@langchain/groq": { + "optional": true + }, + "@langchain/mistralai": { + "optional": true + }, + "@langchain/ollama": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "peggy": { + "optional": true + }, + "typeorm": { + "optional": true + } + } + }, + "node_modules/langsmith": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.2.14.tgz", + "integrity": "sha512-ClAuAgSf3m9miMYotLEaZKQyKdaWlfjhebCuYco8bc6g72dU2VwTg31Bv4YINBq7EH2i1cMwbOiJxbOXPqjGig==", + "license": "MIT", + "dependencies": { + "@types/uuid": "^10.0.0", + "commander": "^10.0.1", + "p-queue": "^6.6.2", + "p-retry": "4", + "semver": "^7.6.3", + "uuid": "^10.0.0" + }, + "peerDependencies": { + "openai": "*" + }, + "peerDependenciesMeta": { + "openai": { + "optional": true + } + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/openai": { + "version": "4.77.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.77.3.tgz", + "integrity": "sha512-wLDy4+KWHz31HRFMW2+9KQuVuT2QWhs0z94w1Gm1h2Ut9vIHr9/rHZggbykZEfyiaJRVgw8ZS9K6AylDWzvPYw==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.70", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.70.tgz", + "integrity": "sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tiny-async-pool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-2.1.0.tgz", + "integrity": "sha512-ltAHPh/9k0STRQqaoUX52NH4ZQYAJz24ZAEwf1Zm+HYg3l9OXTWeqWKyYsHu40wF/F0rxd2N2bk5sLvX2qlSvg==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zod": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz", + "integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/examples/authorization-for-rag/langgraph-agentic/package.json b/examples/authorization-for-rag/langgraph-agentic/package.json new file mode 100644 index 0000000..3cde412 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/package.json @@ -0,0 +1,29 @@ +{ + "name": "auth0-langgraph-agentic-rag-js", + "version": "0.0.0", + "description": "Demonstrates the usage of the Okta FGA with LangChain to query documents with permission checks.", + "x-type": "module", + "main": "index.js", + "author": { + "name": "Auth0 Inc.", + "url": "https://auth0.com" + }, + "license": "Apache-2.0", + "scripts": { + "start": "npx tsx index.ts", + "fga:init": "npx tsx ./scripts/fga-init.ts" + }, + "dependencies": { + "@auth0/ai-langchain": "*", + "@langchain/core": "^0.3.33", + "@langchain/langgraph": "^0.2.41", + "@langchain/openai": "^0.3.17", + "@openfga/sdk": "^0.8.0", + "dotenv": "^16.4.7", + "langchain": "^0.3.12", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/node": "^22.10.7" + } +} diff --git a/examples/authorization-for-rag/langgraph-agentic/scripts/fga-init.ts b/examples/authorization-for-rag/langgraph-agentic/scripts/fga-init.ts new file mode 100644 index 0000000..6bfa232 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-agentic/scripts/fga-init.ts @@ -0,0 +1,66 @@ +import "dotenv/config"; + +import { CredentialsMethod, OpenFgaClient } from "@openfga/sdk"; + +/** + * Initializes the OpenFgaClient, writes an authorization model, and configures pre-defined tuples. + * + * This function performs the following steps: + * 1. Creates an instance of OpenFgaClient with the necessary configuration. + * 2. Writes an authorization model with specified schema version and type definitions. + * 3. Configures pre-defined tuples using the newly created authorization model. + */ +async function main() { + const fgaClient = new OpenFgaClient({ + apiUrl: process.env.FGA_API_URL || "https://api.us1.fga.dev", + storeId: process.env.FGA_STORE_ID!, + credentials: { + method: CredentialsMethod.ClientCredentials, + config: { + apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER || "auth.fga.dev", + apiAudience: process.env.FGA_API_AUDIENCE || "https://api.us1.fga.dev/", + clientId: process.env.FGA_CLIENT_ID!, + clientSecret: process.env.FGA_CLIENT_SECRET!, + }, + }, + }); + + // 01. WRITE MODEL + const model = await fgaClient.writeAuthorizationModel({ + schema_version: "1.1", + type_definitions: [ + { type: "user" }, + { + type: "doc", + relations: { owner: { this: {} }, viewer: { this: {} } }, + metadata: { + relations: { + owner: { directly_related_user_types: [{ type: "user" }] }, + viewer: { + directly_related_user_types: [ + { type: "user" }, + { type: "user", wildcard: {} }, + ], + }, + }, + }, + }, + ], + }); + + console.log("NEW MODEL ID: ", model.authorization_model_id); + + // 02. CONFIGURE PRE-DEFINED TUPLES + await fgaClient.write( + { + writes: [ + { user: "user:*", relation: "viewer", object: "doc:public-doc" }, + ], + }, + { + authorizationModelId: model.authorization_model_id, + } + ); +} + +main().catch(console.error); diff --git a/examples/authorization-for-rag/langgraph-stategraph/.env.example b/examples/authorization-for-rag/langgraph-stategraph/.env.example new file mode 100644 index 0000000..b5f2690 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/.env.example @@ -0,0 +1,11 @@ +# OpenAI +OPENAI_API_KEY= + + +# Okta FGA +FGA_STORE_ID= +FGA_CLIENT_ID= +FGA_CLIENT_SECRET= +# Required only for non-US regions +FGA_API_URL=https://api.xxx.fga.dev +FGA_API_AUDIENCE=https://api.xxx.fga.dev/ diff --git a/examples/authorization-for-rag/langgraph-stategraph/.gitignore b/examples/authorization-for-rag/langgraph-stategraph/.gitignore new file mode 100644 index 0000000..44dee43 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/.gitignore @@ -0,0 +1,30 @@ +# Security +.env +.temp.md +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# TypeScript +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# dotenv environment variables file +.env.test +.env.production + +# Optional VS Code settings +.vscode/* diff --git a/examples/authorization-for-rag/langgraph-stategraph/README.md b/examples/authorization-for-rag/langgraph-stategraph/README.md new file mode 100644 index 0000000..1f87c5f --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/README.md @@ -0,0 +1,72 @@ +# LangChain Retrievers + LangGraph StateGraph + Okta FGA + +This example demonstrates how to combine [LangChain](https://js.langchain.com/) RAG methods and [LangGraph](https://langchain-ai.github.io/langgraphjs/) with robust authorization controls for RAG workflows. Using [Okta FGA](https://docs.fga.dev/), it ensures that users can only access documents they are authorized to view. The example retrieves relevant documents, enforces access permissions, and generates responses based only on authorized data, maintaining strict data security and preventing unauthorized access. + +## Getting Started + +### Prerequisites + +- An Okta FGA account, you can create one [here](https://dashboard.fga.dev). +- An OpenAI account and API key create one [here](https://platform.openai.com). + +### Setup + +1. Create a `.env` file by renaming the included `.env.example` file. It should look like this: + + ```sh + # OpenAI + OPENAI_API_KEY=xx-xxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx + + # Okta FGA + FGA_STORE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx + FGA_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx + FGA_CLIENT_SECRET=xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx + # Required only for non-US regions + FGA_API_URL=https://api.xxx.fga.dev + FGA_API_AUDIENCE=https://api.xxx.fga.dev/ + ``` + +#### Obtain OpenAI API Key + +[Use this page for instructions on how to find your OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key). Once you have your key, update the `.env` file accordingly. + +#### Configure Okta FGA + +1. **Create a client** + + Navigate to _Settings_ and in the _Authorized Clients_ section click **+ Create Client** button. On the new page give your client a name and mark all three client permissions then click **Create**. + +2. Copy the information on the modal and update your `.env` file with the values you now have for `FGA_STORE_ID`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`. Click **Continue** to get values for `FGA_API_URL` and `FGA_API_AUDIENCE`. + +### How to run it + +1. Install dependencies. + + ```sh + $ npm install + ``` + +2. Initialize the FGA model and tuples + + ```sh + $ npm run fga:init + ``` + +3. Running the example + + ```sh + npm start + ``` + +--- + +

+ + + + Auth0 Logo + +

+

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

+

+This project is licensed under the Apache 2.0 license. See the LICENSE file for more info.

diff --git a/examples/authorization-for-rag/langgraph-stategraph/assets/docs/private-doc.md b/examples/authorization-for-rag/langgraph-stategraph/assets/docs/private-doc.md new file mode 100644 index 0000000..2ed6baa --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/assets/docs/private-doc.md @@ -0,0 +1,36 @@ +**Zeko Advanced Systems Inc. (Ticker: ZEKO)** +**Forecast for Fiscal Year 2025** + +**Executive Summary:** + +As we look ahead to fiscal year 2025, we maintain a bearish outlook on Zeko Advanced Systems Inc. (ZEKO). Despite the company's stable performance in recent quarters, several factors suggest that ZEKO may underperform the broader market in the coming year. Our analysis considers the company's financial performance, market dynamics, and strategic positioning, which collectively indicate potential headwinds that could hinder growth and profitability. + +**Revenue Growth Challenges:** + +While Zeko reported a modest 2.3% increase in revenue for Q3 2024, this growth rate lags behind industry peers and suggests potential challenges in sustaining momentum. The company's reliance on digital health solutions and AI-driven patient monitoring devices, while innovative, may face increased competition from both established players and new entrants. Additionally, economic uncertainties and geopolitical tensions could dampen demand in key emerging markets, particularly in Asia and the Middle East, where Zeko is focusing its expansion efforts. + +**Margin Pressures:** + +Zeko's gross margin declined slightly to 55% in Q3 2024, primarily due to rising raw material costs and ongoing supply chain disruptions. These pressures are expected to persist into 2025, further compressing margins and impacting profitability. Additionally, the company's significant investment in research and development, while necessary for innovation, may not yield immediate returns, thereby straining operating margins. + +**Operational and Strategic Concerns:** + +Despite Zeko's commitment to innovation and strategic partnerships, the pace of product development and market adoption may not be sufficient to drive significant revenue growth. The introduction of new AI-driven platforms and minimally invasive surgical technologies, while promising, may face regulatory hurdles and require extensive validation before achieving widespread adoption. Furthermore, the company's expansion into emerging markets presents inherent risks, including currency fluctuations and regulatory challenges. + +**Financial Outlook:** + +- **Revenue:** We project Zeko's revenue growth to remain subdued, with an estimated increase of 2-3% for fiscal year 2025. This projection reflects the anticipated competitive pressures and macroeconomic uncertainties that could limit market expansion. + +- **Net Income:** Net income growth is expected to be modest, with potential headwinds from increased operational costs and margin pressures. We forecast a net income increase of 1-2% year-over-year. + +- **Earnings Per Share (EPS):** Given the expected challenges in revenue and net income growth, we anticipate EPS to grow at a similar rate of 1-2%, potentially reaching $1.64 to $1.65 for fiscal year 2025. + +- **Gross Margin:** Gross margin is likely to remain under pressure, potentially declining further to 54-55% as cost challenges persist. + +**Conclusion:** + +In conclusion, while Zeko Advanced Systems Inc. continues to demonstrate resilience and a commitment to innovation, the company faces significant challenges that may impede its ability to outperform the market in fiscal year 2025. Investors should remain cautious and consider these potential headwinds when evaluating ZEKO as an investment opportunity. The company's strategic focus on emerging markets and new product development, while commendable, may not deliver the desired financial performance in the near term. As such, we maintain a bearish outlook on Zeko's prospects for the upcoming fiscal year. + +--- + +**Note:** This document is purely fictional and is generated for the purpose of a mock or example use case. All names, technologies, and concepts mentioned are invented. diff --git a/examples/authorization-for-rag/langgraph-stategraph/assets/docs/public-doc.md b/examples/authorization-for-rag/langgraph-stategraph/assets/docs/public-doc.md new file mode 100644 index 0000000..bbc44cb --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/assets/docs/public-doc.md @@ -0,0 +1,127 @@ +# Zeko Advanced Systems Inc. Documentation + +## Table of Contents + +1. **Introduction** +2. **Company Overview** +3. **Core Technologies** +4. **Products & Services** +5. **Research & Development** +6. **Corporate Governance** + +--- + +## 1. **Introduction** + +Welcome to the official documentation for **Zeko Advanced Systems Inc.**. This document provides an overview of our company, the technologies we develop, the products we offer, and our corporate structure. Zeko Advanced Systems Inc. is a pioneering organization at the cutting edge of technological innovation, specializing in high-performance computing, artificial intelligence, and advanced robotics. + +--- + +## 2. **Company Overview** + +**Zeko Advanced Systems Inc.** (ZAS) was founded in 2011 by a group of visionary engineers and entrepreneurs dedicated to creating the next generation of intelligent systems. Based in Silicon Valley, California, Zeko has grown into a leading force in the tech industry, delivering groundbreaking solutions in multiple sectors including aerospace, defense, healthcare, and consumer technology. + +### Mission Statement + +Our mission is to revolutionize industries by delivering advanced systems that combine artificial intelligence, machine learning, and quantum computing. We aim to enhance human capability and improve the quality of life for people around the world. + +### Vision + +We envision a future where intelligent systems drive progress in every field, from autonomous vehicles to personalized healthcare, making the impossible possible. + +--- + +## 3. **Core Technologies** + +At Zeko Advanced Systems Inc., we specialize in developing a suite of cutting-edge technologies that push the boundaries of what is possible. + +### **Quantum Computing** + +Our quantum computing division is at the forefront of developing scalable, fault-tolerant quantum processors. Zeko's proprietary QuantumFusion™ technology promises to revolutionize industries by enabling unprecedented computational power for complex simulations, cryptography, and data analysis. + +### **Artificial Intelligence** + +Our AI platforms leverage deep learning, neural networks, and natural language processing to deliver innovative solutions for automation, predictive analytics, and intelligent decision-making. Zeko’s AI systems are deployed in sectors such as financial services, manufacturing, and autonomous driving. + +### **Autonomous Robotics** + +Zeko’s robotics division specializes in creating highly intelligent, autonomous robots capable of performing complex tasks in dynamic environments. Our robots are utilized in various fields, including logistics, healthcare, and hazardous material handling. + +### **Cybersecurity Solutions** + +Zeko Advanced Systems Inc. offers a comprehensive range of cybersecurity products designed to protect enterprises against emerging threats. Our ZeroTrust™ security architecture provides multi-layered protection across cloud infrastructure, endpoints, and internal networks. + +--- + +## 4. **Products & Services** + +Zeko Advanced Systems Inc. provides a diverse array of products and services tailored to meet the specific needs of different industries. + +### **Zeko Axiom™ (Quantum Processor)** + +The Zeko Axiom™ is a state-of-the-art quantum processor designed for high-performance computing tasks, capable of solving complex problems that would take traditional supercomputers millennia to process. + +### **Zeko NeuralNet™ (AI Platform)** + +Our Zeko NeuralNet™ platform is an all-in-one artificial intelligence suite that helps businesses streamline operations, optimize decision-making, and build smarter systems. It includes machine learning models, pre-trained algorithms, and customizable templates for deployment. + +### **Zeko RoboFleet™ (Autonomous Vehicles)** + +The Zeko RoboFleet™ is a fleet of autonomous, electric vehicles designed for commercial applications, including logistics, delivery, and public transportation. Equipped with cutting-edge sensors and AI, RoboFleet™ operates safely in urban environments. + +### **Zeko SecureShield™ (Cybersecurity Suite)** + +Zeko SecureShield™ is an enterprise-grade cybersecurity solution that integrates artificial intelligence with advanced encryption technologies to safeguard your data against the latest threats. With real-time threat detection and response, it provides a 360-degree defense perimeter for your organization. + +### **Zeko CloudX™ (Cloud Computing Services)** + +Zeko CloudX™ is our scalable cloud infrastructure platform that powers businesses with reliable storage, processing power, and seamless data management. Optimized for AI workloads and quantum computing, CloudX™ offers a flexible environment for developing and deploying next-gen applications. + +--- + +## 5. **Research & Development** + +Zeko Advanced Systems Inc. is committed to continuous innovation. Our R&D department plays a pivotal role in ensuring that our technologies remain on the cutting edge. We invest over 30% of our annual revenue into R&D to explore new solutions, improve existing products, and identify future industry needs. + +### Key R&D Focus Areas: + +- **Quantum Machine Learning:** We are developing quantum-enhanced machine learning models that can outperform classical systems in data analysis and pattern recognition. +- **AI-Driven Robotics:** Our team is working on next-gen autonomous robots that can adapt in real-time to changing environments and learn from experience. +- **Advanced Materials for Quantum Hardware:** Our materials science team is exploring novel compounds for the development of more stable, energy-efficient quantum processors. + +--- + +## 6. **Corporate Governance** + +Zeko Advanced Systems Inc. is governed by a team of seasoned executives and industry experts. Our leadership is dedicated to ensuring the long-term growth of the company, while maintaining high standards of ethics and responsibility. + +### **Board of Directors:** + +- **Elliott Zeko** - CEO & Founder +- **Dr. Helena Wong** - Chief Technology Officer (CTO) +- **Sarah Perez** - Chief Financial Officer (CFO) +- **Dr. Alan Tan** - Chief Operating Officer (COO) +- **Rebecca Knight** - Chief Marketing Officer (CMO) + +### **Executive Leadership Team:** + +- **John Carver** - Senior Vice President of Research & Development +- **Samantha Lee** - Vice President of AI & Robotics +- **Marcus Holt** - Vice President of Cloud & Cybersecurity Solutions +- **Emily Jordan** - Vice President of Strategic Partnerships + +--- + +## 7. **Partnerships & Collaborations** + +Zeko Advanced Systems Inc. is proud to collaborate with a variety of industry leaders, research institutions, and government agencies. Our strategic partnerships allow us to leverage combined expertise and drive forward-thinking solutions. + +### Notable Partnerships: + +- **NASA**: Joint development of autonomous systems for space exploration missions. +- **MIT AI Lab**: Collaborative research into artificial general intelligence (AGI) and machine learning. +- **Tesla**: Integration of Zeko’s AI platform into Tesla's autonomous driving systems. + +--- + +**Note:** This document is purely fictional and is generated for the purpose of a mock or example use case. All names, technologies, and concepts mentioned are invented. diff --git a/examples/authorization-for-rag/langgraph-stategraph/helpers/read-documents.ts b/examples/authorization-for-rag/langgraph-stategraph/helpers/read-documents.ts new file mode 100644 index 0000000..a24dbeb --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/helpers/read-documents.ts @@ -0,0 +1,25 @@ +import fs from "node:fs/promises"; + +import { Document } from "@langchain/core/documents"; + +async function readDoc(path: string) { + return await fs.readFile(path, "utf-8"); +} + +/* Reads documents from the assets folder and converts them to langChain Documents */ +export async function readDocuments() { + const folderPath = "./assets/docs"; + const files = await fs.readdir(folderPath); + const documents: Document[] = []; + + for (const file of files) { + documents.push( + new Document({ + pageContent: await readDoc(`${folderPath}/${file}`), + metadata: { id: file.slice(0, file.lastIndexOf(".")) }, + }) + ); + } + + return documents; +} diff --git a/examples/authorization-for-rag/langgraph-stategraph/index.ts b/examples/authorization-for-rag/langgraph-stategraph/index.ts new file mode 100644 index 0000000..4ae41c0 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/index.ts @@ -0,0 +1,109 @@ +/** + * LangChain + LangGraph Example: Retrieval with Okta FGA (Fine-Grained Authorization) + */ +import "dotenv/config"; + +import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai"; +import { MemoryVectorStore } from "langchain/vectorstores/memory"; +import { Annotation, START, StateGraph } from "@langchain/langgraph"; +import { Document } from "@langchain/core/documents"; +import { FGARetriever } from "@auth0/ai-langchain"; + +import { readDocuments } from "./helpers/read-documents"; + +/** + * Demonstrates the usage of the Okta FGA (Fine-Grained Authorization) + * with a vector store index to query documents with permission checks. + * + * The FGARetriever checks if the user has the "viewer" relation to the document + * based on predefined tuples in Okta FGA. + * + * Example: + * - A tuple {user: "user:*", relation: "viewer", object: "doc:public-doc"} allows all users to view "public-doc". + * - A tuple {user: "user:user1", relation: "viewer", object: "doc:private-doc"} allows "user1" to view "private-doc". + * + * The output of the query depends on the user's permissions to view the documents. + */ +async function main() { + console.info( + "\n..:: LangChain + LangGraph Example: Retrieval with Okta FGA (Fine-Grained Authorization)\n\n" + ); + + const StateAnnotation = Annotation.Root({ + question: Annotation, + documents: Annotation, + response: Annotation, + }); + + // UserID + const user = "user1"; + // 1. Read and load documents from the assets folder + const documents = await readDocuments(); + // 2. Create an in-memory vector store from the documents for OpenAI models. + const vectorStore = await MemoryVectorStore.fromDocuments( + documents, + new OpenAIEmbeddings({ model: "text-embedding-3-small" }) + ); + const llm = new ChatOpenAI({ temperature: 0, model: "gpt-4o-mini" }); + + // 3. Create a retriever that uses FGA to gate fetching documents on permissions. + const retriever = FGARetriever.create({ + retriever: vectorStore.asRetriever(), + // FGA tuple to query for the user's permissions + buildQuery: (doc) => ({ + user: `user:${user}`, + object: `doc:${doc.metadata.id}`, + relation: "viewer", + }), + }); + + // 4. Create a state graph workflow + const workflow = new StateGraph(StateAnnotation) + // 5. add retriever as node to the graph + .addNode("retrieve", async (state) => ({ + documents: await retriever.invoke(state.question), + })) + // 6. Create a language model tool node + .addNode("prompt_llm", async (state) => { + const context = state.documents + .map((doc) => doc.pageContent) + .join("\n\n"); + const { content } = await llm.invoke([ + { + role: "system", + content: `Answer the user's question based on the following context: ${context}. + Only use the information provided in the context. If you need more information, ask for it.`, + }, + { + role: "user", + content: `Here is the question: ${state.question}`, + }, + ]); + return { + response: content, + }; + }) + .addEdge(START, "retrieve") + .addEdge("retrieve", "prompt_llm"); + const graph = workflow.compile(); + + // 6. Query the graph with a prompt + const state = await graph.invoke({ + question: "Show me forecast for ZEKO?", + }); + + /** + * Output: `The provided context does not include specific financial forecasts...` + */ + console.info(state.response); + + /** + * If we add the following tuple to the Okta FGA: + * + * { user: "user:user1", relation: "viewer", object: "doc:private-doc" } + * + * Then, the output will be: `The forecast for Zeko Advanced Systems Inc. (ZEKO) for fiscal year 2025...` + */ +} + +main().catch(console.error); diff --git a/examples/authorization-for-rag/langgraph-stategraph/package-lock.json b/examples/authorization-for-rag/langgraph-stategraph/package-lock.json new file mode 100644 index 0000000..c295682 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/package-lock.json @@ -0,0 +1,849 @@ +{ + "name": "auth0-langchain-rag-js", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "auth0-langchain-rag-js", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "@langchain/core": "^0.3.33", + "@langchain/langgraph": "^0.2.41", + "@langchain/openai": "^0.3.17", + "@openfga/sdk": "^0.8.0", + "dotenv": "^16.4.7", + "langchain": "^0.3.12", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/node": "^22.10.7" + } + }, + "node_modules/@cfworker/json-schema": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.0.3.tgz", + "integrity": "sha512-ZykIcDTVv5UNmKWSTLAs3VukO6NDJkkSKxrgUTDPBkAlORVT3H9n5DbRjRl8xIotklscHdbLIa0b9+y3mQq73g==", + "license": "MIT" + }, + "node_modules/@langchain/core": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.33.tgz", + "integrity": "sha512-gIszaRKWmP1HEgOhJLJaMiTMH8U3W9hG6raWihwpCTb0Ns7owjrmaqmgMa9h3W4/0xriaKfrfFBd6tepKsfxZA==", + "license": "MIT", + "dependencies": { + "@cfworker/json-schema": "^4.0.2", + "ansi-styles": "^5.0.0", + "camelcase": "6", + "decamelize": "1.2.0", + "js-tiktoken": "^1.0.12", + "langsmith": ">=0.2.8 <0.4.0", + "mustache": "^4.2.0", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^10.0.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@langchain/langgraph": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-0.2.41.tgz", + "integrity": "sha512-NeNizWP4k9voEwJxuFtfopF02Lx1isuEsdZKYCN3ueJpOnkVg0iGx8woPBsQpYcrWcySkIt3zOkgtUsrNHqo3g==", + "license": "MIT", + "dependencies": { + "@langchain/langgraph-checkpoint": "~0.0.13", + "@langchain/langgraph-sdk": "~0.0.32", + "uuid": "^10.0.0", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.36 <0.3.0 || >=0.3.9 < 0.4.0" + } + }, + "node_modules/@langchain/langgraph-checkpoint": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.13.tgz", + "integrity": "sha512-amdmBcNT8a9xP2VwcEWxqArng4gtRDcnVyVI4DsQIo1Aaz8e8+hH17zSwrUF3pt1pIYztngIfYnBOim31mtKMg==", + "license": "MIT", + "dependencies": { + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.31 <0.4.0" + } + }, + "node_modules/@langchain/langgraph-sdk": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.36.tgz", + "integrity": "sha512-KkAZM0uXBaMcD/dpGTBppOhbvNX6gz+Y1zFAC898OblegFkSvICrkd0oRQ5Ro/GWK/NAoDymnMUDXeZDdUkSuw==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0" + } + }, + "node_modules/@langchain/langgraph-sdk/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@langchain/openai": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.3.17.tgz", + "integrity": "sha512-uw4po32OKptVjq+CYHrumgbfh4NuD7LqyE+ZgqY9I/LrLc6bHLMc+sisHmI17vgek0K/yqtarI0alPJbzrwyag==", + "license": "MIT", + "dependencies": { + "js-tiktoken": "^1.0.12", + "openai": "^4.77.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.3.29 <0.4.0" + } + }, + "node_modules/@langchain/textsplitters": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@langchain/textsplitters/-/textsplitters-0.1.0.tgz", + "integrity": "sha512-djI4uw9rlkAb5iMhtLED+xJebDdAG935AdP4eRTB02R7OB/act55Bj9wsskhZsvuyQRpO4O1wQOp85s6T6GWmw==", + "license": "MIT", + "dependencies": { + "js-tiktoken": "^1.0.12" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.21 <0.4.0" + } + }, + "node_modules/@openfga/sdk": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@openfga/sdk/-/sdk-0.8.0.tgz", + "integrity": "sha512-tFd5oQ6a3ps8Qbj9V8VhETyKnl7QtQa0o9G9464yI6KAih0FhMg/5e1/T701j6hkeGqGGJCmv1csD/OXyGCpFQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "axios": "^1.7.9", + "tiny-async-pool": "^2.1.0" + }, + "engines": { + "node": ">=16.15.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/js-tiktoken": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.16.tgz", + "integrity": "sha512-nUVdO5k/M9llWpiaZlBBDdtmr6qWXwSD6fgaDu2zM8UP+OXxx9V37lFkI6w0/1IuaDx7WffZ37oYd9KvcWKElg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.5.1" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/langchain": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.3.12.tgz", + "integrity": "sha512-BjdQ/f/66W05L8nRgX74bf5QvJIphpg+K5ZTmQwGE8Gk3umtzHp8T4YIRFYjvTxU4XQrGXOgWk1Y9rk5uBbjKA==", + "license": "MIT", + "dependencies": { + "@langchain/openai": ">=0.1.0 <0.4.0", + "@langchain/textsplitters": ">=0.0.0 <0.2.0", + "js-tiktoken": "^1.0.12", + "js-yaml": "^4.1.0", + "jsonpointer": "^5.0.1", + "langsmith": ">=0.2.8 <0.4.0", + "openapi-types": "^12.1.3", + "p-retry": "4", + "uuid": "^10.0.0", + "yaml": "^2.2.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/anthropic": "*", + "@langchain/aws": "*", + "@langchain/cerebras": "*", + "@langchain/cohere": "*", + "@langchain/core": ">=0.2.21 <0.4.0", + "@langchain/google-genai": "*", + "@langchain/google-vertexai": "*", + "@langchain/google-vertexai-web": "*", + "@langchain/groq": "*", + "@langchain/mistralai": "*", + "@langchain/ollama": "*", + "axios": "*", + "cheerio": "*", + "handlebars": "^4.7.8", + "peggy": "^3.0.2", + "typeorm": "*" + }, + "peerDependenciesMeta": { + "@langchain/anthropic": { + "optional": true + }, + "@langchain/aws": { + "optional": true + }, + "@langchain/cerebras": { + "optional": true + }, + "@langchain/cohere": { + "optional": true + }, + "@langchain/google-genai": { + "optional": true + }, + "@langchain/google-vertexai": { + "optional": true + }, + "@langchain/google-vertexai-web": { + "optional": true + }, + "@langchain/groq": { + "optional": true + }, + "@langchain/mistralai": { + "optional": true + }, + "@langchain/ollama": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "peggy": { + "optional": true + }, + "typeorm": { + "optional": true + } + } + }, + "node_modules/langsmith": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.2.14.tgz", + "integrity": "sha512-ClAuAgSf3m9miMYotLEaZKQyKdaWlfjhebCuYco8bc6g72dU2VwTg31Bv4YINBq7EH2i1cMwbOiJxbOXPqjGig==", + "license": "MIT", + "dependencies": { + "@types/uuid": "^10.0.0", + "commander": "^10.0.1", + "p-queue": "^6.6.2", + "p-retry": "4", + "semver": "^7.6.3", + "uuid": "^10.0.0" + }, + "peerDependencies": { + "openai": "*" + }, + "peerDependenciesMeta": { + "openai": { + "optional": true + } + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/openai": { + "version": "4.77.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.77.3.tgz", + "integrity": "sha512-wLDy4+KWHz31HRFMW2+9KQuVuT2QWhs0z94w1Gm1h2Ut9vIHr9/rHZggbykZEfyiaJRVgw8ZS9K6AylDWzvPYw==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.70", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.70.tgz", + "integrity": "sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tiny-async-pool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-2.1.0.tgz", + "integrity": "sha512-ltAHPh/9k0STRQqaoUX52NH4ZQYAJz24ZAEwf1Zm+HYg3l9OXTWeqWKyYsHu40wF/F0rxd2N2bk5sLvX2qlSvg==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zod": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz", + "integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/examples/authorization-for-rag/langgraph-stategraph/package.json b/examples/authorization-for-rag/langgraph-stategraph/package.json new file mode 100644 index 0000000..924ff6a --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/package.json @@ -0,0 +1,29 @@ +{ + "name": "auth0-langgraph-state-rag-js", + "version": "0.0.0", + "description": "Demonstrates the usage of the Okta FGA with LangChain to query documents with permission checks.", + "x-type": "module", + "main": "index.js", + "author": { + "name": "Auth0 Inc.", + "url": "https://auth0.com" + }, + "license": "Apache-2.0", + "scripts": { + "start": "npx tsx index.ts", + "fga:init": "npx tsx ./scripts/fga-init.ts" + }, + "dependencies": { + "@auth0/ai-langchain": "*", + "@langchain/core": "^0.3.33", + "@langchain/langgraph": "^0.2.41", + "@langchain/openai": "^0.3.17", + "@openfga/sdk": "^0.8.0", + "dotenv": "^16.4.7", + "langchain": "^0.3.12", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/node": "^22.10.7" + } +} diff --git a/examples/authorization-for-rag/langgraph-stategraph/scripts/fga-init.ts b/examples/authorization-for-rag/langgraph-stategraph/scripts/fga-init.ts new file mode 100644 index 0000000..6bfa232 --- /dev/null +++ b/examples/authorization-for-rag/langgraph-stategraph/scripts/fga-init.ts @@ -0,0 +1,66 @@ +import "dotenv/config"; + +import { CredentialsMethod, OpenFgaClient } from "@openfga/sdk"; + +/** + * Initializes the OpenFgaClient, writes an authorization model, and configures pre-defined tuples. + * + * This function performs the following steps: + * 1. Creates an instance of OpenFgaClient with the necessary configuration. + * 2. Writes an authorization model with specified schema version and type definitions. + * 3. Configures pre-defined tuples using the newly created authorization model. + */ +async function main() { + const fgaClient = new OpenFgaClient({ + apiUrl: process.env.FGA_API_URL || "https://api.us1.fga.dev", + storeId: process.env.FGA_STORE_ID!, + credentials: { + method: CredentialsMethod.ClientCredentials, + config: { + apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER || "auth.fga.dev", + apiAudience: process.env.FGA_API_AUDIENCE || "https://api.us1.fga.dev/", + clientId: process.env.FGA_CLIENT_ID!, + clientSecret: process.env.FGA_CLIENT_SECRET!, + }, + }, + }); + + // 01. WRITE MODEL + const model = await fgaClient.writeAuthorizationModel({ + schema_version: "1.1", + type_definitions: [ + { type: "user" }, + { + type: "doc", + relations: { owner: { this: {} }, viewer: { this: {} } }, + metadata: { + relations: { + owner: { directly_related_user_types: [{ type: "user" }] }, + viewer: { + directly_related_user_types: [ + { type: "user" }, + { type: "user", wildcard: {} }, + ], + }, + }, + }, + }, + ], + }); + + console.log("NEW MODEL ID: ", model.authorization_model_id); + + // 02. CONFIGURE PRE-DEFINED TUPLES + await fgaClient.write( + { + writes: [ + { user: "user:*", relation: "viewer", object: "doc:public-doc" }, + ], + }, + { + authorizationModelId: model.authorization_model_id, + } + ); +} + +main().catch(console.error); diff --git a/examples/authorization-for-rag/llamaindex/.env.example b/examples/authorization-for-rag/llamaindex/.env.example new file mode 100644 index 0000000..b5f2690 --- /dev/null +++ b/examples/authorization-for-rag/llamaindex/.env.example @@ -0,0 +1,11 @@ +# OpenAI +OPENAI_API_KEY= + + +# Okta FGA +FGA_STORE_ID= +FGA_CLIENT_ID= +FGA_CLIENT_SECRET= +# Required only for non-US regions +FGA_API_URL=https://api.xxx.fga.dev +FGA_API_AUDIENCE=https://api.xxx.fga.dev/ diff --git a/examples/authorization-for-rag/llamaindex/README.md b/examples/authorization-for-rag/llamaindex/README.md index dad6634..edc3f84 100644 --- a/examples/authorization-for-rag/llamaindex/README.md +++ b/examples/authorization-for-rag/llamaindex/README.md @@ -21,9 +21,8 @@ This example demonstrates how to combine [LlamaIndex](https://ts.llamaindex.ai/) FGA_STORE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx FGA_CLIENT_SECRET=xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx - # Optional + # Required only for non-US regions FGA_API_URL=https://api.xxx.fga.dev - FGA_API_TOKEN_ISSUER=auth.fga.dev FGA_API_AUDIENCE=https://api.xxx.fga.dev/ ``` diff --git a/package-lock.json b/package-lock.json index 64979af..2712b6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,11 @@ } }, "examples/authorization-for-rag/genkit": { + "name": "genkit-retrievers-with-fga", "version": "0.0.0", "license": "Apache-2.0", "dependencies": { + "@auth0/ai-genkit": "*", "@genkit-ai/dev-local-vectorstore": "^0.9.12", "@openfga/sdk": "^0.8.0", "dotenv": "^16.4.5", @@ -25,20 +27,376 @@ } }, "examples/authorization-for-rag/langchain": { + "name": "langchain-retrievers-with-fga", "version": "0.0.0", "license": "Apache-2.0", "dependencies": { "@auth0/ai-langchain": "*", - "@langchain/openai": "^0.3.16", + "@langchain/openai": "^0.3.17", "@openfga/sdk": "^0.8.0", - "dotenv": "16.4.7", - "langchain": "^0.3.11" + "dotenv": "^16.4.7", + "langchain": "^0.3.12" }, "devDependencies": { - "@types/node": "^22.10.6" + "@types/node": "^22.10.7" + } + }, + "examples/authorization-for-rag/langchain/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "examples/authorization-for-rag/langchain/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "examples/authorization-for-rag/langchain/node_modules/langchain": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.3.12.tgz", + "integrity": "sha512-BjdQ/f/66W05L8nRgX74bf5QvJIphpg+K5ZTmQwGE8Gk3umtzHp8T4YIRFYjvTxU4XQrGXOgWk1Y9rk5uBbjKA==", + "license": "MIT", + "dependencies": { + "@langchain/openai": ">=0.1.0 <0.4.0", + "@langchain/textsplitters": ">=0.0.0 <0.2.0", + "js-tiktoken": "^1.0.12", + "js-yaml": "^4.1.0", + "jsonpointer": "^5.0.1", + "langsmith": ">=0.2.8 <0.4.0", + "openapi-types": "^12.1.3", + "p-retry": "4", + "uuid": "^10.0.0", + "yaml": "^2.2.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/anthropic": "*", + "@langchain/aws": "*", + "@langchain/cerebras": "*", + "@langchain/cohere": "*", + "@langchain/core": ">=0.2.21 <0.4.0", + "@langchain/google-genai": "*", + "@langchain/google-vertexai": "*", + "@langchain/google-vertexai-web": "*", + "@langchain/groq": "*", + "@langchain/mistralai": "*", + "@langchain/ollama": "*", + "axios": "*", + "cheerio": "*", + "handlebars": "^4.7.8", + "peggy": "^3.0.2", + "typeorm": "*" + }, + "peerDependenciesMeta": { + "@langchain/anthropic": { + "optional": true + }, + "@langchain/aws": { + "optional": true + }, + "@langchain/cerebras": { + "optional": true + }, + "@langchain/cohere": { + "optional": true + }, + "@langchain/google-genai": { + "optional": true + }, + "@langchain/google-vertexai": { + "optional": true + }, + "@langchain/google-vertexai-web": { + "optional": true + }, + "@langchain/groq": { + "optional": true + }, + "@langchain/mistralai": { + "optional": true + }, + "@langchain/ollama": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "peggy": { + "optional": true + }, + "typeorm": { + "optional": true + } + } + }, + "examples/authorization-for-rag/langgraph-agentic": { + "name": "auth0-langgraph-agentic-rag-js", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "@auth0/ai-langchain": "*", + "@langchain/core": "^0.3.33", + "@langchain/langgraph": "^0.2.41", + "@langchain/openai": "^0.3.17", + "@openfga/sdk": "^0.8.0", + "dotenv": "^16.4.7", + "langchain": "^0.3.12", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/node": "^22.10.7" + } + }, + "examples/authorization-for-rag/langgraph-agentic/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "examples/authorization-for-rag/langgraph-agentic/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "examples/authorization-for-rag/langgraph-agentic/node_modules/langchain": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.3.12.tgz", + "integrity": "sha512-BjdQ/f/66W05L8nRgX74bf5QvJIphpg+K5ZTmQwGE8Gk3umtzHp8T4YIRFYjvTxU4XQrGXOgWk1Y9rk5uBbjKA==", + "license": "MIT", + "dependencies": { + "@langchain/openai": ">=0.1.0 <0.4.0", + "@langchain/textsplitters": ">=0.0.0 <0.2.0", + "js-tiktoken": "^1.0.12", + "js-yaml": "^4.1.0", + "jsonpointer": "^5.0.1", + "langsmith": ">=0.2.8 <0.4.0", + "openapi-types": "^12.1.3", + "p-retry": "4", + "uuid": "^10.0.0", + "yaml": "^2.2.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/anthropic": "*", + "@langchain/aws": "*", + "@langchain/cerebras": "*", + "@langchain/cohere": "*", + "@langchain/core": ">=0.2.21 <0.4.0", + "@langchain/google-genai": "*", + "@langchain/google-vertexai": "*", + "@langchain/google-vertexai-web": "*", + "@langchain/groq": "*", + "@langchain/mistralai": "*", + "@langchain/ollama": "*", + "axios": "*", + "cheerio": "*", + "handlebars": "^4.7.8", + "peggy": "^3.0.2", + "typeorm": "*" + }, + "peerDependenciesMeta": { + "@langchain/anthropic": { + "optional": true + }, + "@langchain/aws": { + "optional": true + }, + "@langchain/cerebras": { + "optional": true + }, + "@langchain/cohere": { + "optional": true + }, + "@langchain/google-genai": { + "optional": true + }, + "@langchain/google-vertexai": { + "optional": true + }, + "@langchain/google-vertexai-web": { + "optional": true + }, + "@langchain/groq": { + "optional": true + }, + "@langchain/mistralai": { + "optional": true + }, + "@langchain/ollama": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "peggy": { + "optional": true + }, + "typeorm": { + "optional": true + } + } + }, + "examples/authorization-for-rag/langgraph-stategraph": { + "name": "auth0-langgraph-state-rag-js", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "@auth0/ai-langchain": "*", + "@langchain/core": "^0.3.33", + "@langchain/langgraph": "^0.2.41", + "@langchain/openai": "^0.3.17", + "@openfga/sdk": "^0.8.0", + "dotenv": "^16.4.7", + "langchain": "^0.3.12", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/node": "^22.10.7" + } + }, + "examples/authorization-for-rag/langgraph-stategraph/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "examples/authorization-for-rag/langgraph-stategraph/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "examples/authorization-for-rag/langgraph-stategraph/node_modules/langchain": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.3.12.tgz", + "integrity": "sha512-BjdQ/f/66W05L8nRgX74bf5QvJIphpg+K5ZTmQwGE8Gk3umtzHp8T4YIRFYjvTxU4XQrGXOgWk1Y9rk5uBbjKA==", + "license": "MIT", + "dependencies": { + "@langchain/openai": ">=0.1.0 <0.4.0", + "@langchain/textsplitters": ">=0.0.0 <0.2.0", + "js-tiktoken": "^1.0.12", + "js-yaml": "^4.1.0", + "jsonpointer": "^5.0.1", + "langsmith": ">=0.2.8 <0.4.0", + "openapi-types": "^12.1.3", + "p-retry": "4", + "uuid": "^10.0.0", + "yaml": "^2.2.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/anthropic": "*", + "@langchain/aws": "*", + "@langchain/cerebras": "*", + "@langchain/cohere": "*", + "@langchain/core": ">=0.2.21 <0.4.0", + "@langchain/google-genai": "*", + "@langchain/google-vertexai": "*", + "@langchain/google-vertexai-web": "*", + "@langchain/groq": "*", + "@langchain/mistralai": "*", + "@langchain/ollama": "*", + "axios": "*", + "cheerio": "*", + "handlebars": "^4.7.8", + "peggy": "^3.0.2", + "typeorm": "*" + }, + "peerDependenciesMeta": { + "@langchain/anthropic": { + "optional": true + }, + "@langchain/aws": { + "optional": true + }, + "@langchain/cerebras": { + "optional": true + }, + "@langchain/cohere": { + "optional": true + }, + "@langchain/google-genai": { + "optional": true + }, + "@langchain/google-vertexai": { + "optional": true + }, + "@langchain/google-vertexai-web": { + "optional": true + }, + "@langchain/groq": { + "optional": true + }, + "@langchain/mistralai": { + "optional": true + }, + "@langchain/ollama": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "peggy": { + "optional": true + }, + "typeorm": { + "optional": true + } } }, "examples/authorization-for-rag/llamaindex": { + "name": "llamaindex-retrievers-with-fga", "version": "0.0.0", "license": "Apache-2.0", "dependencies": { @@ -1363,8 +1721,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.0.tgz", "integrity": "sha512-/vYKi/qMxwNsuIJ9WGWwM2rflY40ZenK3Kh4uR5vB9/Nz12Y7IUN/Xf4wDA7vzPfw0VNh3b/jz4+MjcVgARKJg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@colors/colors": { "version": "1.6.0", @@ -2850,18 +3207,17 @@ } }, "node_modules/@langchain/core": { - "version": "0.3.30", - "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.30.tgz", - "integrity": "sha512-HFUpjJ6FkPSSeLKzCLKxba4VN1DKnrXRmjaWHDb5KUyE9DZrqak3Sh6k2dkzXDJIcdd/uNeeQGFyQnubVEMkPw==", + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.33.tgz", + "integrity": "sha512-gIszaRKWmP1HEgOhJLJaMiTMH8U3W9hG6raWihwpCTb0Ns7owjrmaqmgMa9h3W4/0xriaKfrfFBd6tepKsfxZA==", "license": "MIT", - "peer": true, "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", - "langsmith": "^0.2.8", + "langsmith": ">=0.2.8 <0.4.0", "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", @@ -2873,6 +3229,64 @@ "node": ">=18" } }, + "node_modules/@langchain/langgraph": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-0.2.41.tgz", + "integrity": "sha512-NeNizWP4k9voEwJxuFtfopF02Lx1isuEsdZKYCN3ueJpOnkVg0iGx8woPBsQpYcrWcySkIt3zOkgtUsrNHqo3g==", + "license": "MIT", + "dependencies": { + "@langchain/langgraph-checkpoint": "~0.0.13", + "@langchain/langgraph-sdk": "~0.0.32", + "uuid": "^10.0.0", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.36 <0.3.0 || >=0.3.9 < 0.4.0" + } + }, + "node_modules/@langchain/langgraph-checkpoint": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.13.tgz", + "integrity": "sha512-amdmBcNT8a9xP2VwcEWxqArng4gtRDcnVyVI4DsQIo1Aaz8e8+hH17zSwrUF3pt1pIYztngIfYnBOim31mtKMg==", + "license": "MIT", + "dependencies": { + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.31 <0.4.0" + } + }, + "node_modules/@langchain/langgraph-sdk": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.36.tgz", + "integrity": "sha512-KkAZM0uXBaMcD/dpGTBppOhbvNX6gz+Y1zFAC898OblegFkSvICrkd0oRQ5Ro/GWK/NAoDymnMUDXeZDdUkSuw==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0" + } + }, + "node_modules/@langchain/langgraph-sdk/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@langchain/openai": { "version": "0.3.17", "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.3.17.tgz", @@ -5629,7 +6043,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/lodash": { @@ -5645,9 +6058,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.6.tgz", - "integrity": "sha512-qNiuwC4ZDAUNcY47xgaSuS92cjf8JbSUoaKS77bmLG1rU7MlATVSiw/IlrjtIyyskXBZ8KkNfjK/P5na7rgXbQ==", + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -6303,7 +6716,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -6412,6 +6824,14 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/auth0-langgraph-agentic-rag-js": { + "resolved": "examples/authorization-for-rag/langgraph-agentic", + "link": true + }, + "node_modules/auth0-langgraph-state-rag-js": { + "resolved": "examples/authorization-for-rag/langgraph-stategraph", + "link": true + }, "node_modules/axios": { "version": "1.7.9", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", @@ -6745,7 +7165,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7393,7 +7812,6 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -10587,7 +11005,6 @@ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", "license": "MIT", - "peer": true, "bin": { "mustache": "bin/mustache" } @@ -13843,7 +14260,8 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { - "langchain": "^0.3.11" + "langchain": "^0.3.11", + "zod": "^3.24.1" }, "devDependencies": { "@types/node": "^22.10.6", diff --git a/packages/ai-langchain/package.json b/packages/ai-langchain/package.json index b733d22..bfd0735 100644 --- a/packages/ai-langchain/package.json +++ b/packages/ai-langchain/package.json @@ -15,7 +15,8 @@ }, "license": "Apache-2.0", "dependencies": { - "langchain": "^0.3.11" + "langchain": "^0.3.11", + "zod": "^3.24.1" }, "peerDependencies": { "@openfga/sdk": "0.8.0" diff --git a/packages/ai-langchain/src/retrievers/fga-retriever.ts b/packages/ai-langchain/src/retrievers/fga-retriever.ts index 9390dc4..0221ef5 100644 --- a/packages/ai-langchain/src/retrievers/fga-retriever.ts +++ b/packages/ai-langchain/src/retrievers/fga-retriever.ts @@ -9,6 +9,8 @@ import { import type { BaseRetrieverInput } from "@langchain/core/retrievers"; import type { CallbackManagerForRetrieverRun } from "@langchain/core/callbacks/manager"; +import { StructuredToolInterface, tool } from "@langchain/core/tools"; +import { z } from "zod"; export type FGARetrieverCheckerFn = ( doc: DocumentInterface> @@ -159,4 +161,22 @@ export class FGARetriever extends BaseRetriever { (d, i) => resultsByObject.get(documentToObject.get(d) || "") === true ); } + + /** + * Converts the FGA retriever into a tool that can be used by a LangGraph agent. + * @returns StructuredToolInterface. + */ + asJoinedStringTool(): StructuredToolInterface { + return tool( + async ({ query }) => { + const documents = await this.retriever.invoke(query); + return documents.map((doc) => doc.pageContent).join("\n\n"); + }, + { + name: "fga-retriever-tool", + description: "Returns the filtered documents page content as string.", + schema: z.object({ query: z.string() }), + } + ); + } }