├── README.md └── examples ├── langman-simple ├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── biome.json ├── bun.lockb ├── package.json ├── src │ ├── graph.ts │ ├── main.ts │ ├── model.ts │ ├── server.ts │ ├── state.ts │ └── tools.ts └── tsconfig.json └── langman-webhook ├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── biome.json ├── bun.lockb ├── package.json ├── src ├── graph.ts ├── main.ts ├── model.ts ├── server.ts ├── state.ts └── tools.ts └── tsconfig.json /README.md: -------------------------------------------------------------------------------- 1 | # LangMan Examples (Payman + LangGraph AI Agent) 2 | 3 | This repository contains various examples demonstrating how AI agents can interact with and pay humans to complete tasks using LangGraph for AI Agent development and Payman for handling payments and task creation. 4 | 5 | ## Overview 6 | 7 | The `LangMan Examples` repository provides multiple examples to help developers understand how to integrate LangGraph and Payman. Each example showcases a different use case or integration pattern. 8 | 9 | ## Examples 10 | 11 | - **[LangMan-Simple](examples/langman-simple/)**: Demonstrates a basic AI agent setup using LangGraph and Payman to automate task creation and payment processes. 12 | - **[LangMan-Webhook](examples/langman-webhook/)**: Shows how to integrate webhooks for asynchronous updates to the AI once human completes task and is paid. 13 | - _(More examples will be added in the future)_ 14 | 15 | ## Features 16 | 17 | - Create AI-driven workflows using LangGraph 18 | - Pay humans for services and tasks via Payman 19 | - Automate task creation, payment processing, and AI-human collaboration 20 | - Provide multiple examples to illustrate different integration scenarios 21 | 22 | ## Prerequisites 23 | 24 | Before using any of the examples, ensure you have the following installed: 25 | 26 | - [Bun](https://bun.sh/) - Fast all-in-one JavaScript runtime 27 | 28 | Additionally, you'll need: 29 | 30 | - OpenAI API key 31 | - Payman API key 32 | 33 | ## Getting Started 34 | 35 | 1. **Clone the repository:** 36 | 37 | ```bash 38 | git clone https://github.com/PaymanAI/langman-examples.git 39 | ``` 40 | 41 | ```bash 42 | cd langman-examples 43 | ``` 44 | 45 | 2. **Choose an example to get started:** 46 | Navigate to the desired example directory, such as `examples/langman-simple`. 47 | 48 | ```bash 49 | cd examples/langman-simple 50 | ``` 51 | 52 | 3. **Install dependencies:** 53 | 54 | ```bash 55 | bun install 56 | ``` 57 | 58 | 4. **Set up environment variables:** 59 | - Copy `.env.example` to `.env` 60 | - Fill in your OpenAI and Payman API keys in the `.env` file 61 | 62 | ## Example-Specific Instructions 63 | 64 | Each example has its own README file containing detailed setup instructions and usage guidelines. Please refer to the individual README files for further information: 65 | 66 | - [LangMan-Simple README](examples/langman-simple/README.md) 67 | 68 | ## Repository Structure 69 | 70 | ``` 71 | langman-examples/ 72 | ├── examples/ 73 | │ ├── langman-simple/ 74 | │ │ ├── src/ 75 | │ │ ├── .env.example 76 | │ │ ├── LICENSE 77 | │ │ ├── README.md 78 | │ │ ├── package.json 79 | │ │ └── tsconfig.json 80 | │ ├── langman-webhook/ 81 | │ │ ├── src/ 82 | │ │ ├── .env.example 83 | │ │ ├── LICENSE 84 | │ │ ├── README.md 85 | │ │ ├── package.json 86 | │ │ └── tsconfig.json 87 | ├── .gitignore 88 | ├── README.md 89 | ├── LICENSE 90 | ├── biome.json 91 | └── package.json 92 | ``` 93 | 94 | ## Contributing 95 | 96 | Contributions are welcome! If you would like to add a new example or improve an existing one, please feel free to submit a pull request. 97 | 98 | ## License 99 | 100 | [MIT License](LICENSE) 101 | 102 | ## Acknowledgements 103 | 104 | - [LangGraph](https://github.com/langchain-ai/langgraph) for AI workflow management 105 | - [Payman](https://paymanai.com) for task creation and payment processing 106 | - [OpenAI](https://openai.com) for the language model 107 | 108 | ## Support 109 | 110 | For any questions or issues, please open an issue in the GitHub repository or contact the maintainers directly. 111 | -------------------------------------------------------------------------------- /examples/langman-simple/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY='' 2 | PAYMAN_API_SECRET='' 3 | PAYMAN_DEV_API="https://agent-sandbox.payman.ai/api/tasks" -------------------------------------------------------------------------------- /examples/langman-simple/.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | package-lock.json 62 | 63 | # Snowpack dependency directory (https://snowpack.dev/) 64 | 65 | web_modules/ 66 | 67 | # TypeScript cache 68 | 69 | *.tsbuildinfo 70 | 71 | # Optional npm cache directory 72 | 73 | .npm 74 | 75 | # Optional eslint cache 76 | 77 | .eslintcache 78 | 79 | # Optional stylelint cache 80 | 81 | .stylelintcache 82 | 83 | # Microbundle cache 84 | 85 | .rpt2_cache/ 86 | .rts2_cache_cjs/ 87 | .rts2_cache_es/ 88 | .rts2_cache_umd/ 89 | 90 | # Optional REPL history 91 | 92 | .node_repl_history 93 | 94 | # Output of 'npm pack' 95 | 96 | *.tgz 97 | 98 | # Yarn Integrity file 99 | 100 | .yarn-integrity 101 | 102 | # dotenv environment variable files 103 | 104 | .env 105 | .env.development.local 106 | .env.test.local 107 | .env.production.local 108 | .env.local 109 | 110 | # parcel-bundler cache (https://parceljs.org/) 111 | 112 | .parcel-cache 113 | 114 | # Next.js build output 115 | 116 | .next 117 | out 118 | 119 | # Nuxt.js build / generate output 120 | 121 | .nuxt 122 | dist 123 | 124 | # Gatsby files 125 | 126 | # Comment in the public line in if your project uses Gatsby and not Next.js 127 | 128 | # https://nextjs.org/blog/next-9-1#public-directory-support 129 | 130 | # public 131 | 132 | # vuepress build output 133 | 134 | .vuepress/dist 135 | 136 | # vuepress v2.x temp and cache directory 137 | 138 | .temp 139 | 140 | # Docusaurus cache and generated files 141 | 142 | .docusaurus 143 | 144 | # Serverless directories 145 | 146 | .serverless/ 147 | 148 | # FuseBox cache 149 | 150 | .fusebox/ 151 | 152 | # DynamoDB Local files 153 | 154 | .dynamodb/ 155 | 156 | # TernJS port file 157 | 158 | .tern-port 159 | 160 | # Stores VSCode versions used for testing VSCode extensions 161 | 162 | .vscode-test 163 | 164 | # yarn v2 165 | 166 | .yarn/cache 167 | .yarn/unplugged 168 | .yarn/build-state.yml 169 | .yarn/install-state.gz 170 | .pnp.* 171 | 172 | # IntelliJ based IDEs 173 | .idea 174 | 175 | # Finder (MacOS) folder config 176 | .DS_Store 177 | -------------------------------------------------------------------------------- /examples/langman-simple/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Payman AI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/langman-simple/README.md: -------------------------------------------------------------------------------- 1 | # LangMan-Simple (Payman + Langgraph AI Agent) 2 | 3 | LangMan-Simple is an AI agent that demonstrates how an AI can interact with and pay humans to complete tasks. It combines the power of Langgraph for abstracting workflows as programmatic AI Agents and Payman for handling payments and task creation. 4 | 5 | ## Features 6 | 7 | - Create AI-driven workflows using Langgraph 8 | - Pay humans for things the AI needs using Payman 9 | - Automate task creation and payment processes 10 | - Demonstrate AI-human collaboration in a simple, understandable way 11 | 12 | ## Prerequisites 13 | 14 | Before you begin, ensure you have the following installed: 15 | 16 | - [Bun](https://bun.sh/) - Fast all-in-one JavaScript runtime 17 | 18 | You'll also need: 19 | 20 | - OpenAI API key 21 | - Payman API key 22 | 23 | ## Installation 24 | 25 | 1. Clone the repository: 26 | 27 | ``` 28 | git clone https://github.com/PaymanAI/langman-simple.git 29 | ``` 30 | 31 | ``` 32 | cd langman-simple 33 | ``` 34 | 35 | 2. Install dependencies: 36 | 37 | ``` 38 | bun install 39 | ``` 40 | 41 | 3. Set up environment variables: 42 | 43 | - Copy `.env.example` to `.env` 44 | - Fill in your OpenAI and Payman API keys in the `.env` file 45 | 46 | ## Configuration 47 | 48 | To use Payman: 49 | 50 | 1. Go to [app.paymanai.com](https://app.paymanai.com) 51 | 2. Create a wallet 52 | 3. Add funds to your wallet 53 | 4. Generate an API key 54 | 5. Add the API key to your `.env` file 55 | 56 | ## Quick Start 57 | 58 | To quickly get started and create your first task: 59 | 60 | 1. Start the development server: 61 | 62 | ``` 63 | bun dev 64 | ``` 65 | 66 | 2. In a new terminal window, use curl to initiate a new conversation and create a task: 67 | 68 | ``` 69 | curl -X POST http://localhost:3000/start 70 | ``` 71 | 72 | This will start a new conversation thread and instruct the AI to create a task using the Payman API. The response will include a `thread_id` which you can use for further interactions. 73 | 74 | 3. (Optional) To continue the conversation or check the status, use: 75 | 76 | ``` 77 | curl -X GET http://localhost:3000/message/{thread_id} 78 | ``` 79 | 80 | Replace `{thread_id}` with the ID received from the previous step. 81 | 82 | ## Usage 83 | 84 | To run the project in development mode: 85 | 86 | ``` 87 | bun dev 88 | ``` 89 | 90 | The server will start, and you can interact with the AI agent through the defined endpoints. 91 | 92 | ## API Endpoints 93 | 94 | - `POST /start`: Initiates a new conversation thread with the AI agent 95 | - `POST /message/:id`: Sends a message to an existing conversation thread 96 | - `GET /message/:id`: Retrieves the current state of a conversation thread 97 | 98 | ## Project Structure 99 | 100 | - `server.ts`: Main server file with API endpoints 101 | - `graph.ts`: Defines the Langgraph workflow 102 | - `tools.ts`: Contains the Payman task creation tool 103 | - `model.ts`: Configures the language model (currently using OpenAI, feel free to use others like Anthropics, etc.) 104 | 105 | ## Contributing 106 | 107 | Contributions are welcome! Please feel free to submit a Pull Request. 108 | 109 | ## License 110 | 111 | [MIT License](LICENSE) 112 | 113 | ## Acknowledgements 114 | 115 | - [Langgraph](https://github.com/langchain-ai/langgraph) for AI workflow management 116 | - [Payman](https://paymanai.com) for task creation and payment processing 117 | - [OpenAI](https://openai.com) for the language model 118 | 119 | ## Support 120 | 121 | For any questions or issues, please open an issue in the GitHub repository or contact the maintainers directly. 122 | -------------------------------------------------------------------------------- /examples/langman-simple/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", 3 | "files": { 4 | "include": ["*.ts", "*.js"] 5 | }, 6 | "formatter": { 7 | "enabled": true, 8 | "formatWithErrors": true, 9 | "indentStyle": "space", 10 | "lineWidth": 100 11 | }, 12 | "javascript": { 13 | "formatter": { 14 | "arrowParentheses": "asNeeded", 15 | "jsxQuoteStyle": "single", 16 | "lineWidth": 80, 17 | "quoteStyle": "single", 18 | "semicolons": "asNeeded" 19 | }, 20 | "parser": { 21 | "unsafeParameterDecoratorsEnabled": true 22 | } 23 | }, 24 | "linter": { 25 | "enabled": true, 26 | "rules": { 27 | "complexity": { 28 | "noExcessiveCognitiveComplexity": { 29 | "level": "warn", 30 | "options": { 31 | "maxAllowedComplexity": 15 32 | } 33 | }, 34 | "noUselessSwitchCase": "error", 35 | "noVoid": "error", 36 | "useLiteralKeys": "error", 37 | "useSimplifiedLogicExpression": "error" 38 | }, 39 | "correctness": { 40 | "noNewSymbol": "error", 41 | "noUnusedImports": "error", 42 | "noUnusedVariables": "error", 43 | "useHookAtTopLevel": "error" 44 | }, 45 | "nursery": { 46 | "all": true 47 | }, 48 | "recommended": true, 49 | "style": { 50 | "noImplicitBoolean": "error", 51 | "noNamespace": "error", 52 | "noNegationElse": "error", 53 | "noNonNullAssertion": "error", 54 | "noShoutyConstants": "error", 55 | "useCollapsedElseIf": "error", 56 | "useShorthandArrayType": "error", 57 | "useShorthandAssign": "error" 58 | }, 59 | "suspicious": { 60 | "noApproximativeNumericConstant": "error", 61 | "noControlCharactersInRegex": "error", 62 | "noMisrefactoredShorthandAssign": "error" 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/langman-simple/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaymanAI/langman-examples/d82a450bbcb1d745d544a91fda80984c4ea18b76/examples/langman-simple/bun.lockb -------------------------------------------------------------------------------- /examples/langman-simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agent-clone-ts-langgraph", 3 | "module": "src", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "bun --watch src/main.ts", 7 | "lint": "biome check .", 8 | "lint:fix": "biome check --fix ." 9 | }, 10 | "devDependencies": { 11 | "@biomejs/biome": "1.9.3", 12 | "@types/bun": "latest" 13 | }, 14 | "peerDependencies": { 15 | "typescript": "^5.0.0" 16 | }, 17 | "dependencies": { 18 | "@langchain/core": "^0.3.6", 19 | "@langchain/langgraph": "^0.2.11", 20 | "axios": "^1.7.7", 21 | "elysia": "^1.1.17", 22 | "paymanai": "^1.0.0", 23 | "uuid": "^10.0.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/langman-simple/src/graph.ts: -------------------------------------------------------------------------------- 1 | import { StateGraph } from "@langchain/langgraph"; 2 | import StateAnnotation from "./state"; 3 | import { model } from "./model"; 4 | import { MemorySaver } from "@langchain/langgraph"; 5 | import { AIMessage } from "@langchain/core/messages"; 6 | import { createTaskTool } from "./tools"; 7 | import { ToolNode } from "@langchain/langgraph/prebuilt"; 8 | 9 | const tools = [createTaskTool]; 10 | const toolNodeForGraph = new ToolNode(tools); 11 | 12 | async function callModel(state: typeof StateAnnotation.State) { 13 | const messages = state.messages; 14 | const response = await model.invoke(messages); 15 | 16 | // We return a list, because this will get added to the existing list 17 | return { messages: [response] }; 18 | } 19 | 20 | function checkToolCall(state: typeof StateAnnotation.State) { 21 | const messages = state.messages; 22 | const lastMessage = messages[messages.length - 1] as AIMessage; 23 | // If the LLM makes a tool call, then we route to the "tools" node 24 | if (lastMessage.tool_calls?.length) { 25 | return "tools"; 26 | } 27 | // Otherwise, we stop (reply to the user) 28 | return "__end__"; 29 | } 30 | 31 | const workflow = new StateGraph(StateAnnotation) 32 | .addNode("agent", callModel) 33 | .addNode("tools", toolNodeForGraph) 34 | .addEdge("__start__", "agent") 35 | .addConditionalEdges("agent", checkToolCall, ["tools", "__end__"]) 36 | .addEdge("tools", "agent"); 37 | 38 | const checkpointer = new MemorySaver(); 39 | 40 | export const app = workflow.compile({ checkpointer }); 41 | -------------------------------------------------------------------------------- /examples/langman-simple/src/main.ts: -------------------------------------------------------------------------------- 1 | import { server } from './server' 2 | 3 | server.listen(3000, () => console.log('Starting server on port 3000')) 4 | -------------------------------------------------------------------------------- /examples/langman-simple/src/model.ts: -------------------------------------------------------------------------------- 1 | import { createTaskTool } from "./tools"; 2 | import { ChatOpenAI } from "@langchain/openai"; 3 | 4 | const tools = [createTaskTool]; 5 | 6 | const OPENAI_API_KEY = process.env.OPENAI_API_KEY; 7 | 8 | export const model = new ChatOpenAI({ 9 | model: "gpt-4o", 10 | openAIApiKey: OPENAI_API_KEY, 11 | temperature: 0.7, 12 | }).bindTools(tools); 13 | -------------------------------------------------------------------------------- /examples/langman-simple/src/server.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, t } from "elysia"; 2 | import { v4 as uuidv4 } from "uuid"; 3 | import { app } from "./graph"; 4 | import { HumanMessage } from "@langchain/core/messages"; 5 | 6 | export const server = new Elysia() 7 | .post("/start", async () => { 8 | const thread_id = uuidv4(); 9 | const result = await app.invoke( 10 | { 11 | messages: [ 12 | new HumanMessage( 13 | "Get Tyllen (tyllen@paymanai.com) to plan an event for me. It's for 50 people and I want it to be a surprise party. I want it to be at a restaurant and I want to spend $50. I want it to be on a Saturday night. Make a made up itenerary for him and have him do it for us. Go for it!" 14 | ), 15 | ], 16 | }, 17 | { configurable: { thread_id } } 18 | ); 19 | 20 | return { 21 | state: result, 22 | thread_id, 23 | }; 24 | }) 25 | .post( 26 | "/message/:id", 27 | async ({ body: { message }, params: { id } }) => { 28 | const config = { configurable: { thread_id: id } }; 29 | await app.updateState(config, { messages: [message] }); //add `asNode: "wait_for_input"` to update as a graph node 30 | 31 | return { 32 | state: await app.getState(config), 33 | id, 34 | }; 35 | }, 36 | { 37 | body: t.Object({ 38 | message: t.String(), 39 | }), 40 | } 41 | ) 42 | .get("/message/:id", async ({ params: { id } }) => { 43 | const config = { configurable: { thread_id: id } }; 44 | return { 45 | state: await app.getState(config), 46 | id, 47 | }; 48 | }); 49 | -------------------------------------------------------------------------------- /examples/langman-simple/src/state.ts: -------------------------------------------------------------------------------- 1 | import type { BaseMessage } from "@langchain/core/messages"; 2 | import { Annotation } from "@langchain/langgraph"; 3 | 4 | const StateAnnotation = Annotation.Root({ 5 | messages: Annotation({ 6 | reducer: (x, y): BaseMessage[] => x.concat(y), 7 | }), 8 | }); 9 | 10 | export default StateAnnotation; 11 | -------------------------------------------------------------------------------- /examples/langman-simple/src/tools.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { z } from "zod"; 3 | import { tool } from "@langchain/core/tools"; 4 | 5 | // Define the task creation tool 6 | export const createTaskTool = tool( 7 | async ({ title, description, email }) => { 8 | const headers = { 9 | "x-payman-api-secret": process.env.PAYMAN_API_SECRET, // Environment variable for API secret 10 | "Content-Type": "application/json", 11 | Accept: "application/vnd.payman.v1+json", 12 | }; 13 | 14 | const payload = { 15 | title: title, // Task title (e.g., drink name) 16 | description: description, // Task description (e.g., how to make the drink) 17 | payout: 5000, // $50 payout in cents 18 | inviteEmails: [email], // List of emails to invite to complete the task 19 | }; 20 | 21 | try { 22 | // Choose between sandbox or live environment based on environment variable 23 | const apiUrl: any = process.env.PAYMAN_DEV_API; 24 | 25 | // Make the API request 26 | const response = await axios.post(apiUrl, payload, { headers }); 27 | 28 | // Return the response content upon success 29 | return `Task created successfully: ${response.data.title}`; 30 | } catch (error: any) { 31 | // Type assertion for error 32 | // Handle errors (HTTP errors or general exceptions) 33 | if (error.response) { 34 | return `HTTP Error: ${error.response.status} - ${error.response.data.errorMessage}`; 35 | } else { 36 | return `Error: ${error.data}`; 37 | } 38 | } 39 | }, 40 | { 41 | name: "createTask", 42 | description: 43 | "Create a new task on the Payman platform with a title, description, and invited email.", 44 | schema: z.object({ 45 | title: z 46 | .string() 47 | .describe( 48 | "The title of the task. Make it clear, concise, and to the point." 49 | ), 50 | description: z 51 | .string() 52 | .describe( 53 | "The description of the task. Be as detailed as possible as the human will use this to complete the task." 54 | ), 55 | email: z 56 | .string() 57 | .email() 58 | .describe("The email of the person to invite to complete the task."), 59 | }), 60 | } 61 | ); 62 | -------------------------------------------------------------------------------- /examples/langman-simple/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | "paths": { 11 | "@/*": [ 12 | "./src/*" 13 | ] 14 | }, 15 | 16 | // Bundler mode 17 | "moduleResolution": "bundler", 18 | "allowImportingTsExtensions": true, 19 | "verbatimModuleSyntax": true, 20 | "noEmit": true, 21 | 22 | // Best practices 23 | "strict": true, 24 | "skipLibCheck": true, 25 | "noFallthroughCasesInSwitch": true, 26 | 27 | // Some stricter flags (disabled by default) 28 | "noUnusedLocals": false, 29 | "noUnusedParameters": false, 30 | "noPropertyAccessFromIndexSignature": false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/langman-webhook/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY='' 2 | PAYMAN_API_SECRET='' 3 | PAYMAN_DEV_API="https://agent-sandbox.payman.ai/api/tasks" -------------------------------------------------------------------------------- /examples/langman-webhook/.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | package-lock.json 62 | 63 | # Snowpack dependency directory (https://snowpack.dev/) 64 | 65 | web_modules/ 66 | 67 | # TypeScript cache 68 | 69 | *.tsbuildinfo 70 | 71 | # Optional npm cache directory 72 | 73 | .npm 74 | 75 | # Optional eslint cache 76 | 77 | .eslintcache 78 | 79 | # Optional stylelint cache 80 | 81 | .stylelintcache 82 | 83 | # Microbundle cache 84 | 85 | .rpt2_cache/ 86 | .rts2_cache_cjs/ 87 | .rts2_cache_es/ 88 | .rts2_cache_umd/ 89 | 90 | # Optional REPL history 91 | 92 | .node_repl_history 93 | 94 | # Output of 'npm pack' 95 | 96 | *.tgz 97 | 98 | # Yarn Integrity file 99 | 100 | .yarn-integrity 101 | 102 | # dotenv environment variable files 103 | 104 | .env 105 | .env.development.local 106 | .env.test.local 107 | .env.production.local 108 | .env.local 109 | 110 | # parcel-bundler cache (https://parceljs.org/) 111 | 112 | .parcel-cache 113 | 114 | # Next.js build output 115 | 116 | .next 117 | out 118 | 119 | # Nuxt.js build / generate output 120 | 121 | .nuxt 122 | dist 123 | 124 | # Gatsby files 125 | 126 | # Comment in the public line in if your project uses Gatsby and not Next.js 127 | 128 | # https://nextjs.org/blog/next-9-1#public-directory-support 129 | 130 | # public 131 | 132 | # vuepress build output 133 | 134 | .vuepress/dist 135 | 136 | # vuepress v2.x temp and cache directory 137 | 138 | .temp 139 | 140 | # Docusaurus cache and generated files 141 | 142 | .docusaurus 143 | 144 | # Serverless directories 145 | 146 | .serverless/ 147 | 148 | # FuseBox cache 149 | 150 | .fusebox/ 151 | 152 | # DynamoDB Local files 153 | 154 | .dynamodb/ 155 | 156 | # TernJS port file 157 | 158 | .tern-port 159 | 160 | # Stores VSCode versions used for testing VSCode extensions 161 | 162 | .vscode-test 163 | 164 | # yarn v2 165 | 166 | .yarn/cache 167 | .yarn/unplugged 168 | .yarn/build-state.yml 169 | .yarn/install-state.gz 170 | .pnp.* 171 | 172 | # IntelliJ based IDEs 173 | .idea 174 | 175 | # Finder (MacOS) folder config 176 | .DS_Store 177 | -------------------------------------------------------------------------------- /examples/langman-webhook/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Payman AI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/langman-webhook/README.md: -------------------------------------------------------------------------------- 1 | # LangMan-Webhook (Payman + Langgraph AI Agent) 2 | 3 | LangMan-Webhook is an AI agent that demonstrates how an AI can interact with and pay humans to complete tasks, incorporating a webhook for task completion feedback. It combines the power of Langgraph for abstracting workflows as programmatic AI Agents and Payman for handling payments and task creation. 4 | 5 | ## Features 6 | 7 | - Create AI-driven workflows using Langgraph 8 | - Pay humans for tasks the AI needs using Payman 9 | - Automate task creation and payment processes 10 | - Use webhooks to receive task completion feedback 11 | 12 | ## Prerequisites 13 | 14 | Before you begin, ensure you have the following installed: 15 | 16 | - [Bun](https://bun.sh/) - Fast all-in-one JavaScript runtime 17 | - [ngrok](https://ngrok.com/) - For exposing your local server to the internet 18 | 19 | You'll also need: 20 | 21 | - OpenAI API key 22 | - Payman API key 23 | 24 | ## Installation 25 | 26 | 1. Clone the repository: 27 | 28 | ``` 29 | git clone https://github.com/PaymanAI/langman-webhook.git 30 | cd langman-webhook 31 | ``` 32 | 33 | 2. Install dependencies: 34 | 35 | ``` 36 | bun install 37 | ``` 38 | 39 | 3. Set up environment variables: 40 | 41 | - Copy `.env.example` to `.env` 42 | - Fill in your OpenAI and Payman API keys in the `.env` file 43 | 44 | ## Configuration 45 | 46 | To use Payman: 47 | 48 | 1. Go to [app.paymanai.com](https://app.paymanai.com) 49 | 2. Create a wallet 50 | 3. Add funds to your wallet 51 | 4. Generate an API key 52 | 5. Add the API key to your `.env` file 53 | 54 | ## Quick Start 55 | 56 | To quickly get started and create your first task: 57 | 58 | 1. Start the development server: 59 | 60 | ``` 61 | bun dev 62 | ``` 63 | 64 | 2. In a new terminal window, start ngrok to expose your local server: 65 | 66 | ``` 67 | ngrok http 3000 68 | ``` 69 | 70 | 3. Copy the ngrok URL (e.g., `https://your-ngrok-url.ngrok.io`) and set it as the webhook URL in your Payman dashboard. 71 | 72 | 4. Open the `server.ts` file and locate the following section: 73 | 74 | ```typescript 75 | new HumanMessage( 76 | "Get Tyllen (tyllen@paymanai.com) to plan an event for me. It's for 50 people and I want it to be a surprise party. I want it to be at a restaurant and I want to spend $50. I want it to be on a Saturday night. Make a made up itinerary for him and have him do it for us. Go for it!" 77 | ); 78 | ``` 79 | 80 | Replace `tyllen@paymanai.com` with your own email address. This ensures that you'll receive the task assignment. 81 | 82 | 5. Use curl to initiate a new conversation and create a task: 83 | 84 | ``` 85 | curl -X POST http://localhost:3000/start 86 | ``` 87 | 88 | This will start a new conversation thread and instruct the AI to create a task using the Payman API. The response will include a `thread_id` which you can use for further interactions. 89 | 90 | 6. Check your email for the task assignment. Complete the task as requested on the Payman platform. 91 | 92 | 7. Once you've completed the task, the webhook will be triggered. You should see console output in your terminal where the server is running, showing the result of the webhook processing. 93 | 94 | 8. (Optional) To continue the conversation or check the status, use: 95 | 96 | ``` 97 | curl -X GET http://localhost:3000/message/{thread_id} 98 | ``` 99 | 100 | Replace `{thread_id}` with the ID received from step 5. 101 | 102 | This process allows you to test the full flow of task creation, assignment, completion, and webhook processing. 103 | 104 | ## Usage 105 | 106 | To run the project in development mode: 107 | 108 | ``` 109 | bun dev 110 | ``` 111 | 112 | The server will start, and you can interact with the AI agent through the defined endpoints. 113 | 114 | ## API Endpoints 115 | 116 | - `POST /start`: Initiates a new conversation thread with the AI agent 117 | - `POST /message/:id`: Sends a message to an existing conversation thread 118 | - `GET /message/:id`: Retrieves the current state of a conversation thread 119 | - `POST /webhook`: Receives webhook notifications from Payman about task completions 120 | 121 | ## Project Structure 122 | 123 | - `server.ts`: Main server file with API endpoints 124 | - `graph.ts`: Defines the Langgraph workflow 125 | - `tools.ts`: Contains the Payman task creation tool 126 | - `model.ts`: Configures the language model (currently using OpenAI, feel free to use others like Anthropic, etc.) 127 | - `state.ts`: Defines the state management for the application 128 | 129 | ## Contributing 130 | 131 | Contributions are welcome! Please feel free to submit a Pull Request. 132 | 133 | ## License 134 | 135 | [MIT License](LICENSE) 136 | 137 | ## Acknowledgements 138 | 139 | - [Langgraph](https://github.com/langchain-ai/langgraph) for AI workflow management 140 | - [Payman](https://paymanai.com) for task creation and payment processing 141 | - [OpenAI](https://openai.com) for the language model 142 | - [ngrok](https://ngrok.com/) for exposing local servers to the internet 143 | 144 | ## Support 145 | 146 | For any questions or issues, please open an issue in the GitHub repository or contact the maintainers directly. 147 | -------------------------------------------------------------------------------- /examples/langman-webhook/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", 3 | "files": { 4 | "include": ["*.ts", "*.js"] 5 | }, 6 | "formatter": { 7 | "enabled": true, 8 | "formatWithErrors": true, 9 | "indentStyle": "space", 10 | "lineWidth": 100 11 | }, 12 | "javascript": { 13 | "formatter": { 14 | "arrowParentheses": "asNeeded", 15 | "jsxQuoteStyle": "single", 16 | "lineWidth": 80, 17 | "quoteStyle": "single", 18 | "semicolons": "asNeeded" 19 | }, 20 | "parser": { 21 | "unsafeParameterDecoratorsEnabled": true 22 | } 23 | }, 24 | "linter": { 25 | "enabled": true, 26 | "rules": { 27 | "complexity": { 28 | "noExcessiveCognitiveComplexity": { 29 | "level": "warn", 30 | "options": { 31 | "maxAllowedComplexity": 15 32 | } 33 | }, 34 | "noUselessSwitchCase": "error", 35 | "noVoid": "error", 36 | "useLiteralKeys": "error", 37 | "useSimplifiedLogicExpression": "error" 38 | }, 39 | "correctness": { 40 | "noNewSymbol": "error", 41 | "noUnusedImports": "error", 42 | "noUnusedVariables": "error", 43 | "useHookAtTopLevel": "error" 44 | }, 45 | "nursery": { 46 | "all": true 47 | }, 48 | "recommended": true, 49 | "style": { 50 | "noImplicitBoolean": "error", 51 | "noNamespace": "error", 52 | "noNegationElse": "error", 53 | "noNonNullAssertion": "error", 54 | "noShoutyConstants": "error", 55 | "useCollapsedElseIf": "error", 56 | "useShorthandArrayType": "error", 57 | "useShorthandAssign": "error" 58 | }, 59 | "suspicious": { 60 | "noApproximativeNumericConstant": "error", 61 | "noControlCharactersInRegex": "error", 62 | "noMisrefactoredShorthandAssign": "error" 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/langman-webhook/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaymanAI/langman-examples/d82a450bbcb1d745d544a91fda80984c4ea18b76/examples/langman-webhook/bun.lockb -------------------------------------------------------------------------------- /examples/langman-webhook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agent-clone-ts-langgraph", 3 | "module": "src", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "bun --watch src/main.ts", 7 | "lint": "biome check .", 8 | "lint:fix": "biome check --fix ." 9 | }, 10 | "devDependencies": { 11 | "@biomejs/biome": "1.9.3", 12 | "@types/bun": "latest" 13 | }, 14 | "peerDependencies": { 15 | "typescript": "^5.0.0" 16 | }, 17 | "dependencies": { 18 | "@langchain/core": "^0.3.9", 19 | "@langchain/langgraph": "^0.2.14", 20 | "@langchain/openai": "^0.3.6", 21 | "axios": "^1.7.7", 22 | "elysia": "^1.1.17", 23 | "paymanai": "^1.0.0", 24 | "uuid": "^10.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/langman-webhook/src/graph.ts: -------------------------------------------------------------------------------- 1 | import { StateGraph } from "@langchain/langgraph"; 2 | import StateAnnotation from "./state"; 3 | import { model } from "./model"; 4 | import { MemorySaver } from "@langchain/langgraph"; 5 | import { AIMessage, ToolMessage } from "@langchain/core/messages"; 6 | import { generateTools } from "./tools"; 7 | import { ToolNode } from "@langchain/langgraph/prebuilt"; 8 | 9 | async function callModel(state: typeof StateAnnotation.State) { 10 | const messages = state.messages; 11 | const tools = generateTools(); 12 | const modelWithTools = model.bindTools(tools); 13 | const response = await modelWithTools.invoke(messages); 14 | 15 | // We return a list, because this will get added to the existing list 16 | return { messages: [response] }; 17 | } 18 | 19 | async function ToolNodeWithGraphState(state: typeof StateAnnotation.State) { 20 | const tools = generateTools(); 21 | const toolNodeWithConfig = new ToolNode(tools); 22 | return toolNodeWithConfig.invoke(state); 23 | } 24 | 25 | function checkToolCall(state: typeof StateAnnotation.State) { 26 | const messages = state.messages; 27 | const lastMessage = messages[messages.length - 1] as AIMessage; 28 | // If the LLM makes a tool call, then we route to the "tools" node 29 | if (lastMessage.tool_calls?.length) { 30 | return "tools"; 31 | } 32 | // Otherwise, we stop (reply to the user) 33 | return "__end__"; 34 | } 35 | 36 | function checkToolResponse(state: typeof StateAnnotation.State) { 37 | const messages = state.messages; 38 | const lastMessage = messages[messages.length - 1] as ToolMessage; 39 | 40 | const content = lastMessage.content as string; 41 | 42 | if (content.includes("HTTP Error")) { 43 | //if error sends back to AI Agent, but could also send to another node that better handles the error 44 | return "agent"; 45 | } 46 | 47 | console.log("WAITING FOR WEBHOOK"); 48 | state.waitingForWebhook = true; 49 | // console.log("State", state); 50 | return "waitForWebhook"; 51 | } 52 | 53 | const workflow = new StateGraph(StateAnnotation) 54 | .addNode("agent", callModel) 55 | .addNode("tools", ToolNodeWithGraphState) 56 | .addNode("waitForWebhook", async () => {}) 57 | .addEdge("__start__", "agent") 58 | .addConditionalEdges("agent", checkToolCall, ["tools", "__end__"]) 59 | .addConditionalEdges("tools", checkToolResponse, ["waitForWebhook", "agent"]) 60 | .addEdge("waitForWebhook", "agent"); 61 | 62 | const checkpointer = new MemorySaver(); 63 | 64 | export const app = workflow.compile({ 65 | checkpointer, 66 | interruptBefore: ["waitForWebhook"], 67 | }); 68 | -------------------------------------------------------------------------------- /examples/langman-webhook/src/main.ts: -------------------------------------------------------------------------------- 1 | import { server } from './server' 2 | 3 | server.listen(3000, () => console.log('Starting server on port 3000')) 4 | -------------------------------------------------------------------------------- /examples/langman-webhook/src/model.ts: -------------------------------------------------------------------------------- 1 | import { ChatOpenAI } from "@langchain/openai"; 2 | 3 | const OPENAI_API_KEY = process.env.OPENAI_API_KEY; 4 | 5 | export const model = new ChatOpenAI({ 6 | model: "gpt-4o", 7 | openAIApiKey: OPENAI_API_KEY, 8 | temperature: 0.7, 9 | }); 10 | -------------------------------------------------------------------------------- /examples/langman-webhook/src/server.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, t } from "elysia"; 2 | import { v4 as uuidv4 } from "uuid"; 3 | import { app } from "./graph"; 4 | import { HumanMessage } from "@langchain/core/messages"; 5 | 6 | export const server = new Elysia() 7 | .post("/start", async () => { 8 | const thread_id = uuidv4(); 9 | const result = await app.invoke( 10 | { 11 | messages: [ 12 | new HumanMessage( 13 | "Get Tyllen (tyllen@paymanai.com) to plan an event for me. It's for 50 people and I want it to be a surprise party. I want it to be at a restaurant and I want to spend $50. I want it to be on a Saturday night. Make a made up itenerary for him and have him do it for us. Go for it!" 14 | ), 15 | ], 16 | waitingForWebhook: false, 17 | }, 18 | { configurable: { thread_id } } 19 | ); 20 | 21 | return { 22 | state: result, 23 | thread_id, 24 | }; 25 | }) 26 | .post( 27 | "/message/:id", 28 | async ({ body: { message }, params: { id } }) => { 29 | const config = { configurable: { thread_id: id } }; 30 | await app.updateState(config, { messages: [message] }); //add `asNode: "wait_for_input"` to update as a graph node 31 | 32 | return { 33 | state: await app.getState(config), 34 | id, 35 | }; 36 | }, 37 | { 38 | body: t.Object({ 39 | message: t.String(), 40 | }), 41 | } 42 | ) 43 | .post( 44 | "/webhook", 45 | async ({ body: { eventType, details } }) => { 46 | console.log("Webhook received", eventType, details); 47 | 48 | const thread_id = details.metadata.thread_id; 49 | const config = { configurable: { thread_id } }; 50 | switch (eventType) { 51 | case "submission.approved": { 52 | let submissionText = details.submission_details.description; 53 | await app.updateState( 54 | config, 55 | { 56 | messages: [ 57 | new HumanMessage( 58 | `User let us know they completed the task, here is the response: ${submissionText}` 59 | ), 60 | ], 61 | waitingForWebhook: false, 62 | }, 63 | 64 | "waitForWebhook" 65 | ); 66 | 67 | // Wait for the state to be updated before invoking 68 | const result = await app.invoke(null, config); 69 | 70 | console.log("Result from webhook:", result); 71 | return { 72 | state: result, 73 | thread_id, 74 | }; 75 | } 76 | } 77 | }, 78 | { 79 | body: t.Object({ 80 | eventType: t.String(), 81 | details: t.Any(), 82 | }), 83 | } 84 | ) 85 | .get("/message/:id", async ({ params: { id } }) => { 86 | const config = { configurable: { thread_id: id } }; 87 | return { 88 | state: await app.getState(config), 89 | id, 90 | }; 91 | }); 92 | -------------------------------------------------------------------------------- /examples/langman-webhook/src/state.ts: -------------------------------------------------------------------------------- 1 | import type { BaseMessage } from "@langchain/core/messages"; 2 | import { Annotation } from "@langchain/langgraph"; 3 | 4 | const StateAnnotation = Annotation.Root({ 5 | messages: Annotation({ 6 | reducer: (x, y): BaseMessage[] => x.concat(y), 7 | }), 8 | waitingForWebhook: Annotation(), 9 | }); 10 | 11 | export default StateAnnotation; 12 | -------------------------------------------------------------------------------- /examples/langman-webhook/src/tools.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { z } from "zod"; 3 | import { tool } from "@langchain/core/tools"; 4 | import { type LangGraphRunnableConfig } from "@langchain/langgraph"; 5 | 6 | export function generateTools() { 7 | const createTask = tool( 8 | async (input, config: LangGraphRunnableConfig) => { 9 | const { title, description, email } = input; 10 | const thread_id = config.configurable?.thread_id; 11 | 12 | const headers = { 13 | "x-payman-api-secret": process.env.PAYMAN_API_SECRET, 14 | "Content-Type": "application/json", 15 | Accept: "application/vnd.payman.v1+json", 16 | }; 17 | 18 | const payload = { 19 | title: title, 20 | description: description, 21 | payout: 5000, 22 | metadata: { 23 | thread_id, 24 | }, 25 | inviteEmails: [email], 26 | }; 27 | 28 | try { 29 | const apiUrl: any = process.env.PAYMAN_DEV_API; 30 | const response = await axios.post(apiUrl, payload, { headers }); 31 | 32 | return `Task created successfully: ${response.data.title}`; 33 | } catch (error: any) { 34 | if (error.response) { 35 | return `HTTP Error: ${error.response.status} - ${error.response.data.errorMessage}`; 36 | } else { 37 | return `Error: ${error.data}`; 38 | } 39 | } 40 | }, 41 | { 42 | name: "createTask", 43 | description: 44 | "Create a new task on the Payman platform with a title, description, and invited email.", 45 | schema: z.object({ 46 | title: z.string().describe("The title of the task."), 47 | description: z.string().describe("The description of the task."), 48 | email: z 49 | .string() 50 | .email() 51 | .describe("The email of the person to invite to complete the task."), 52 | }), 53 | } 54 | ); 55 | return [createTask]; 56 | } 57 | -------------------------------------------------------------------------------- /examples/langman-webhook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | "paths": { 11 | "@/*": [ 12 | "./src/*" 13 | ] 14 | }, 15 | 16 | // Bundler mode 17 | "moduleResolution": "bundler", 18 | "allowImportingTsExtensions": true, 19 | "verbatimModuleSyntax": true, 20 | "noEmit": true, 21 | 22 | // Best practices 23 | "strict": true, 24 | "skipLibCheck": true, 25 | "noFallthroughCasesInSwitch": true, 26 | 27 | // Some stricter flags (disabled by default) 28 | "noUnusedLocals": false, 29 | "noUnusedParameters": false, 30 | "noPropertyAccessFromIndexSignature": false 31 | } 32 | } 33 | --------------------------------------------------------------------------------