Centralized AI agent framework for Open Geospatial Python packages and QGIS plugins (Strands Agents)
Project description
GeoAgent
GeoAgent is a shared AI agent layer for geospatial Python packages, live map widgets, and QGIS plugins. It gives projects such as leafmap, anymap, geoai, geemap, STAC workflows, NASA Earthdata workflows, and QGIS plugins one consistent way to expose geospatial tools to large language models.
GeoAgent is built on Strands Agents. It wraps Strands with geospatial context, tool metadata, optional package adapters, provider configuration, and confirmation hooks for operations that should not run silently.
Why GeoAgent?
Many geospatial libraries need the same agent features:
- bind an agent to a live map, QGIS session, dataset, or workflow object;
- expose package functions as structured tools with docstrings and metadata;
- support OpenAI, ChatGPT/Codex OAuth, Anthropic, Google Gemini, Bedrock, LiteLLM, and local Ollama models;
- keep optional geospatial stacks optional;
- ask for confirmation before deleting layers, saving files, or running expensive processing jobs;
- provide a stable integration point for downstream packages and plugins.
GeoAgent centralizes that layer so each package does not need to maintain its own agent framework.
Core Concepts
| Concept | Purpose |
|---|---|
GeoAgent |
High-level facade around a Strands Agent. |
GeoAgentConfig |
Provider, model, temperature, token, and client settings. |
GeoAgentContext |
Runtime objects bound to the agent, such as a map or QGIS iface. |
@geo_tool |
Decorator that turns a Python function into a Strands tool with GeoAgent metadata. |
GeoToolRegistry |
Registry for tool metadata, safety flags, categories, and fast-mode filtering. |
for_leafmap |
Factory that binds tools to a leafmap.Map-compatible object. |
for_anymap |
Factory that binds tools to an anymap.Map-compatible object. |
for_qgis |
Factory that binds tools to qgis.utils.iface and an optional QgsProject. |
for_nasa_opera |
Factory that binds NASA OPERA search/display tools plus QGIS tools. |
create_agent |
Factory for custom tools or package-specific integrations. |
Installation
Install the core package:
pip install GeoAgent
Core installs only the agent framework dependencies, mainly strands-agents
and pydantic. Geospatial packages and provider clients are optional extras:
| Extra | Purpose |
|---|---|
GeoAgent[openai] |
OpenAI model support through Strands. |
GeoAgent[anthropic] |
Anthropic Claude model support through Strands. |
GeoAgent[gemini] |
Google Gemini model support through Strands. |
GeoAgent[ollama] |
Local Ollama model support. |
GeoAgent[litellm] |
LiteLLM model support for many hosted and proxy providers. |
GeoAgent[leafmap] |
leafmap live map integration. |
GeoAgent[anymap] |
anymap live map integration. |
GeoAgent[stac] |
STAC client dependencies. |
GeoAgent[earthdata] |
NASA Earthdata dependencies. |
GeoAgent[nasa-opera] |
NASA OPERA search dependencies. |
GeoAgent[geoai] |
geoai integration dependencies. |
GeoAgent[earthengine] |
Google Earth Engine dependencies. |
GeoAgent[ui] |
Solara UI dependencies. |
GeoAgent[providers] |
OpenAI, Anthropic, Gemini, Ollama, and LiteLLM provider clients. |
GeoAgent[all] |
Most optional integrations. QGIS itself remains system-installed. |
Examples:
pip install "GeoAgent[leafmap,openai]"
pip install "GeoAgent[anymap,anthropic]"
pip install "GeoAgent[stac,earthdata,openai]"
For QGIS, install GeoAgent in the Python environment used by QGIS. The
GeoAgent[qgis] extra is a marker extra; QGIS is provided by the desktop
application or system package manager.
Provider Configuration
GeoAgent selects a provider from environment variables when no provider is specified:
| Provider | Environment |
|---|---|
| OpenAI | OPENAI_API_KEY, optional OPENAI_MODEL |
| ChatGPT/Codex OAuth | OPENAI_CODEX_ACCESS_TOKEN, optional OPENAI_CODEX_MODEL |
| Anthropic | ANTHROPIC_API_KEY, optional ANTHROPIC_MODEL |
| Google Gemini | GEMINI_API_KEY or GOOGLE_API_KEY, optional GEMINI_MODEL |
| LiteLLM | LITELLM_API_KEY, optional LITELLM_MODEL and LITELLM_BASE_URL |
| Ollama | OLLAMA_HOST or USE_OLLAMA=1, optional OLLAMA_MODEL |
| Bedrock | AWS credential chain and model access, optional BEDROCK_MODEL |
ChatGPT/Codex OAuth uses the Codex browser login flow and the Codex Responses backend.
You can also configure providers explicitly:
from geoagent import GeoAgentConfig, for_leafmap
agent = for_leafmap(
m,
config=GeoAgentConfig(
provider="openai",
model="gpt-5.5",
temperature=0,
max_tokens=4096,
),
)
Factories also accept provider= and model_id= shortcuts:
agent = for_leafmap(m, provider="gemini", model_id="gemini-3.1-pro-preview")
Quickstart
Use GeoAgent directly when you do not need a map or package-specific toolset:
from geoagent import GeoAgent, GeoAgentConfig
agent = GeoAgent(config=GeoAgentConfig(provider="openai", model="gpt-5.5"))
resp = agent.chat("Explain STAC in two sentences.")
print(resp.answer_text)
Bind an agent to a live leafmap map:
import leafmap
from geoagent import for_leafmap
m = leafmap.Map()
agent = for_leafmap(m)
resp = agent.chat("Add a marker for Knoxville and zoom to it.")
print(resp.answer_text)
m
Bind an agent to an anymap map:
import anymap
from geoagent import for_anymap
m = anymap.Map()
agent = for_anymap(m)
agent.chat("Change the basemap and list the current layers.")
Use GeoAgent inside QGIS:
from qgis.utils import iface
from geoagent import for_qgis
agent = for_qgis(iface)
resp = agent.chat("Summarize the project layers and zoom to the active layer.")
print(resp.answer_text)
geoagent.tools.qgis is import-safe outside QGIS. It imports QGIS classes only
inside tool bodies, so tests and non-QGIS environments can import the module.
Built-In Tool Surfaces
leafmap and anymap
for_leafmap(m) and for_anymap(m) expose a shared map-control surface:
- inspect state and layers:
get_map_state,list_layers; - navigate:
set_center,fly_to,set_zoom,zoom_in,zoom_out,zoom_to_bounds,zoom_to_layer; - manage layers:
add_layer,remove_layer,clear_layers,set_layer_visibility,set_layer_opacity; - add data:
add_vector_data,add_geojson_data,add_raster_data,add_cog_layer,add_stac_layer,add_xyz_tile_layer,add_pmtiles_layer,add_marker; - change basemaps and export maps:
change_basemap,save_map.
Layer lookup accepts exact names or a unique case-insensitive substring for
operations such as remove_layer, zoom_to_layer, set_layer_visibility, and
set_layer_opacity.
QGIS
for_qgis(iface, project=None) exposes tools that run through a Qt GUI-thread
marshaller:
- inspect project and layer state:
list_project_layers,get_active_layer,get_project_state,get_layer_summary,inspect_layer_fields,get_selected_features; - navigate:
zoom_in,zoom_out,zoom_to_layer,zoom_to_extent,zoom_to_selected,set_center,set_scale,refresh_canvas; - manage layers and data:
add_vector_layer,add_raster_layer,add_xyz_tile_layer,remove_layer,set_layer_visibility,set_layer_opacity; - select and process:
select_features_by_expression,clear_selection,run_processing_algorithm; - open QGIS UI and save:
open_attribute_table,save_project.
QGIS chat uses a sequential tool executor and GUI-thread marshalling so map canvas and layer-tree calls are routed safely.
NASA OPERA
for_nasa_opera(iface, project=None) exposes NASA OPERA product tools and the
standard QGIS tool surface:
- inspect OPERA products:
get_available_datasets,get_dataset_info; - search Earthdata granules:
search_opera_data; - display results:
display_footprints,display_raster,create_mosaic.
The OPERA integration is implemented as native GeoAgent tools and does not wrap
the NASA OPERA plugin's legacy nasa_opera.ai.tools registry.
When adding OPERA capabilities, implement the reusable tool logic in
geoagent/tools/nasa_opera.py. Keep the NASA OPERA QGIS plugin focused on UI,
settings, provider selection, progress display, and compatibility aliases. The
plugin consumes GeoAgent tool metadata automatically, so new GeoAgent OPERA
tools are available to the plugin AI Assistant without duplicating tool logic.
Use it from the QGIS Python console or from plugin code. For direct tool
testing, use submit_nasa_opera_search_task(...); this avoids LLM/provider
initialization and reports progress in QGIS's message bar and Log Messages
panel:
from geoagent.tools.nasa_opera import submit_nasa_opera_search_task
task = submit_nasa_opera_search_task(
iface,
dataset="OPERA_L3_DSWX-HLS_V1",
bbox="-95.5,29.5,-95.0,30.0",
start_date="2024-01-01",
end_date="2024-01-31",
max_results=5,
display_footprints=True,
)
For a longer QGIS-console script, see examples/nasa_opera_qgis.py.
Natural-language OPERA chat is intentionally disabled inside QGIS for now.
Use direct tools or submit_nasa_opera_search_task(...) so QGIS task/thread
ownership remains explicit.
Direct Tool Calls
Every GeoAgent exposes the underlying Strands tool caller. This is useful for tests, notebooks, and plugin UI actions:
agent = for_leafmap(m)
agent.tool.add_marker(lat=35.9606, lon=-83.9207, name="Knoxville")
agent.tool.list_layers()
You can inspect registered tool names and metadata:
agent.tool_names
agent.tool_registry.get_all_tools_config()
Safety and Confirmation
Tools carry metadata such as requires_confirmation, destructive, and
long_running. Confirmation is enforced by a Strands hook before gated tools
run.
By default, confirmation-required tools are denied unless you pass a confirmation callback:
from geoagent import auto_approve_all, for_leafmap
agent = for_leafmap(m, confirm=auto_approve_all)
For real applications, pass a callback that opens a Qt dialog, notebook modal, web UI prompt, or CLI prompt. Use confirmation for operations that delete data, overwrite files, save projects, launch expensive jobs, or call external services with cost implications.
Custom Tools
Package integrations can expose their own functions with @geo_tool:
from geoagent import GeoAgentContext, create_agent, geo_tool
@geo_tool(category="demo")
def buffer_distance(layer_name: str, distance: float) -> str:
"""Buffer a named layer by a distance in map units."""
return f"Buffered {layer_name} by {distance}."
agent = create_agent(
context=GeoAgentContext(),
tools=[buffer_distance],
)
For package-specific adapters, prefer a factory that binds live objects through
closures, just like for_leafmap, for_anymap, and for_qgis. This keeps
widgets, clients, credentials, and session objects out of the LLM-visible
arguments.
Fast Mode
Pass fast=True to reduce the exposed tool surface and cap response tokens for
lower-latency map control:
agent = for_leafmap(m, fast=True)
Fast mode keeps common inspection, navigation, and basemap tools, filters out heavier or more specialized tools, and limits model responses to short post-tool replies. The cap is conservative enough for tool calls while avoiding very long responses. The model call still dominates latency for local models, so small prompts may not show a large timing difference on every provider.
Examples
Runnable notebooks live under docs/examples/:
docs/examples/intro.ipynb— basic GeoAgent usage.docs/examples/live_mapping.ipynb— live map workflow.docs/examples/qgis_agent.ipynb— QGIS-oriented workflow using mocks.examples/nasa_opera_qgis.py— NASA OPERA workflow for QGIS.
Prompt ideas:
- "List layers on the current map."
- "Add a marker for Seattle and zoom to it."
- "Show the QGIS project state and summarize each layer."
- "Select parcels where population is greater than 10000."
- "Add a STAC layer and set its opacity to 0.6."
- "Search for January 2024 OPERA surface water near Houston and display the footprints."
Development
git clone https://github.com/opengeos/GeoAgent.git
cd GeoAgent
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pre-commit install
Run checks:
ruff check geoagent tests
pytest -q
See docs/contributing.md for guidance on adding new package and tool integrations.
License
GeoAgent is released under the MIT License. See LICENSE.
Links
- Documentation: https://geoagent.gishub.org
- Repository: https://github.com/opengeos/GeoAgent
- Issues: https://github.com/opengeos/GeoAgent/issues
- Strands Agents: https://strandsagents.com/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file geoagent-1.1.1.tar.gz.
File metadata
- Download URL: geoagent-1.1.1.tar.gz
- Upload date:
- Size: 193.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
766d346e2365d9e93e9121d2075886be1f60a5aa59d52a301961ed7b0f663d0f
|
|
| MD5 |
61bb15ceb6dec58985eccfde3f8405cf
|
|
| BLAKE2b-256 |
c23558cc5bf37893d0fad808a5b0aa47444be42c570ce670b512971cbda1066f
|
File details
Details for the file geoagent-1.1.1-py2.py3-none-any.whl.
File metadata
- Download URL: geoagent-1.1.1-py2.py3-none-any.whl
- Upload date:
- Size: 99.4 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdd531b95bae304edb66e0716004f4dda5fb8a74d276bbeccd88d3984967c55f
|
|
| MD5 |
d3f05be55bff28e1ecf02a214c3b3ca0
|
|
| BLAKE2b-256 |
74b63f4a04c8834158422ca3345241926c96091af7f383b4c99068cdebfb9d47
|