{"id":23777299,"url":"https://github.com/pompeii-labs/magma","last_synced_at":"2025-10-04T21:34:44.477Z","repository":{"id":259981840,"uuid":"858296398","full_name":"pompeii-labs/magma","owner":"pompeii-labs","description":"An AI agent framework built to get your agents into an application as fast as possible. Deploy on MagmaDeploy.com or self-host","archived":false,"fork":false,"pushed_at":"2025-03-27T14:43:51.000Z","size":224,"stargazers_count":80,"open_issues_count":0,"forks_count":5,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-27T15:47:39.354Z","etag":null,"topics":["agent","agent-based","ai","magma","typescript"],"latest_commit_sha":null,"homepage":"https://magmadeploy.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pompeii-labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-16T16:49:10.000Z","updated_at":"2025-03-26T23:45:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"51bc0f55-8d8d-478d-9cb9-20e5cbc949dd","html_url":"https://github.com/pompeii-labs/magma","commit_stats":null,"previous_names":["pompeii-labs/magma"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pompeii-labs%2Fmagma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pompeii-labs%2Fmagma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pompeii-labs%2Fmagma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pompeii-labs%2Fmagma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pompeii-labs","download_url":"https://codeload.github.com/pompeii-labs/magma/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246697992,"owners_count":20819480,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","agent-based","ai","magma","typescript"],"created_at":"2025-01-01T08:24:11.242Z","updated_at":"2025-10-04T21:34:39.431Z","avatar_url":"https://github.com/pompeii-labs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cimg alt=\"Magma Framework logo\" src=\"https://db.productdialog.com/storage/v1/object/public/images/magma-header.jpg\"\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cstrong\u003eTurn your workflows into a workforce.\u003c/strong\u003e\u003c/div\u003e\n\u003cdiv align=\"center\"\u003eCreate and deploy conversational agents without any of the headaches.\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![npm version](https://img.shields.io/npm/v/@pompeii-labs/magma.svg)](https://www.npmjs.com/package/@pompeii-labs/magma)\n[![Slack](https://img.shields.io/badge/Slack-4A154B?logo=slack\u0026logoColor=fff)](https://join.slack.com/t/magmacommunity/shared_invite/zt-2tghhq3av-Xn9k9ntwN5ZwqvxbWcfsTg)\n[![GitHub stars](https://img.shields.io/github/stars/pompeii-labs/Magma?style=social)](https://github.com/pompeii-labs/magma)\n\n\u003c/div\u003e\n\n## 🌋 What is Magma?\n\nMagma is a framework that lets you create AI agents without the headache. No complex chains, no confusing abstractions - just write the logic you want your agent to have.\n\nWant to try it out? [Chat with Dialog](https://chat.productdialog.com/ac94ab36-c5bb-4b54-a195-2b6b2499dcff), our user research agent built with Magma!\n\n## ⚡️ Quick Start\n\n1. Install Magma:\n```bash\nnpm i @pompeii-labs/magma\n```\n\n2. Create your first agent:\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\n\n// Magma Agents are class based, so you can extend them with your own methods\nclass MyAgent extends MagmaAgent {\n\n    // Want to give it some personality? Add system prompts:\n    getSystemPrompts() {\n        return [{\n            role: \"system\",\n            content: \"You are a friendly assistant who loves dad jokes\"\n        }];\n    }\n}\n\n// That's it! You've got a working agent\nconst myAgent = new MyAgent();\n\n// Run it:\nconst reply = await myAgent.main();\nconsole.log(reply.content);\n```\n\n## 🔥 Key Features\n\n- **Simple**: Build agents in minutes with minimal code\n- **Flexible**: Use any AI provider (OpenAI, Anthropic, Groq)\n- **Hosted**: Deploy your agents in seconds with the [MagmaDeploy platform](https://magmadeploy.com)\n- **Powerful**: Add tools and middleware when you need them\n- **Observable**: See exactly what your agent is doing\n\n## 🛠 Examples\n\n### Add Tools\nTools give your agent the ability to perform actions. Any method decorated with @tool and @toolparam will be available for the agent to use.\n\n**Important Notes**:\n- Every tool method must return a string\n- Every tool has `call` as a required parameter, which is the `MagmaToolCall` object\n- Tools are executed in sequence\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\nimport { tool, toolparam } from \"@pompeii-labs/magma/decorators\";\n\n/** Decorate any agent class method with @toolparam or @tool. \n * @tool is used to define the tool itself\n * @toolparam is used to define the parameters of the tool (key, type, description, required)\n */\nclass MyAgent extends MagmaAgent {\n    @tool({ name: \"search_database\", description: \"Search the database for records\" })\n    @toolparam({\n        key: \"query\",\n        type: \"string\",\n        description: \"Search query\",\n        required: true\n    })\n    @toolparam({\n        key: \"filters\",\n        type: \"object\",\n        properties: [\n            { key: \"date\", type: \"string\" },\n            { key: \"category\", type: \"string\", enum: [\"A\", \"B\", \"C\"] }\n        ]\n    })\n    async searchDatabase(call: MagmaToolCall) {\n        const { query, filters } = call.fn_args;\n\n        const results = await this.searchDatabase(query, filters);\n\n        return \"Here are the results of your search: \" + JSON.stringify(results);\n    }\n}\n```\n\n### Add Middleware\nMiddleware is a novel concept to Magma. It allows you to add custom logic to your agent before or after a tool is executed.\n\nThis is a great way to add custom logging, validation, data sanitization, etc.\n\n**Types**:\n- \"preCompletion\": Runs before the LLM call is made, takes in a MagmaUserMessage\n- \"onCompletion\": Runs after the agent generates a text response, takes in a MagmaAssistantMessage\n- \"preToolExecution\": Runs before a tool is executed, takes in a MagmaToolCall\n- \"onToolExecution\": Runs after a tool is executed, takes in a MagmaToolResult\n\n**Important Notes**:\n- You can have unlimited middleware methods\n- Middleware methods can manipulate the message they take in\n- Middleware methods can throw errors to adjust the flow of the agent\n\n**Error Handling**:\n- If preCompletion middleware throws an error, the error message is supplied as if it were the assistant message. The user and assistant messages are also removed from the conversation history\n- If onCompletion middleware throws an error, the error message is supplied to the LLM, and it tries to regenerate a response. The assistant message is not added to the conversation history\n- If preToolExecution middleware throws an error, the error message is supplied as if it were the response from the tool\n- If onToolExecution middleware throws an error, the error message is supplied as if it were the response from the tool\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\nimport { middleware } from \"@pompeii-labs/magma/decorators\";\n\n/**\n * Decorate any agent class method with @middleware to add custom logging, validation, etc.\n * Types: \"preCompletion\", \"onCompletion\", \"preToolExecution\", \"onToolExecution\"\n */\nclass MyAgent extends MagmaAgent {\n\n    @middleware(\"onCompletion\")\n    async logBeforeCompletion(message) {\n        if (message.content.includes(\"bad word\")) {\n            throw new Error(\"You just used a bad word, please try again.\");\n        }\n    }\n}\n```\n\n### Schedule Jobs\nJobs allow you to schedule functions within your agent. Jobs conform to the standard UNIX cron syntax (https://crontab.guru/).\n\n**Important Notes**:\n- Jobs should be static methods, so they can run without instantiating the agent.\n- Jobs do not take in any parameters, and they do not return anything.\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\nimport { job } from \"@pompeii-labs/magma/decorators\";\n\nclass MyAgent extends MagmaAgent {\n    // Run every day at midnight\n    @job(\"0 0 * * *\")\n    static async dailyCleanup() {\n        await this.cleanDatabase();\n    }\n\n    // Run every hour with timezone\n    @job(\"0 * * * *\", { timezone: \"America/New_York\" })\n    static async hourlySync() {\n        await this.syncData();\n    }\n}\n```\n\n### Expose Hooks\nHooks allow you to expose your agent as an API. Any method decorated with @hook will be exposed as an endpoint.\n\n\n**Important Notes**:\n- Hooks are static methods, so they can run without instantiating the agent.\n- Hooks are exposed at `/hooks/{hook_name}` in the Magma API\n- The only parameter to hook functions is the request object, which is an instance of `express.Request`\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\nimport { hook } from \"@pompeii-labs/magma/decorators\";\nimport { Request } from \"express\";\n\nclass MyAgent extends MagmaAgent {\n\n    @hook('notification')\n    static async handleNotification(req: Request) {\n        await this.processNotification(req.body);\n    }\n}\n```\n\n### Use Different Providers\nYou can use any supported provider by setting the providerConfig.\n\n**Important Notes**:\n- You can set the providerConfig in the constructor, or by calling `setProviderConfig`\n- You do not need to adjust any of your tools, middleware, jobs, or hooks to use a different provider. Magma will handle the rest.\n```ts\nclass Agent extends MagmaAgent {\n    constructor() {\n        // Use OpenAI (default)\n        super({\n            providerConfig: {\n                provider: \"openai\",\n                model: \"gpt-4o\"\n            }\n        });\n\n        // Use Anthropic\n        this.setProviderConfig({\n            provider: \"anthropic\",\n            model: \"claude-3.5-sonnet-20240620\"\n        });\n\n        // Use Groq\n        this.setProviderConfig({\n            provider: \"groq\",\n            model: \"llama-3.1-70b-versatile\"\n        });\n    }\n}\n```\n\n### State Management\nEvery Tool, Middleware, Hook, and Job is passed the instance of the agent. This allows you to manipulate agent state and call agent functions in Utility classes\n\n```ts\nclass MyAgent extends MagmaAgent {\n    // Using a field to store data\n    myQuery: string;\n    counter: number;\n\n    async setup() {\n        this.myQuery = \"Hello, World!\";\n        this.counter = 0;\n    }\n\n    @tool({ description: \"Increment the counter\" })\n    async increment() {\n        this.counter++;\n        return `Counter is now ${this.counter}`;\n    }\n\n    @tool({ name: \"api_call\" })\n    async apiCall() {\n        const response = await fetch(\"https://myapi.com/data\", {\n            body: JSON.stringify({\n                query: this.myQuery\n            })\n        });\n\n        return JSON.stringify(response.json());\n    }\n}\n```\n\n### Core Methods\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\n\nclass MyAgent extends MagmaAgent {\n    // Initialize your agent\n    async setup() {\n        // Load resources, connect to databases, etc.\n        await this.loadDatabase();\n        return \"I'm ready to help!\";\n    }\n\n    // Handle incoming messages\n    async receive(message: any) {\n        // Process user input before main() is called\n        if (message.type === 'image') {\n            await this.processImage(message.content);\n        }\n    }\n\n    // Clean up resources\n    async cleanup();\n\n    // Manually trigger a specific tool\n    async trigger({ name: \"get_weather\" });\n\n    // Stop the current execution\n    kill();\n}\n```\n\n### Event Handlers\nEvent handlers are optional methods that allow you to tack on custom logic to various events in the agent lifecycle.\n```ts\nimport { MagmaAgent } from \"@pompeii-labs/magma\";\n\nclass MyAgent extends MagmaAgent {\n    // Handle agent shutdown\n    async onCleanup() {\n        console.log(\"Agent shutting down...\");\n    }\n\n    // Handle errors\n    async onError(error: Error) {\n        console.error(\"Something went wrong:\", error);\n        await this.notifyAdmin(error);\n    }\n\n    // Track token usage\n    async onUsageUpdate(usage: MagmaUsage) {\n        await this.saveUsageMetrics(usage);\n    }\n\n    // Process streaming responses\n    async onStreamChunk(chunk: MagmaStreamChunk) {\n        console.log(\"Received chunk:\", chunk.content);\n    }\n}\n```\n\n## 📚 Want More?\n\n- Join our [Slack Community](https://join.slack.com/t/magmacommunity/shared_invite/zt-2tghhq3av-Xn9k9ntwN5ZwqvxbWcfsTg)\n- Star us on [GitHub](https://github.com/pompeii-labs/magma)\n\n## 📝 License\n\nMagma is [Apache 2.0 licensed](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpompeii-labs%2Fmagma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpompeii-labs%2Fmagma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpompeii-labs%2Fmagma/lists"}