Metadata-Version: 2.4
Name: opengeolab-geocopilot
Version: 0.4.10
Summary: A Codex-powered, notebook-native general agent for JupyterLab
Author: OpenGMS Team
License: MIT
License-File: LICENSE
Keywords: agent,codex,geospatial,jupyterlab,opengms
Classifier: Framework :: Jupyter
Classifier: Framework :: Jupyter :: JupyterLab
Classifier: Framework :: Jupyter :: JupyterLab :: 4
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: fastmcp<4,>=3
Requires-Dist: jupyter-server-documents==0.3.1
Requires-Dist: jupyter-server-mcp==0.2.1
Requires-Dist: jupyter-server<3,>=2.4
Requires-Dist: jupyterlab<4.6,>=4.5
Requires-Dist: mcp<2,>=1.0
Requires-Dist: nbformat<6,>=5.10
Requires-Dist: pygeomodel<2,>=1.0.16
Requires-Dist: tomli-w<2,>=1.0
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Requires-Dist: types-tornado>=5.1.1; extra == 'dev'
Provides-Extra: test
Requires-Dist: coverage[toml]>=7.6; extra == 'test'
Requires-Dist: ipykernel>=6.29; extra == 'test'
Requires-Dist: jsonschema>=4.23; extra == 'test'
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
Requires-Dist: pytest-cov>=5; extra == 'test'
Requires-Dist: pytest-jupyter>=0.10; extra == 'test'
Requires-Dist: pytest>=8.2; extra == 'test'
Description-Content-Type: text/markdown

# GeoCopilot 0.4.10

GeoCopilot is a notebook-native, Codex-powered general agent embedded in
JupyterLab. It keeps Codex's native shell and file capabilities, adds
revision-safe notebook tools through Jupyter MCP, and makes OpenGMS resources
available as a standard Codex skill.

This is a clean 1.0 implementation. The previous 0.x plugin is not a dependency
and none of its intent routing or browser-executed task machinery is used here.

## Product guarantees

- One persistent Codex thread and at most one active turn for each Jupyter user.
- One user message maps directly to one `turn/start`; there is no classifier call.
- Native Codex shell, file editing, search, Git, and patch capabilities remain available.
- Notebook operations use root-safe paths, stable cell IDs, YDocs, source hashes,
  revisions, and server-side kernels.
- Browser disconnects do not own or cancel the active turn.
- OpenGMS capability selection is made by Codex from the Skill description, not
  by keywords, regular expressions, or a host-side router.
- There is no read-only mode or per-command approval UI. Production safety comes
  from the isolated, non-root, per-user container.

## Development

Requirements:

- Python 3.10–3.13
- JupyterLab 4.5.x
- Node.js 20 LTS
- Codex CLI 0.145.0

```bash
python -m pip install -e ".[test,dev]"
npm install
npm run build
jupyter lab
```

Run the verification suite:

```bash
pytest
npm run lint
npm run build:prod
```

The right sidebar contains one persistent conversation. While a turn is
running, new input is disabled and the turn can be interrupted with **Stop turn**.
Closing the browser does not stop the server-side turn.

## Notebook execution and observation

Notebook work follows the implementation patterns used by current Jupyter
agents rather than a separate GeoCopilot task router:

- [Notebook Intelligence](https://github.com/plmbr/notebook-intelligence)
  provides the exploratory-versus-construction workflow baseline.
- [Jupyter AI Jupyternaut](https://github.com/jupyter-ai-contrib/jupyter-ai-jupyternaut)
  provides the execute, inspect, repair, and bounded-retry behavior.
- [Jupyter AI Tools](https://github.com/jupyter-ai-contrib/jupyter-ai-tools)
  and [Datalayer Jupyter MCP Server](https://github.com/datalayer/jupyter-mcp-server)
  provide the output-fidelity and native MCP `ImageContent` patterns.

`notebook.run_cell` returns one MCP result containing structured stdout,
stderr, errors, MIME metadata, execution timing, and up to three raster outputs
as native image blocks. Kernel completion is therefore an execution fact, not
an automatic claim that the scientific or visual result is valid. Codex
examines the returned evidence in the same turn and decides whether to
continue, repair, or ask the user.

Kernel awareness remains notebook-scoped and server-side:

- `notebook.kernel_status` reports the notebook session, kernel identity,
  execution state, connections, and last activity without starting a kernel.
- `notebook.list_variables` performs a private, history-free kernel probe and
  returns bounded variable metadata such as type, shape, dtype, columns, and
  CRS. It does not serialize complete in-memory objects.
- `notebook.interrupt_kernel` interrupts a live notebook kernel.
- `notebook.restart_kernel` restarts the path-specific kernel and explicitly
  reports that memory-resident state has been cleared.

These tools follow the server-side kernel-management pattern used by Datalayer
Jupyter MCP Server. Cell execution also interrupts the kernel when its timeout
is reached, instead of leaving an orphaned computation running.

## Runtime model

Production deployments run one non-root Jupyter Server container per user.
GeoCopilot starts one private `codex app-server` process over stdio, uses the
Jupyter Server root as its working directory, and runs with full filesystem
access inside that isolated container.

On Windows only, Jupyter Server uses an event loop that cannot create asyncio
subprocess transports. GeoCopilot therefore runs the original asyncio App Server
transport on a private Proactor event loop in one background thread; its messages
are queued to Jupyter's main event loop. macOS and Linux retain their native
asyncio subprocess transport. GeoCopilot never alters Jupyter's global event-loop
policy.

For a custom Base URL on Windows, GeoCopilot requires Codex CLI 0.145.0 or
newer. Earlier CLI builds can accept a turn but fail to advance a custom
Responses-provider request. GeoCopilot checks this before starting the App
Server and reports a clear configuration error instead of leaving a turn active.

For Windows diagnostics, GeoCopilot records only bounded JSON-RPC metadata
(direction, method, request ID, and timestamp), plus stderr line counts; it never
records prompts, API keys, or raw request payloads. While a Windows turn is fresh,
it also delays fallback `thread/read` reconciliation so status polling cannot
interfere with an active App Server turn. If Codex emits no model event after the
user message, the panel displays a diagnostic ID instead of only an indefinite
working indicator.

API keys are write-only in the UI and are stored outside the Jupyter workspace.
No prompt classifier or keyword-based skill router exists in this project.
When a custom Base URL is configured, GeoCopilot defines a dedicated Codex
model provider with `env_key = "OPENAI_API_KEY"` and
`wire_api = "responses"`. Its isolated configuration also disables Codex's
experimental `multi_agent_v2` scheduler, which has an upstream incompatibility
with custom Responses providers on Windows. This avoids mixing third-party
endpoint credentials with Codex's built-in OpenAI authentication state.

The extension uses these fixed runtime defaults:

```toml
approval_policy = "never"
sandbox_mode = "danger-full-access"
```

JupyterLab is currently constrained to 4.5.x because the fixed
`jupyter-server-documents==0.3.1` frontend packages require JupyterLab 4.5 and
target `@jupyter/ydoc` 3.x. The bounds prevent pip from producing incompatible
JupyterLab 4.4 or 4.6 environments; they can be lifted when that upstream stack
publishes a compatible release.

The Codex working directory is always the Jupyter Server `root_dir`. Settings
are saved under Jupyter's per-user config/data directories, while user notebooks
and data remain in the workspace.

## OpenGMS resources

Model-service code uses `PyGeoModel>=1.0.16,<2` directly. The data-processing
method client contains the internal production service address and token from
the Method Library specification, so it works without deployment environment
variables. Explicit constructor arguments remain available for tests.

The two platform Skills live in `geocopilot/skills/opengms-model-services` and
`geocopilot/skills/opengms-data-methods`. Production images also install them
under `/etc/codex/skills`. At local startup GeoCopilot copies the packaged
Skills into its private `CODEX_HOME` and verifies them through Codex
`skills/list`; startup fails clearly rather than silently running without the
resource capabilities. Users can also install their own Skills under
`~/.agents/skills`.

## Container

Build the non-root single-user image from the repository root:

```bash
docker build -f docker/Dockerfile -t opengeolab/geocopilot:0.4.10 .
```

The image pins Codex CLI 0.145.0, JupyterLab 4.5.10, and Notebook 7.5.7,
exposes Jupyter on port 8888, and uses `/home/jovyan/work` as both the mounted
workspace and `ServerApp.root_dir`.

## Protocol compatibility

The generated Codex App Server schemas for 0.145.0 are checked into
`schema/codex-0.145.0`. Regenerate them before any Codex upgrade and run the
contract suite:

```bash
scripts/regenerate_codex_schema.sh
pytest tests/test_contracts.py
```

`jupyter-server-mcp==0.2.1` exposes Streamable HTTP but does not ship the
stdio proxy present on its unreleased development branch. GeoCopilot therefore
connects Codex directly to `http://127.0.0.1:3001/mcp`; the port remains private
inside each single-user container. Override it with `GEOCOPILOT_MCP_URL` only
when the matching Jupyter MCP port is changed.
