Skip to content

Migrate Edge Configuration to SDK#413

Open
timmarkhuff wants to merge 21 commits intomainfrom
tim/edge-config
Open

Migrate Edge Configuration to SDK#413
timmarkhuff wants to merge 21 commits intomainfrom
tim/edge-config

Conversation

@timmarkhuff
Copy link
Contributor

@timmarkhuff timmarkhuff commented Mar 12, 2026

Moves the edge endpoint config schema from edge-endpoint into the Python SDK so users can programmatically build and validate edge configurations.

What's new

  • New groundlight.edge submodule with Pydantic models ported from edge-endpoint/app/core/configs.py:
    • EdgeEndpointConfig -- top-level config (includes global_config) with ergonomic add_detector() support
    • DetectorsConfig -- detector-scoped config model for detector-only workflows
    • InferenceConfig -- per-detector inference behavior (frozen/immutable)
    • GlobalConfig, DetectorConfig -- supporting models
  • Preset constants aligned with edge-endpoint defaults:
    • DEFAULT
    • EDGE_ANSWERS_WITH_ESCALATION
    • NO_CLOUD
    • DISABLED
  • Validation parity preserved:
    • disable_cloud_escalation requires always_return_edge_prediction=True
    • duplicate detector ID checks
    • detector config cross-reference checks (detectors[*].edge_inference_config must exist in edge_inference_configs)

Usage

from groundlight.edge import (
    DEFAULT,
    EDGE_ANSWERS_WITH_ESCALATION,
    GlobalConfig,
    NO_CLOUD,
    EdgeEndpointConfig,
    DetectorsConfig,
)

# Path 1: Build a full edge endpoint config
full_config = EdgeEndpointConfig(
    global_config=GlobalConfig(
        refresh_rate=30.0,
        confident_audit_rate=0.0,
    )
)
full_config.add_detector("det_abc123", NO_CLOUD)
full_config.add_detector("det_def456", DEFAULT)

# Path 2: Build detector-only changes
detectors_config = DetectorsConfig()
detectors_config.add_detector("det_abc123", NO_CLOUD)
detectors_config.add_detector("det_xyz789", EDGE_ANSWERS_WITH_ESCALATION)

Design decisions

  • InferenceConfig is frozen to prevent accidental mutation of shared preset objects.
  • add_detector() accepts either a detector ID string or a Detector object (consistent with existing SDK ergonomics).
  • Inference configs are auto-registered on first use via add_detector(); no separate registration step is needed.
  • EdgeEndpointConfig composes DetectorsConfig and delegates detector mutations through add_detector().
  • DetectorsConfig.to_payload() provides explicit detector-scoped wire serialization for future HTTP use.
  • Serialization matches the edge-endpoint YAML shape (detectors as a list, edge_inference_configs as a dict keyed by config name).
  • name on InferenceConfig is excluded from serialization because it is represented as the dict key.

Quality and tests

  • Added focused unit tests for edge config behavior in test/unit/test_edge_config.py, including:
    • duplicate detector and inference-config collision behavior
    • add_detector() duplicate detector ID rejection
    • constructor-time rejection of undefined edge_inference_config references
    • acceptance of value-equivalent named InferenceConfig objects
    • InferenceConfig validation constraints
    • DetectorsConfig.to_payload() payload shape
    • flattened EdgeEndpointConfig.model_dump() payload shape

Follow-up work

  • Update edge-endpoint to import these models from the Python SDK instead of defining them locally.
  • Add edge-endpoint runtime config API (proposed names):
    • POST /set-edge-config (full config replace)
    • GET /edge-config (get current active config)
    • detector-scoped endpoint(s), likely one of:
      • POST /set-edge-detectors with mode replace|merge
      • or separate add/remove detector operations
  • Add SDK methods (proposed names) that wrap those APIs:
    • set_edge_endpoint_config(config, *, timeout_s=...)
    • get_edge_endpoint_config()
    • set_edge_endpoint_detectors(detectors, *, mode="replace"|"merge", timeout_s=...)
    • optional: remove_edge_endpoint_detectors(detector_ids, *, timeout_s=...)
  • Implement retry behavior in SDK for "endpoint busy" responses (bounded exponential backoff + timeout budget).

@@ -0,0 +1,41 @@
"""Example of constructing an edge endpoint configuration programmatically."""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is temporary, I'll get rid of this before merging.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Getting rid of it is too easy, grab the most important snippets and put them in docs in a md file, we auto push those to a webpage

Copy link
Collaborator

@brandon-wada brandon-wada left a comment

Choose a reason for hiding this comment

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

This looks good so far, we should discuss more what the calls to update the config on the remote machine should look like

@@ -0,0 +1,41 @@
"""Example of constructing an edge endpoint configuration programmatically."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Getting rid of it is too easy, grab the most important snippets and put them in docs in a md file, we auto push those to a webpage

RootEdgeConfig,
)

__all__ = [
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit, this is a little redundant since it includes all objects that could be importet

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ChatGPT says: "good point. all is kept intentionally to make the public API explicit/stable for this new module (and to control wildcard-import surface), but it can be removed if repo convention prefers omitting it."

I'm not really sure which way is best...

Tim Huff and others added 3 commits March 17, 2026 10:55
Resolve the merge conflict in test_edge_config and preserve current edge config tests.

Made-with: Cursor
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