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
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ event_bus:

config:
segmentation_model_key:
description: "Model key to use for segmentation (must be in AdapterInferenceBridge config)."
default: "qwen3-coder"
description: "Logical route key to use for segmentation (must be in AdapterInferenceBridge config)."
default: "adr_segmentation"
segmentation_temperature:
description: "Temperature for the segmentation LLM call."
default: 0.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ class HandlerSegmentation:
def __init__(
self,
inference_bridge: ModelInferenceAdapter | None = None,
segmentation_model_key: str = "qwen3-coder",
segmentation_model_key: str = "adr_segmentation",
segmentation_temperature: float = 0.1,
segmentation_timeout_seconds: float = 120.0,
low_confidence_threshold: float = 0.4,
Expand Down Expand Up @@ -360,7 +360,7 @@ def from_contract(cls, contract: dict[str, Any]) -> HandlerSegmentation:
cfg = contract.get("config", {})
return cls(
segmentation_model_key=str(
cfg.get("segmentation_model_key", {}).get("default", "qwen3-coder")
cfg.get("segmentation_model_key", {}).get("default", "adr_segmentation")
),
segmentation_temperature=float(
cfg.get("segmentation_temperature", {}).get("default", 0.1)
Expand Down
14 changes: 7 additions & 7 deletions src/omnimarket/nodes/node_ci_fix_effect/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ node_version: {major: 1, minor: 0, patch: 0}

description: >
LLM-routed CI fix effect. Receives a ModelCiFixCommand, uses the routing
policy's primary model (deepseek-r1-14b) to diagnose the failing CI job and
generate a patch. Applies the patch locally and re-runs tests as a gate.
policy's primary logical route to diagnose the failing CI job and generate a
patch. Applies the patch locally and re-runs tests as a gate.
Scaffold only — real LLM + patch logic lands in OMN-8994 (Wave 2).

handler:
Expand All @@ -31,8 +31,8 @@ descriptor:

model_routing:
ci_fixer:
primary: "deepseek-r1-14b"
fallback: "qwen3-coder-30b"
primary: "ci_fixer_primary"
fallback: "ci_fixer_fallback"
fallback_allowed_roles:
- "ci_fixer"
max_tokens: 2048
Expand All @@ -46,16 +46,16 @@ model_routing:
# vars at load time. Operators MUST configure LLM_CODER_FAST_URL /
# LLM_CODER_URL (and matching *_MODEL_NAME) for this node to function;
# the handler fails loud at contract load when an env var is unset.
deepseek-r1-14b:
ci_fixer_primary:
base_url_env: LLM_CODER_FAST_URL
model_id_env: LLM_CODER_FAST_MODEL_NAME
timeout_seconds: 120.0
qwen3-coder-30b:
ci_fixer_fallback:
base_url_env: LLM_CODER_URL
model_id_env: LLM_CODER_MODEL_NAME
timeout_seconds: 120.0
ci_override:
primary: "deepseek-r1-14b"
primary: "ci_fixer_primary"

event_bus:
consumer_group: omnimarket.ci_fix_effect.consume.v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# SPDX-License-Identifier: MIT
"""Handler for node_ci_fix_effect [OMN-8994].

EFFECT node. Receives ModelCiFixCommand, fetches failing CI log, routes to LLM
(deepseek-r1-14b primary), parses unified diff, applies patch, runs test gate.
Model routing: primary=deepseek-r1-14b, fallback=qwen3-coder-30b per contract.yaml.
EFFECT node. Receives ModelCiFixCommand, fetches failing CI log, routes to the
logical LLM route selected by policy, parses unified diff, applies patch, and
runs the test gate.
"""

from __future__ import annotations
Expand Down
8 changes: 4 additions & 4 deletions src/omnimarket/nodes/node_conflict_hunk_effect/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ node_version: {major: 1, minor: 0, patch: 0}
description: >
LLM-routed conflict resolution effect. Receives a ModelConflictHunkCommand,
creates an ephemeral git worktree, scans for conflict markers, resolves each hunk
via LLM (qwen3-coder-30b primary, glm-4.5 fallback), validates the patch, commits,
via logical LLM routing, validates the patch, commits,
and emits ModelConflictResolvedEvent. Branch guard prevents pushing to main/master/develop.
pytest gate runs in worktree before commit. No shell=True anywhere.

Expand All @@ -32,15 +32,15 @@ descriptor:

model_routing:
conflict_resolver:
primary: "qwen3-coder-30b"
fallback: "glm-4.5"
primary: "conflict_resolver_primary"
fallback: "conflict_resolver_fallback"
fallback_allowed_roles:
- "conflict_resolver"
endpoint_env: "LLM_CODER_URL"
max_tokens: 8192
transport: "http"
ci_override:
primary: "qwen3-coder-30b"
primary: "conflict_resolver_primary"

event_bus:
consumer_group: omnimarket.conflict_hunk_effect.consume.v1
Expand Down
9 changes: 7 additions & 2 deletions src/omnimarket/nodes/node_generation_consumer/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ event_bus:
model_routing:
provider: local
endpoint_env: LLM_CODER_URL
model_id: "Qwen/Qwen3-Coder-480B-A35B-Instruct"
served_model_id_env: LLM_CODER_MODEL_NAME
auth:
shared_secret_env: LOCAL_LLM_SHARED_SECRET
cidr_allowlist_env: LLM_ENDPOINT_CIDR_ALLOWLIST
Expand All @@ -81,7 +81,12 @@ dependencies:
- name: llm_coder_url
type: environment
key: LLM_CODER_URL
description: "Base URL for the Qwen3-Coder LLM endpoint — set via overlay from Infisical"
description: "Base URL for the generation LLM endpoint — set via overlay from Infisical"
required: true
- name: llm_coder_model_name
type: environment
key: LLM_CODER_MODEL_NAME
description: "Served model ID for the generation LLM endpoint — set via overlay from Infisical"
required: true
- name: llm_shared_secret
type: environment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,9 @@
"output_model",
]

_DEFAULT_MODEL_ID = "Qwen/Qwen3-Coder-480B-A35B-Instruct"

# Contract model_routing keys — resolved at construction from contract.yaml
_MODEL_ROUTING_ENDPOINT_ENV_KEY = "endpoint_env"
_MODEL_ROUTING_MODEL_ID_KEY = "model_id"
_MODEL_ROUTING_MODEL_ID_ENV_KEY = "served_model_id_env"

_DEFAULT_SYSTEM_PROMPT = (
"You are an ONEX node generator. Generate a valid ONEX contract.yaml and Python handler.\n"
Expand Down Expand Up @@ -240,9 +238,23 @@ def __init__(
self._endpoint_env: str = model_routing.get(
_MODEL_ROUTING_ENDPOINT_ENV_KEY, "LLM_CODER_URL"
)
self._model_id: str = model_routing.get(
_MODEL_ROUTING_MODEL_ID_KEY, _DEFAULT_MODEL_ID
self._model_id_env: str = str(
model_routing.get(_MODEL_ROUTING_MODEL_ID_ENV_KEY, "")
)
if not self._model_id_env:
raise ValueError(
"contract.yaml model_routing.served_model_id_env is required; "
"served model IDs must come from overlays, not handler defaults"
)

def _resolve_model_id(self) -> str:
model_id = os.environ.get(self._model_id_env, "").strip()
if not model_id:
raise RuntimeError(
f"{self._model_id_env} is unset/empty; served model ID must be "
"provided by the runtime overlay"
)
return model_id

def _ensure_effect(self) -> None:
if self._effect is not None:
Expand Down Expand Up @@ -296,7 +308,7 @@ async def _call_llm(
request = ModelLlmInferenceRequest(
base_url=endpoint,
operation_type=EnumLlmOperationType.CHAT_COMPLETION,
model=self._model_id,
model=self._resolve_model_id(),
messages=(
{"role": "system", "content": _DEFAULT_SYSTEM_PROMPT},
{"role": "user", "content": user_content},
Expand All @@ -318,7 +330,9 @@ async def handle(
# Derive metadata from contract-resolved routing config.
# endpoint_env is always LLM_CODER_URL (or whatever the contract declares);
# "local" provider means no per-token cost.
model_id = self._model_id
model_id = (
"injected_effect" if self._injected_effect else self._resolve_model_id()
)
provider = "local"
endpoint_class = "local"

Expand Down
3 changes: 1 addition & 2 deletions src/omnimarket/nodes/node_hostile_reviewer/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,7 @@ model_routing:
config:
openrouter_base_url:
env_var: "OPENROUTER_BASE_URL"
default: "https://openrouter.ai/api"
description: "Base URL for OpenRouter API. Override for testing or proxy routing."
description: "Optional API base URL supplied by runtime overlay for testing or proxy routing."
required: false

dependencies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ handler_routing:
# === CONFIGURATION FIELDS ===
config_fields:
KREUZBERG_URL:
default: "http://localhost:8090"
required: true
description: "Base URL of the kreuzberg Docker service"
KREUZBERG_TEXT_STORE_PATH:
required: true
Expand Down
6 changes: 3 additions & 3 deletions src/omnimarket/nodes/node_local_supervisor/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ descriptor:
- effects

model_routing:
primary: qwen3-coder-30b
fallback: claude-sonnet
primary: local_supervisor_primary
fallback: local_supervisor_fallback
timeout_per_attempt_s: 60
max_retries: 3
reason_for_fallback: "local timeout or unavailable"
Expand All @@ -56,7 +56,7 @@ model_routing:
inputs:
routing_decision:
type: object
description: "Pre-made routing decision: model_key, endpoint_url, role, correlation_id"
description: "Pre-made routing decision: logical_model_key, endpoint_ref, role, correlation_id"
required: true
prompt:
type: str
Expand Down
2 changes: 1 addition & 1 deletion src/omnimarket/nodes/node_projection_savings/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ event_bus:

metadata:
transport_type: kafka
delegate_skill_baseline_model: claude-opus-4-6
delegate_skill_baseline_model_source: pricing_manifest
14 changes: 7 additions & 7 deletions src/omnimarket/nodes/node_thread_reply_effect/contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ handler:
env_dependencies:
LLM_CODER_URL:
required: false
description: "vLLM Qwen3-Coder-30B endpoint URL (primary model)"
description: "Primary thread-reply endpoint URL supplied by runtime overlay"
LLM_GLM_URL:
required: false
description: "GLM cloud API base URL (fallback model)"
description: "Fallback thread-reply endpoint URL supplied by runtime overlay"
LLM_CODER_FAST_URL:
required: false
description: "vLLM fast model endpoint URL (secondary local option)"
Expand All @@ -45,13 +45,13 @@ descriptor:
- effects

model_routing:
primary: qwen3-coder-30b
fallback: glm-4.5
primary: thread_replier_primary
fallback: thread_replier_fallback
fallback_allowed_roles:
- thread_replier
max_tokens: 2048
ci_override:
primary: qwen3-coder-30b
primary: thread_replier_primary

inputs:
correlation_id:
Expand Down Expand Up @@ -115,10 +115,10 @@ metadata:

config:
LLM_CODER_URL:
description: "Qwen3-Coder endpoint URL (primary model)."
description: "Primary thread-reply endpoint URL."
required: false
LLM_GLM_URL:
description: "GLM cloud API base URL (fallback model)."
description: "Fallback thread-reply endpoint URL."
required: false
LLM_CODER_FAST_URL:
description: "Fast model endpoint URL."
Expand Down
2 changes: 1 addition & 1 deletion tests/nodes/node_ci_fix_effect/test_handler_ci_fix.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,6 @@ def test_load_contract_succeeds_with_env_vars_set(
monkeypatch.setenv("LLM_CODER_URL", "http://test-coder:8000")
monkeypatch.setenv("LLM_CODER_MODEL_NAME", "test-qwen3-coder-30b")
cfg = _load_contract_routing_config()
endpoint = cfg.model_endpoints["deepseek-r1-14b"]
endpoint = cfg.model_endpoints["ci_fixer_primary"]
assert endpoint.base_url == "http://test-fast:8001"
assert endpoint.model_id == "test-deepseek-r1-distill-14b"
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ def _failing_publisher(topic: str, payload: bytes) -> None:

@pytest.mark.unit
def test_handler_reads_endpoint_env_from_contract_model_routing(tmp_path: Path) -> None:
"""Handler must derive endpoint_env from contract.yaml model_routing section."""
"""Handler must derive runtime env names from contract.yaml model_routing."""
contract = {
"name": "node_generation_consumer",
"contract_version": {"major": 1, "minor": 0, "patch": 0},
Expand All @@ -468,7 +468,7 @@ def test_handler_reads_endpoint_env_from_contract_model_routing(tmp_path: Path)
"event_bus": {"publish_topics": [], "subscribe_topics": []},
"model_routing": {
"endpoint_env": "LLM_CODER_URL",
"model_id": "Qwen/Qwen3-Coder-480B-A35B-Instruct",
"served_model_id_env": "LLM_CODER_MODEL_NAME",
},
}
contract_path = tmp_path / "contract.yaml"
Expand All @@ -480,14 +480,14 @@ def test_handler_reads_endpoint_env_from_contract_model_routing(tmp_path: Path)
)

assert handler._endpoint_env == "LLM_CODER_URL"
assert "Qwen3-Coder" in handler._model_id
assert handler._model_id_env == "LLM_CODER_MODEL_NAME"


@pytest.mark.unit
def test_handler_falls_back_to_llm_coder_url_when_model_routing_absent(
def test_handler_rejects_contract_without_served_model_id_env(
tmp_path: Path,
) -> None:
"""When contract has no model_routing section, handler defaults to LLM_CODER_URL."""
"""The handler must not silently supply a served model ID default."""
contract = {
"name": "node_generation_consumer",
"contract_version": {"major": 1, "minor": 0, "patch": 0},
Expand All @@ -498,12 +498,11 @@ def test_handler_falls_back_to_llm_coder_url_when_model_routing_absent(
contract_path = tmp_path / "contract.yaml"
contract_path.write_text(yaml.dump(contract))

handler = HandlerGenerationConsumer(
effect_handler=FakeLlmEffect([_VALID_LLM_RESPONSE]),
contract_path=contract_path,
)

assert handler._endpoint_env == "LLM_CODER_URL"
with pytest.raises(ValueError, match="served_model_id_env is required"):
HandlerGenerationConsumer(
effect_handler=FakeLlmEffect([_VALID_LLM_RESPONSE]),
contract_path=contract_path,
)


@pytest.mark.unit
Expand All @@ -521,6 +520,11 @@ def test_production_contract_declares_llm_coder_url_endpoint_env() -> None:
"contract.yaml model_routing.endpoint_env must be 'LLM_CODER_URL'; "
f"got: {model_routing.get('endpoint_env')!r}"
)
assert model_routing.get("served_model_id_env") == "LLM_CODER_MODEL_NAME", (
"contract.yaml model_routing.served_model_id_env must be "
"'LLM_CODER_MODEL_NAME'; "
f"got: {model_routing.get('served_model_id_env')!r}"
)


@pytest.mark.unit
Expand All @@ -540,6 +544,7 @@ def test_production_contract_declares_required_env_dependencies() -> None:
}
required = {
"LLM_CODER_URL",
"LLM_CODER_MODEL_NAME",
"LOCAL_LLM_SHARED_SECRET",
"LLM_ENDPOINT_CIDR_ALLOWLIST",
}
Expand Down
Loading