Skip to content

nsnarayanam/ogc-csapi-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

csapi_agent

A Google ADK / Gemini agent that lets you query OGC API — Connected Systems (CSAPI) servers in natural language. Built as a "second consumer" of the unmerged CSAPI library in camptocamp/ogc-client#136, which itself notes that a second consumer is one of the trigger conditions for unblocking the deferred SWE Common work in OS4CSAPI/ogc-client-CSAPI_2#171.

What this is

A single ADK LlmAgent powered by gemini-2.5-flash, exposing six CSAPI query tools. The tools are Python wrappers around a thin Node CLI that imports @camptocamp/ogc-client/csapi and uses its CSAPIQueryBuilder to construct request URLs against a CSAPI endpoint.

Six tools:

Tool Purpose
discover_csapi(url) Probe an OGC API endpoint; report CSAPI support + collection IDs
get_collection_info(url, collection) Full metadata for one collection
list_systems(url, collection, limit) Sensors / platforms / actuators
list_datastreams(url, collection, limit) Continuous observation channels
list_sampling_features(url, collection, limit) Geographic measurement sites
query_observations(url, collection, datastream_id, time_range, limit) Time-series readings

Architecture

┌───────────────────────┐
│   User (adk web UI)   │
└───────────┬───────────┘
            │ natural-language chat
            ▼
┌───────────────────────────────────────────────┐
│   Gemini LlmAgent (csapi_agent)               │
│   • Picks tool from user intent               │
│   • Summarizes JSON results in prose          │
└───────────┬───────────────────────────────────┘
            │ Python function call (1 of 6)
            ▼
┌───────────────────────────────────────────────┐
│   csapi_tools.py — Python wrappers            │
└───────────┬───────────────────────────────────┘
            │ subprocess.run(node ...)
            ▼
┌───────────────────────────────────────────────┐
│   csapi_cli/cli.mjs — Node CLI                │
│   discover | collection_info | list_systems | │
│   list_datastreams | list_sampling_features | │
│   query_observations                          │
└───────────┬───────────────────────────────────┘
            │ import
            ▼
┌───────────────────────────────────────────────┐
│   @camptocamp/ogc-client/csapi (PR #136)      │
│   • OgcApiEndpoint                            │
│   • createCSAPIBuilder → CSAPIQueryBuilder    │
└───────────┬───────────────────────────────────┘
            │ HTTP fetch
            ▼
┌───────────────────────────────────────────────┐
│   Mock CSAPI Server (FastAPI, port 8765)      │
│   — or any conformant CSAPI endpoint —        │
└───────────────────────────────────────────────┘

Quickstart

Prerequisites: Node ≥20, Python 3.14+, the BIA .venv at BIA/.venv/.

# 1. Copy your existing Google API key (one-time)
cp ../my_agent/.env ./.env

# 2. Install Node deps for the CLI (one-time; links to the patched snapshot)
cd csapi_cli && npm install && cd ..

# 3. Install Python deps for the mock (one-time)
../.venv/bin/pip install -r mock_server/requirements.txt

# 4. Start the mock server (terminal 1)
../.venv/bin/python mock_server/server.py

# 5. Start the agent (terminal 2)
cd ..
source .venv/bin/activate
adk web
# → open http://localhost:8000, pick `csapi_agent` from the dropdown

Example queries

The exact prose the model produces will vary turn-to-turn, but the tool calls and underlying data are deterministic. Sample outputs below were captured against the included mock server.

1. Discover a server

You: Discover the CSAPI server at http://localhost:8765

Tool call: discover_csapi(url="http://localhost:8765")

Tool returns:

{
  "url": "http://localhost:8765",
  "hasConnectedSystems": true,
  "collections": ["weather-stations"]
}

Sample assistant reply: "The server at http://localhost:8765 supports Connected Systems and exposes one collection: weather-stations."


2. List the sensors

You: What sensors are deployed?

Tool call: list_systems(url="http://localhost:8765", collection="weather-stations", limit=10)

Tool returns 2 features: station-001 (North Field Weather Station, −122.4194, 37.7749) and station-002 (Coastal Buoy, −122.5, 37.8). Both are systemKind: Sensor.

Sample assistant reply: "There are two sensor systems registered in weather-stations:

  • station-001 — North Field Weather Station, located at (−122.42, 37.77).
  • station-002 — Coastal Buoy, located at (−122.5, 37.8).

Both are classified as Sensor systems."


3. Show a time-series with a filter

You: Show me the air temperature readings between 5am and 8am UTC on May 2nd, 2026

The agent first calls list_datastreams to map "air temperature" to a datastream ID (temp-001), then:

Tool call: query_observations(url="http://localhost:8765", collection="weather-stations", datastream_id="temp-001", time_range="2026-05-02T05:00:00Z/2026-05-02T08:00:00Z", limit=10)

Tool returns 3 observations:

phenomenonTime result uom
2026-05-02T05:00:00Z 17.5 Cel
2026-05-02T06:00:00Z 18.0 Cel
2026-05-02T07:00:00Z 18.5 Cel

Sample assistant reply: "Air temperature on station-001 climbed steadily from 17.5 °C at 05:00 UTC to 18.5 °C at 07:00 UTC on May 2nd — about 0.5 °C per hour. Three hourly readings in that window."


4. Where are the measurement sites?

You: Where are the sampling locations?

Tool call: list_sampling_features(url="http://localhost:8765", collection="weather-stations", limit=10)

Tool returns 1 feature: sf-001 — North Field Site, Point at (−122.4194, 37.7749).

Sample assistant reply: "There's one sampling site: North Field Site (sf-001), a point location at approximately (−122.42, 37.77)."

Bugs found upstream

Built incrementally against the OpenSensorHub demo server cited in PR #136. Four distinct interop issues surfaced — strong evidence for the #171 trigger condition #3 ("a second consumer demonstrating need"):

# Where Layer Status
1 csapiCollections null-derefs when data is null instead of returning [] Library bug Filed: #188 — patched locally
2 collectionsUrl only accepts rel: "data"; rejects rel: "collections" (used by OpenSensorHub) Library compatibility gap Filed in #188 follow-up — patched locally
3 parseCollections only flags ogc-cs:* rels as CSAPI; ignores collection-level featureType Library / convention mismatch Filed in #188 follow-up
4 getCollectionDocument follows the collection's self link blindly without validating that the returned doc has the requested id Library could be more defensive (server is also wrong here) Filed in #188 follow-up

The bug pattern in (1) is shared by 5 sibling getters (recordCollections, featureCollections, edrCollections, vectorTileCollections, mapTileCollections) — same one-line fix applied by symmetry would harden all of them.

The two patches we apply locally to make the agent work end-to-end live in the snapshot at ~/Downloads/ogc-client-CSAPI_2-phase-7/src/ogc-api/endpoint.ts (lines 88–96 and 230–237). After patching, run npm run build in the snapshot root and the CLI's symlink picks up the rebuilt dist/ automatically.

Known limitations

  • Local snapshot dependency. The CLI links to a patched local snapshot of ogc-client-CSAPI_2 rather than the unpublished npm package. PR #136 has not landed; once it does (and incorporates the four fixes above), the snapshot can be replaced with npm install @camptocamp/ogc-client@dev.
  • Mock server only. The 52°North demo's /conformance is missing CSAPI URIs (server-side regression), and OpenSensorHub has its own bugs (issues 3 & 4 above). The mock at mock_server/server.py is the only currently working full-loop endpoint.
  • No SWE Common parsing. Observations are returned with their raw result field. The architecturally correct typed-extraction path is tracked at upstream issue #171; we will adopt it once shipped rather than build a heuristic in the agent layer.
  • One subprocess per tool call. ~1–2 s of Node startup per call. Fine for chat latency; if it becomes a bottleneck, the CLI could be promoted to a long-running HTTP service.

Project layout

csapi_agent/
├── __init__.py            # ADK package marker
├── agent.py               # LlmAgent definition + tool registration
├── csapi_tools.py         # 6 Python wrappers around the CLI
├── .env.example           # template for GOOGLE_API_KEY
├── csapi_cli/
│   ├── package.json       # links to local snapshot via file:
│   ├── cli.mjs            # Node entry point: 6 subcommands
│   └── node_modules/      # generated by npm install
└── mock_server/
    ├── requirements.txt   # fastapi, uvicorn
    └── server.py          # spec-shaped CSAPI mock on port 8765

About

Natural language OGC CSAPI agent using Google Gemini ADK and ogc-client library

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors