{"id":48352975,"url":"https://github.com/plateerlab/mantis-engine","last_synced_at":"2026-04-05T10:02:00.011Z","repository":{"id":345487132,"uuid":"1185861368","full_name":"PlateerLab/mantis-engine","owner":"PlateerLab","description":"AI agent execution engine — plug in a model, get a working agent.","archived":false,"fork":false,"pushed_at":"2026-03-30T08:24:15.000Z","size":388,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T15:05:00.366Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PlateerLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-19T02:34:57.000Z","updated_at":"2026-03-30T08:24:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/PlateerLab/mantis-engine","commit_stats":null,"previous_names":["plateerlab/matis"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/PlateerLab/mantis-engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlateerLab%2Fmantis-engine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlateerLab%2Fmantis-engine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlateerLab%2Fmantis-engine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlateerLab%2Fmantis-engine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PlateerLab","download_url":"https://codeload.github.com/PlateerLab/mantis-engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlateerLab%2Fmantis-engine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31431451,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T08:13:15.228Z","status":"ssl_error","status_checked_at":"2026-04-05T08:13:11.839Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2026-04-05T10:01:01.679Z","updated_at":"2026-04-05T10:02:00.003Z","avatar_url":"https://github.com/PlateerLab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eMantis Engine\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.org/project/mantis-engine/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/pyversions/mantis-engine\" alt=\"Python\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\u003cstrong\u003eWorkflow execution engine.\u003c/strong\u003e\u003c/p\u003e\n\nFeed a workflow graph (nodes + edges), get logical execution. Replaces tangled, spaghetti executors with clean 4-phase pipeline: **PARSE → PLAN → EXECUTE → FINALIZE**.\n\n```python\nfrom mantis import WorkflowRuntime\n\nruntime = WorkflowRuntime(model=my_llm, tools=[calculate, get_weather])\n\n# Execute a workflow graph\nasync for event in runtime.execute(workflow_data, input_data):\n    print(event)\n\n# Or collect the final result\nresult = await runtime.execute_collect(workflow_data, input_data)\n```\n\n## Installation\n\n```bash\npip install mantis-engine              # core only (httpx)\npip install mantis-engine[search]      # + graph-tool-call (\u003e=0.15)\npip install mantis-engine[sandbox]     # + Docker sandbox\npip install mantis-engine[state]       # + PostgreSQL checkpointing\npip install mantis-engine[all]         # everything\n```\n\n## How It Works\n\n```\n ┌─ Caller (xgen, FastAPI, script) ────────────────────────────────────┐\n │                                                                      │\n │  workflow_data ─── {nodes: [...], edges: [...]}                      │\n │  input_data ────── data for startnode                                │\n │  model ─────────── LLMProvider (for agent nodes)                    │\n │  tools ─────────── [@tool functions] (for agent nodes)              │\n │  hooks ─────────── [TraceHook, ApprovalHook, ...]                   │\n │  providers ─────── search / sandbox / workflows / state             │\n │                                                                      │\n └──────────────────────────┬───────────────────────────────────────────┘\n                            │  runtime.execute(workflow_data, input_data)\n                            ▼\n╔═══════════════════════════════════════════════════════════════════════════╗\n║                         WorkflowRuntime                                  ║\n╠═══════════════════════════════════════════════════════════════════════════╣\n║                                                                           ║\n║   ┌─ PARSE ──────────────────────────────────────────────────────────┐  ║\n║   │  JSON → NodeInfo + EdgeInfo                                       │  ║\n║   │  disabled/disconnected removal · port dependency · runner mapping │  ║\n║   └──────────────────────────┬───────────────────────────────────────┘  ║\n║                              ▼                                           ║\n║   ┌─ PLAN ───────────────────────────────────────────────────────────┐  ║\n║   │  Kahn's algorithm topological sort · cycle detection              │  ║\n║   └──────────────────────────┬───────────────────────────────────────┘  ║\n║                              ▼                                           ║\n║   ┌─ EXECUTE ────────────────────────────────────────────────────────┐  ║\n║   │                                                                    │  ║\n║   │  for node in execution_order:                                      │  ║\n║   │      excluded? → skip                                              │  ║\n║   │      PortStore.wire() → inputs                                     │  ║\n║   │      Hook.before_node()                                            │  ║\n║   │      NodeRunner.run() → result       ┌─────────────────────┐      │  ║\n║   │      Hook.after_node()               │  NodeRunner 6 types │      │  ║\n║   │      PortStore.store()               │  Default  (compute) │      │  ║\n║   │      RouteResolver.evaluate()        │  Agent    (LLM)     │      │  ║\n║   │                                      │  Router   (N-way)   │      │  ║\n║   │      yield event                     │  Provider (config)  │      │  ║\n║   │                                      │  IO       (in/out)  │      │  ║\n║   │                                      │  Bypass   (pass)    │      │  ║\n║   │                                      └─────────────────────┘      │  ║\n║   └──────────────────────────┬───────────────────────────────────────┘  ║\n║                              ▼                                           ║\n║   ┌─ FINALIZE ───────────────────────────────────────────────────────┐  ║\n║   │  collect endnode results · cleanup streams · Hook.on_complete()   │  ║\n║   └──────────────────────────────────────────────────────────────────┘  ║\n║                                                                           ║\n║   ┌─ Internal Modules ───────────────────────────────────────────────┐  ║\n║   │  PortStore ────── port-based data wiring between nodes            │  ║\n║   │  StreamManager ── generator fan-out · BufferedFactory · replay    │  ║\n║   │  RouteResolver ── router branching · subgraph DFS exclusion       │  ║\n║   │  ToolRegistry ─── @tool · file · dir · runtime creation · bridge  │  ║\n║   │  ToolGenerator ── LLM code gen → Docker verify → register         │  ║\n║   │  ToolTester ──── schema → smoke → pytest 3-level verification     │  ║\n║   │  WorkflowGenerator ── LLM → WorkflowDef auto-design              │  ║\n║   └──────────────────────────────────────────────────────────────────┘  ║\n║                                                                           ║\n╠═══════════════════════════════════════════════════════════════════════════╣\n║   HOOKS (applied per node)                                                ║\n║   before_node → [execute] → after_node → on_complete                     ║\n║   Approval · Trace · custom                                               ║\n╠═══════════════════════════════════════════════════════════════════════════╣\n║   ADAPTERS                                                                ║\n║   event_to_sse · langchain_adapter · xgen_adapter · bridge                ║\n╚═══════════════════════════════════════════════════════════════════════════╝\n                            │\n                            ▼\n                    Event Stream / Result\n```\n\nThe main loop has **zero if/elif for node types**. All node-specific logic dispatches to NodeRunner handlers.\n\n## Node Runners\n\n| Runner | Handles | What it does |\n|--------|---------|-------------|\n| DefaultRunner | compute, transform | `node.execute(**inputs)` → store result |\n| AgentRunner | LLM agents | PipelineExecutor loop with ToolRegistry, search, sandbox. Streams tokens + tool calls. |\n| RouterRunner | conditional branch | Extract routing key → RouteResolver excludes unselected subgraphs via DFS |\n| ProviderRunner | model, MCP, config | Create config object → downstream nodes receive via port wiring |\n| IORunner | start, end | Start: inject input_data. End: collect results, stream generators. |\n| BypassRunner | bypass=True | Pass through input without execution |\n\n## Agent Nodes\n\nWhen an agent node has no `node_class`, AgentRunner creates a `PipelineExecutor` with all connected providers:\n\n```\nAgentRunner._run_mantis_agent()\n  → PipelineExecutor(model, ToolRegistry, search, sandbox, workflows, state)\n    → RESOLVE: LLM call (with tool search filtering)\n    → ACT: tool execution (with create_tool + Docker verify if sandbox)\n    → OBSERVE: checkpoint\n    → loop until done\n  → intermediate events (tool_call, tool_result) propagate to workflow stream\n```\n\n## Tool Creation \u0026 Verification\n\nWhen sandbox is provided, agent nodes can create tools at runtime:\n\n```\ncreate_tool → LLM generates @tool code\n  → Docker sandbox: syntax check\n    → ToolTester: smoke test + pytest\n      → pass → ToolRegistry registration → available next iteration\n```\n\n3-level verification:\n\n| Level | Method | Sandbox |\n|-------|--------|---------|\n| 1 | `validate_schema()` | No |\n| 2 | `smoke_test()` | Optional |\n| 3 | `run_pytest()` | Required |\n\n## Tool Search (graph-tool-call)\n\n```python\nfrom mantis.search import GraphToolManager, GraphToolConfig\n\nmanager = GraphToolManager(GraphToolConfig(search_mode=\"enhanced\"))\n\ntools = await manager.aretrieve(\"cancel order\", top_k=5)\nplan = manager.plan_workflow(\"Process refund for order #123\")\ncompressed = manager.compress_result(huge_response, max_chars=4000)\n```\n\n## PipelineExecutor (Agent Mode)\n\nFor standalone agent execution without a workflow graph:\n\n```python\nfrom mantis import PipelineExecutor, tool\nfrom mantis.providers import ModelClient\n\n@tool(name=\"calc\", description=\"Calculate\", parameters={\"expr\": {\"type\": \"string\"}})\nasync def calc(expr: str) -\u003e dict:\n    return {\"result\": eval(expr)}\n\nexecutor = PipelineExecutor(\n    model=ModelClient(model=\"gpt-4o-mini\", api_key=\"sk-...\"),\n    tools=[calc],\n)\nresult = await executor.run(\"What is 42 * 17?\")\n```\n\n## Events\n\n```python\nasync for event in runtime.execute(workflow_data, input_data):\n    match event[\"type\"]:\n        case \"workflow_start\":   ...  # node count, edge count\n        case \"execution_plan\":   ...  # order, node_count\n        case \"node_start\":       ...  # node_id, function_id, name, input_keys, timestamp\n        case \"node_complete\":    ...  # node_id, result_keys, output_data, duration_ms\n        case \"node_skip\":        ...  # node_id, reason (excluded/bypass)\n        case \"route_decision\":   ...  # selected_port\n        case \"stream_chunk\":     ...  # node_id, chunk\n        case \"agent_tool_call\":  ...  # node_id, tool_name, args\n        case \"agent_tool_result\":...  # node_id, tool_name, result\n        case \"workflow_complete\": ...  # final results\n        case \"workflow_error\":   ...  # error detail\n```\n\n## Package Structure\n\n```\nmantis/\n├── runtime/                    # WorkflowRuntime (core engine)\n│   ├── runtime.py              # entry point: PARSE → PLAN → EXECUTE → FINALIZE\n│   ├── parse.py                # workflow JSON → NodeInfo/EdgeInfo\n│   ├── plan.py                 # topological sort (Kahn's algorithm)\n│   ├── context.py              # runtime execution context\n│   ├── port_store.py           # port-based data wiring\n│   ├── stream_manager.py       # generator fan-out / BufferedFactory\n│   ├── route_resolver.py       # router branching + DFS exclusion\n│   ├── runners/                # NodeRunner handlers (6 types)\n│   └── hooks/                  # ExecutionHook (trace, approval)\n│\n├── executor/                   # PipelineExecutor (agent mode)\n│   ├── pipeline.py             # PREPARE → RESOLVE → ACT → OBSERVE loop\n│   ├── flow.py                 # FlowState for deterministic flows\n│   └── phases/                 # pluggable phase implementations\n│\n├── tools/                      # @tool decorator, ToolRegistry, bridge\n├── llm/                        # LLMProvider protocol + OpenAI-compatible client\n├── providers/                  # provider re-exports (ModelClient, etc.)\n├── context/                    # ConversationContext\n├── middleware/                  # approval, trace, graph-search, state\n├── search/                     # GraphToolManager (graph-tool-call)\n├── sandbox/                    # DockerSandbox\n├── generate/                   # ToolGenerator (LLM → code → verify → register)\n├── testing/                    # ToolTester (schema → smoke → pytest)\n├── workflow/                   # WorkflowDef, Store, Generator\n├── safety/                     # ApprovalManager\n├── state/                      # StateStore + state tools\n├── trace/                      # TraceCollector + exporter\n├── adapters/                   # SSE, xgen, LangChain adapters\n├── models/                     # NodeInfo, PortInfo, EdgeInfo\n└── exceptions.py               # MantisError hierarchy\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplateerlab%2Fmantis-engine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplateerlab%2Fmantis-engine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplateerlab%2Fmantis-engine/lists"}