hexgate Structure
⚠️ Status: STALE — predates the multi-adapter + platform refactor. It still describes a small single-agent LangChain demo (This document summarizes howhexgate/demo.py,hexgate/setup.py, two tools) that no longer reflects the codebase. Do not trust paths or flow here until refreshed.
hexgate is structured, how the runtime flows, and what each file is responsible for.
High-Level Shape
hexgate is a small LangChain-based agent runtime with:
- one demo entrypoint
- one agent factory
- one settings/bootstrap layer
- two tools:
web_searchandfetch - one tracing wrapper for Langfuse
- one small async retry utility
hexgate/demo.pystarts the demo.hexgate/setup.pyloads.envand validates required keys.hexgate/agent/factory.pybuilds the agent and Langfuse handler.- The agent uses the system prompt from
hexgate/prompts/agent_system.md. - The agent can call
hexgate/tools/websearch.pyandhexgate/tools/fetch.py. - Tracing is handled through
hexgate/tracing/langfuse.py.
Directory Layout
Top-Level Files
pyproject.toml
This is the package manifest. It defines the project metadata, runtime dependencies, and dev dependencies.
Key snippet:
langchainprovides the agent runtimehttpxis used by the toolslangchain-coreprovides the@tooldecoratorlangfusehandles tracingpython-dotenvloads.env
Package Files
hexgate/__init__.py
This marks hexgate/ as a Python package.
Key snippet:
hexgate/setup.py
This is the bootstrap layer. It loads environment variables and returns a validated Settings object.
Key snippet:
- resolve the
.envpath relative to the repo - load env vars into the process
- create typed settings
- fail early if required keys are missing
hexgate/demo.py
This is the runnable demo entrypoint. It shows the happy path for the first agent.
Key snippet:
- initialize the app
- create the agent and trace handler
- send one hardcoded demo query
- print streaming updates
- print the Langfuse trace URL if tracing is active
hexgate/agent/__init__.py
This marks the agent/ directory as a package. It currently has no extra logic.
hexgate/agent/factory.py
This is the core composition file. It wires together the model, tools, prompt, and tracing.
Key snippets:
- read the system prompt from disk
- build the agent
- attach the two custom tools
- create a Langfuse callback handler
- provide both non-streaming and streaming invocation helpers
hexgate/config/__init__.py
This marks the config folder as a package.
hexgate/config/settings.py
This defines the typed runtime settings model and validates required API keys.
Key snippets:
- gather all env-based configuration in one place
- provide defaults for model and Langfuse host
- validate the minimum keys needed by the runtime
hexgate/prompts/agent_system.md
This is the agent’s system prompt, kept outside Python so it is easy to edit separately.
Key snippet:
- what role it has
- when to use tools
- what tools exist
- how concise and direct the answers should be
hexgate/tools/__init__.py
This marks the tools folder as a package.
hexgate/tools/websearch.py
This implements a Linkup-backed search tool exposed to the agent.
Key snippets:
- fetch
LINKUP_API_KEYfrom the environment - call Linkup’s search API
- retry transient HTTP failures
- normalize provider output into a simpler result shape
- expose the function as an agent tool via
@tool
try/except import for tool, unlike fetch.py, so the codebase is not fully consistent yet.
hexgate/tools/fetch.py
This implements a Tavily-backed URL extraction tool.
Key snippets:
- fetch
TAVILY_API_KEY - call Tavily’s extract endpoint
- retry HTTP failures
- trim returned content to 20,000 characters
- expose the capability as a tool
websearch.py and fetch.py give the agent a simple two-step research pattern:
- search the web for candidate sources
- fetch a specific URL for more detailed extraction
hexgate/tracing/__init__.py
This marks the tracing folder as a package.
hexgate/tracing/langfuse.py
This file isolates Langfuse integration details so the rest of the app does not have to care about SDK differences.
Key snippets:
- provide an
observedecorator wrapper - create a Langfuse callback handler
- adapt to old and new Langfuse callback APIs
- build the runnable config passed into LangChain
- resolve the current trace URL when possible
hexgate/utils/__init__.py
This marks the utils folder as a package.
hexgate/utils/retry.py
This provides a lightweight async retry decorator used by the tools.
Key snippet:
- wrap async functions
- retry only selected exception types
- pause between retries
- re-raise the last error after retries are exhausted
Architectural Notes
1. Separation by concern
The code is split into clear layers:config/for environment and settingsagent/for assembly and runtime wiringtools/for external capabilitiestracing/for observability integrationutils/for generic helpersprompts/for prompt text
2. Thin entrypoint, fat composition
demo.py is intentionally thin. Most interesting logic lives in factory.py.
That is a healthy pattern because:
- CLI files stay easy to read
- the same factory can later be reused by tests, APIs, notebooks, or jobs
3. Tool-first agent design
The current agent is designed around two explicit tools:web_searchfetch
4. Prompt outside Python
Storing the system prompt inprompts/agent_system.md is a good call. It keeps prompt editing cheap and prevents long embedded strings from cluttering factory.py.
5. Version-tolerant Langfuse wrapper
tracing/langfuse.py is doing real architectural work, not just boilerplate. It shields the rest of the app from Langfuse SDK changes, which already mattered in this repo.
Small Gaps / Cleanup Opportunities
hexgate/tools/websearch.pystill has the scaffold-styletry/exceptimport fortool, whilefetch.pynow imports it directly.demo.pyuses a hardcoded question; later you may want a CLI arg or interactive prompt.- There are no tests yet for settings validation, retry behavior, or tool normalization.
- The demo path currently assumes all three provider keys are present, even if a future agent might not always need both tools.
Short Summary
If I had to describe the structure in one sentence:hexgate is a compact agent runtime where demo.py boots the app, factory.py assembles the agent, settings.py validates config, websearch.py and fetch.py provide capabilities, langfuse.py handles tracing compatibility, and retry.py supports resilient tool calls.