Skip to content

[db-executable-env] Phase 2: DatabaseExecutableEnvironment + tool + connection-config skeleton#2468

Draft
aniruddh-alt wants to merge 3 commits into
aniruddh-alt/db-executable-env-trunkfrom
aniruddh-alt/db-executable-env-02-database-skeleton
Draft

[db-executable-env] Phase 2: DatabaseExecutableEnvironment + tool + connection-config skeleton#2468
aniruddh-alt wants to merge 3 commits into
aniruddh-alt/db-executable-env-trunkfrom
aniruddh-alt/db-executable-env-02-database-skeleton

Conversation

@aniruddh-alt

Copy link
Copy Markdown
Contributor

Description

Phase 2 of the db-executable-env phase chain, target branch: aniruddh-alt/db-executable-env-trunk.

What changed: Adds the skeleton for the first concrete ExecutableEnvironment transport — DatabaseExecutableEnvironment, DatabaseExecutableTool, and DatabaseConnectionConfig. Registers env_type: database in the env registry.

Why: The abstract base from Phase 1 needs a first consumer to validate the shape. The database transport is the highest-value first target — it exercises the hardest concerns (pooling, dialect differences, error wrapping) and is the basis for the EHR DB example. The full implementation is large; this PR ships only the type surface so reviewers can sign off on the shape before engine wiring lands.

Phase chain context

  • Feature trunk: aniruddh-alt/db-executable-env-trunk
  • Phases merged into trunk: (none yet)
  • Sibling open phase: [db-executable-env] Phase 1: ExecutableEnvironment + ExecutableTool skeleton #2467 (Phase 1 — Executable base skeleton). This PR is branched off Phase 1 so the abstract-base imports resolve; will rebase onto the trunk once Phase 1 merges. ⚠️ Phase 1 should land first.
  • This phase: 2 (Database executable skeleton)
  • Phases remaining: 3+ TBD (engine + dialect guards + autocommit checkout, error auto-wrap + audit, postgres integration tests, EHR example + e2e)

What's in this PR (456 lines)

File Purpose
src/oumi/core/configs/params/database_connection_params.py DatabaseConnectionConfig — fields for structured mode (driver / host / port / database / username / password_env_var) and DSN mode (dsn_env_var), mutually exclusive. Pool sizing and connect_timeout_s validation. resolve_url() is deferred to the implementation phase (SQLAlchemy dep arrives then).
src/oumi/environments/database_executable_tool.py Full small dataclass — adds optional statement_timeout_ms. Env-side cross-validation against env-level timeout lives on the env (next phase).
src/oumi/environments/database_executable_environment.py Skeleton — @register_environment("database"), _executor_context_kwarg = "db", tool_params_cls = DatabaseExecutableTool. from_params and _build_execution_context raise NotImplementedError until the engine phase. DatabaseExecutableEnvironmentKwargs carries connection, read_only, statement_timeout_ms, audit.
src/oumi/environments/__init__.py Exports the new types.
tests/unit/environments/test_database_executable_tool.py Inherits executor requirement; carries statement_timeout_ms; create() round-trip.
tests/unit/environments/test_database_executable_environment.py _executor_context_kwarg == "db"; from_params raises NotImplementedError; Kwargs rejects missing connection and non-positive timeout; connection dict coercion works.
tests/unit/core/configs/params/test_database_connection_params.py Structured-XOR-DSN, pool bounds, connect_timeout_s bounds.

Why a skeleton phase

This PR adds no runtime dependencies (no sqlalchemy). The skeleton declares the type surface and registers the env type so downstream config code can reference it; the actual engine wiring + dialect guards + error wrapping land in the next phase along with the SQLAlchemy dep.

Each piece has been pre-validated for issues flagged on #2441:

  • DatabaseConnectionConfig mode XOR is enforced at finalize_and_validate time.
  • Kwargs.statement_timeout_ms rejects non-positive values (one of the liberate-bot HIGH-priority findings on feat(environments): add DatabaseExecutableEnvironment #2441 — a per-tool 0 silently disabling the Postgres timeout). The per-tool side of the same validation lives on DatabaseExecutableTool and the env's _validate_tools in the implementation phase.

Related issues

(No associated issue — direct continuation of the work that lived in PR #2441.)

Before submitting

  • Did you add / update tests where needed?
  • Did you run the local test suite? pytest tests/unit/environments/ tests/unit/core/configs/ — 1337 passing on this branch.

Abstract base for envs that run user-supplied dotted-path executors.
Subclasses provide the per-call execution context (DB conn, HTTP client,
FS root, ...) via _build_execution_context. The base owns batch step()
dispatch to _step_one, the _absorb_result post-hook, and the close
lifecycle.

This phase ships the skeleton: class shape, batch step() dispatch, and
abstract _build_execution_context hook. Concrete _step_one (executor
resolution, ToolResult validation, output_schema validation,
_absorb_result invocation) lands in a follow-on phase.

ExecutableTool is a small ToolParams subclass enforcing a non-empty
executor dotted path.

First phase of the db-executable-env trunk chain; targets the trunk
branch, will integrate to main with the rest of the feature.
…tion-config skeleton

Skeleton for the first concrete ExecutableEnvironment transport. Three new
units land here:

- DatabaseConnectionConfig (src/oumi/core/configs/params/) — structured-vs-DSN
  XOR validation, pool / timeout numeric bounds, password-via-env-var hygiene.
  resolve_url() is deferred to the implementation phase (the SQLAlchemy
  dependency lands then).

- DatabaseExecutableTool (src/oumi/environments/) — full small dataclass.
  Adds optional statement_timeout_ms; env-side cross-validation against the
  env-level timeout lives on the env (implementation phase).

- DatabaseExecutableEnvironment (src/oumi/environments/) — skeleton class
  registered as env_type "database". from_params and _build_execution_context
  raise NotImplementedError until the implementation phase wires the
  SQLAlchemy engine, dialect guards (Postgres / MySQL / SQLite read-only +
  statement_timeout), DBAPIError auto-wrap, and audit logging.

Branched off Phase 1 so the abstract base imports resolve; will rebase onto
the trunk once Phase 1 (#2467) merges.
@gitar-bot

gitar-bot Bot commented May 20, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

Strips "skeleton phase", "arrives in a later phase", and forward-reference
phrasing from docstrings and NotImplementedError messages across the
executable + database executable skeletons. Also drops the @contextmanager
wrapper on the not-yet-implemented _build_execution_context since it raises
unconditionally — the return-type annotation alone satisfies the abstract
contract.

The same edits to executable_environment.py / executable_tool.py /
test_executable_environment.py mirror the cleanup landed on Phase 1's
branch; rebasing onto trunk later will collapse them to no-ops.


def test_tool_params_cls_is_database_executable_tool():
"""The env binds to ``DatabaseExecutableTool``."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phrase "binds to" is a bit confusing here. It reads like the env owns a DatabaseExecutableTool (an instance relationship), when envs actually owns tools (from what I understand from our discussions)



def test_default_tool_params_cls_is_executable_tool():
"""ExecutableEnvironment binds to ExecutableTool by default."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants