Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/basics/infrastructure.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ Summarize the external services Neural touches (REST, WebSocket, FIX), their lat

Latency reference: REST polling at 1s intervals, FIX round-trips ~5–10 ms, WebSocket delivers pushes \<100 ms once enabled.

## Deployment runtime model

- The OSS SDK includes a built-in Docker deployment provider.
- Additional runtimes can be loaded as provider plugins through `neural.deployment`.
- This enables private or environment-specific deployment backends without forking SDK APIs.

## Quick smoke tests

```bash
Expand Down Expand Up @@ -57,4 +63,4 @@ REST polling (baseline) ─┬─> Strategy / Aggregator ──> TradingClient
- Verify install & credentials: `getting-started`
- Review execution options: `trading/overview`
- Plan deployment workflows: `workflows/promotion-checklist`

- Build custom runtime integrations: `workflows/deployment-providers`
5 changes: 3 additions & 2 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@
"pages": [
"workflows/build-first-bot",
"workflows/promotion-checklist",
"workflows/data-pipeline"
"workflows/data-pipeline",
"workflows/deployment-providers"
]
},
{
Expand All @@ -120,4 +121,4 @@
"github": "https://github.com/IntelIP/Neural",
"twitter": "https://twitter.com/neural_sdk"
}
}
}
62 changes: 62 additions & 0 deletions docs/workflows/deployment-providers.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: 'Deployment Provider Plugins'
description: 'Extend Neural deployment with external provider plugins (for example, private Daytona runtimes).'
---

Neural ships with a built-in Docker deployment provider and a registry for loading external providers.
This lets you keep proprietary runtime logic outside the OSS SDK while using the same deployment interface.

## Built-in provider

```python
from neural.deployment import create_provider

docker = create_provider("docker")
```

The built-in `docker` provider maps to `DockerDeploymentProvider`.

## Register providers programmatically

```python
from neural.deployment import create_provider, register_provider
from neural.deployment.base import DeploymentProvider

class MyProvider(DeploymentProvider):
...

register_provider("my_provider", MyProvider)
provider = create_provider("my_provider")
```

If a provider name already exists, pass `replace=True` to overwrite it.

## Register providers via entry points

External packages can register providers with Python entry points:

```toml
[project.entry-points."neural.deployment.providers"]
daytona = "neural_daytona_runtime.provider:create_provider"
```

Neural auto-discovers this group and exposes the provider through `create_provider("daytona")`.

## Error behavior

- Unknown provider names raise `ProviderNotFoundError` with available providers listed.
- Plugins that fail to load raise `ProviderNotFoundError` with the plugin load error details.
- Factories that return non-`DeploymentProvider` objects raise `ConfigurationError`.

## Plugin authoring checklist

1. Implement `DeploymentProvider` methods: `deploy`, `status`, `logs`, `stop`, `list_deployments`, `cleanup`.
2. Keep secret loading in your provider package (not in SDK source).
3. Map runtime errors into Neural deployment exceptions with clear operator-facing messages.
4. Add unit tests for discovery and lifecycle methods.

## Next

- Production workflow progression: `workflows/promotion-checklist`
- Deployment and runtime dependencies: `basics/infrastructure`

9 changes: 9 additions & 0 deletions neural/auth/polymarket_us_env.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Helpers for resolving Polymarket US auth credentials from env/files."""

from __future__ import annotations

import base64
Expand All @@ -14,6 +16,7 @@


def _read_text_file(path: str | Path, label: str) -> str:
"""Read a UTF-8 secret file and return stripped text content."""
try:
return Path(path).read_text(encoding="utf-8").strip()
except FileNotFoundError:
Expand All @@ -23,6 +26,7 @@ def _read_text_file(path: str | Path, label: str) -> str:


def _read_bytes_file(path: str | Path, label: str) -> bytes:
"""Read a binary secret file."""
try:
return Path(path).read_bytes()
except FileNotFoundError:
Expand All @@ -32,10 +36,12 @@ def _read_bytes_file(path: str | Path, label: str) -> bytes:


def get_polymarket_us_base_url() -> str:
"""Return the normalized base API URL for Polymarket US."""
return os.getenv("POLYMARKET_US_API_URL", POLYMARKET_US_API_URL).rstrip("/")


def get_polymarket_us_api_key() -> str:
"""Resolve API key from env var first, then fallback secret file path."""
value = os.getenv("POLYMARKET_US_API_KEY")
if value:
return value
Expand All @@ -44,6 +50,7 @@ def get_polymarket_us_api_key() -> str:


def get_polymarket_us_passphrase() -> str:
"""Resolve API passphrase from env var first, then fallback secret file path."""
value = os.getenv("POLYMARKET_US_API_PASSPHRASE")
if value:
return value
Expand All @@ -52,6 +59,7 @@ def get_polymarket_us_passphrase() -> str:


def get_polymarket_us_api_secret() -> bytes:
"""Resolve API secret bytes from env vars or fallback secret file path."""
b64_value = os.getenv("POLYMARKET_US_API_SECRET_BASE64")
if b64_value:
return base64.b64decode(b64_value)
Expand All @@ -73,6 +81,7 @@ def get_polymarket_us_api_secret() -> bytes:


def get_polymarket_us_credentials() -> dict[str, object]:
"""Build full credential payload for signer initialization."""
return {
"api_key": get_polymarket_us_api_key(),
"api_secret": get_polymarket_us_api_secret(),
Expand Down
8 changes: 6 additions & 2 deletions neural/auth/signers/polymarket_us.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,16 @@ def headers(self, method: str, path: str, body: str = "") -> dict[str, str]:
}

@classmethod
def from_env(cls, values: dict[str, Any], now_ms: TimestampFn | None = None) -> PolymarketUSSigner:
def from_env(
cls, values: dict[str, Any], now_ms: TimestampFn | None = None
) -> PolymarketUSSigner:
api_key = values.get("api_key")
api_secret = values.get("api_secret")
passphrase = values.get("passphrase")
if api_key is None or api_secret is None or passphrase is None:
raise ValueError("Missing required Polymarket signer config: api_key, api_secret, passphrase")
raise ValueError(
"Missing required Polymarket signer config: api_key, api_secret, passphrase"
)

if isinstance(api_secret, str):
secret_bytes = api_secret.encode("utf-8")
Expand Down
69 changes: 60 additions & 9 deletions neural/deployment/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
```
"""

from typing import Any

# Core abstractions
from neural.deployment.base import DeploymentContext, DeploymentProvider

Expand All @@ -45,15 +47,6 @@
MonitoringConfig,
)

# Docker provider
from neural.deployment.docker import (
DockerDeploymentProvider,
render_compose_file,
render_dockerfile,
render_dockerignore,
write_compose_file,
)

# Exceptions
from neural.deployment.exceptions import (
ConfigurationError,
Expand All @@ -67,6 +60,57 @@
ProviderNotFoundError,
ResourceLimitExceededError,
)
from neural.deployment.registry import create_provider, list_providers, register_provider

_DOCKER_AVAILABLE = True
_DOCKER_IMPORT_ERROR: Exception | None = None

try:
# Docker provider
from neural.deployment.docker import (
DockerDeploymentProvider,
render_compose_file,
render_dockerfile,
render_dockerignore,
write_compose_file,
)
except Exception as exc: # pragma: no cover - depends on optional dependency presence
_DOCKER_AVAILABLE = False
_DOCKER_IMPORT_ERROR = exc

class DockerDeploymentProvider: # type: ignore[no-redef]
"""Placeholder that raises when Docker deployment extras are missing."""

def __init__(self, *args: Any, **kwargs: Any) -> None:
raise ProviderNotFoundError(
"Docker deployment provider is unavailable. "
"Install optional dependencies with: pip install 'neural-sdk[deployment]'"
) from _DOCKER_IMPORT_ERROR

def render_compose_file(*args: Any, **kwargs: Any) -> str:
raise ProviderNotFoundError(
"Docker compose rendering is unavailable. "
"Install optional dependencies with: pip install 'neural-sdk[deployment]'"
) from _DOCKER_IMPORT_ERROR

def render_dockerfile(*args: Any, **kwargs: Any) -> str:
raise ProviderNotFoundError(
"Dockerfile rendering is unavailable. "
"Install optional dependencies with: pip install 'neural-sdk[deployment]'"
) from _DOCKER_IMPORT_ERROR

def render_dockerignore() -> str:
raise ProviderNotFoundError(
"Docker ignore rendering is unavailable. "
"Install optional dependencies with: pip install 'neural-sdk[deployment]'"
) from _DOCKER_IMPORT_ERROR

def write_compose_file(*args: Any, **kwargs: Any) -> Any:
raise ProviderNotFoundError(
"Docker compose writing is unavailable. "
"Install optional dependencies with: pip install 'neural-sdk[deployment]'"
) from _DOCKER_IMPORT_ERROR


__all__ = [
# Core abstractions
Expand All @@ -83,6 +127,9 @@
"DeploymentInfo",
# Providers
"DockerDeploymentProvider",
"register_provider",
"create_provider",
"list_providers",
# Docker utilities
"render_dockerfile",
"render_dockerignore",
Expand All @@ -101,6 +148,10 @@
"MonitoringError",
]

# Register built-in providers so callers can use create_provider("docker", ...).
if _DOCKER_AVAILABLE:
register_provider("docker", DockerDeploymentProvider, replace=True)


# Convenience function for deploying with context manager
def deploy(
Expand Down
Loading
Loading