-
Notifications
You must be signed in to change notification settings - Fork 1
fix(discovery): bootstrap an honest provider-diverse failover pool #770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a3a24ae
7ccfd92
90d4154
d12f8c8
77e9544
8ea3a06
4f7b6d4
c92d81d
e74e4d0
7cec2fa
8c7686a
fe06058
4e27d52
a30c390
6578dc5
1ca4015
9632f53
91fab32
fd6a8af
dc19672
6b25f19
4d81411
06da0c0
a063113
2539ad5
a78d3a6
75e15af
183e7a8
c01733b
7f725cd
2a360f9
db4134c
f4f1b4a
854d7a2
0777e14
55814b9
386c9a0
6c10b49
c8632d0
6b603ef
4f94e0d
d693ace
8afe847
ea5ab0e
7494f22
074f0e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| name: Provider catalog sync | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| schedule: | ||
| - cron: "17 * * * *" | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: provider-catalog-sync | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| sync: | ||
| name: Bootstrap durable provider KV and model catalog | ||
| if: github.ref == 'refs/heads/main' | ||
| runs-on: ubuntu-latest | ||
| environment: production | ||
| timeout-minutes: 15 | ||
| steps: | ||
| - name: Checkout protected default branch | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # actions/setup-python@v6 | ||
| with: | ||
| python-version: "3.12" | ||
|
|
||
| - name: Install hash-pinned runtime dependencies | ||
| run: python -m pip install --disable-pip-version-check --no-input --require-hashes -r requirements.lock | ||
|
|
||
| - name: Register credentials and refresh normalized model catalog | ||
| shell: bash | ||
| env: | ||
| CONTEXTUAL_ORCHESTRATOR_KV_BACKEND: postgres | ||
| CONTEXTUAL_ORCHESTRATOR_KV_DSN: ${{ secrets.CONTEXTUAL_ORCHESTRATOR_KV_DSN }} | ||
| CONTEXTUAL_ORCHESTRATOR_KV_PASSPHRASE: ${{ secrets.CONTEXTUAL_ORCHESTRATOR_KV_PASSPHRASE }} | ||
| NVIDIA_NIM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }} | ||
| NVIDIA_NIM_API_KEY_SUB: ${{ secrets.NVIDIA_NIM_API_KEY_SUB }} | ||
| BYTEZ_API_KEY: ${{ secrets.BYTEZ_API_KEY }} | ||
| OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} | ||
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||
| run: | | ||
| set -euo pipefail | ||
| test -n "${CONTEXTUAL_ORCHESTRATOR_KV_DSN}" | ||
| test -n "${CONTEXTUAL_ORCHESTRATOR_KV_PASSPHRASE}" | ||
| python -m contextual_orchestrator.provider_catalog_bootstrap --model-limit 24 > provider-bootstrap-report.json | ||
| python - <<'PY' | ||
| import json | ||
| from pathlib import Path | ||
|
|
||
| report = json.loads(Path('provider-bootstrap-report.json').read_text(encoding='utf-8')) | ||
| expected = { | ||
| 'NVIDIA_NIM_API_KEY', | ||
| 'NVIDIA_NIM_API_KEY_SUB', | ||
| 'BYTEZ_API_KEY', | ||
| 'OPENROUTER_API_KEY', | ||
| 'OPENAI_API_KEY', | ||
| } | ||
| registered = set(report['registered_credentials']) | ||
| if registered != expected: | ||
| raise SystemExit(f'credential inventory mismatch: {sorted(expected - registered)}') | ||
| if report['catalog_backend'] != 'postgres': | ||
| raise SystemExit('provider catalog is not durable PostgreSQL') | ||
| if report['catalog_model_count'] < 1 or report['eligible_model_count'] < 1: | ||
| raise SystemExit('provider catalog has no compatible serving model') | ||
| if not report['selected_agent_ids']: | ||
| raise SystemExit('provider catalog produced no serving candidates') | ||
| if report['enabled_agent_ids'] or report['durable_agent_pool']: | ||
| raise SystemExit('ephemeral Actions sync must not claim agent-pool activation') | ||
| print(json.dumps({ | ||
| 'registered_credentials': sorted(registered), | ||
| 'live_discovered_model_count': report['live_discovered_model_count'], | ||
| 'catalog_model_count': report['catalog_model_count'], | ||
| 'last_known_good_model_count': report['last_known_good_model_count'], | ||
| 'selected_agent_count': len(report['selected_agent_ids']), | ||
| 'catalog_refresh_failure_count': report['catalog_refresh_failure_count'], | ||
| 'providers_with_errors': report['providers_with_errors'], | ||
| }, sort_keys=True)) | ||
| PY | ||
| python - <<'PY' | ||
| import os | ||
| from pathlib import Path | ||
|
|
||
| report = Path('provider-bootstrap-report.json').read_text(encoding='utf-8') | ||
| names = ( | ||
| 'NVIDIA_NIM_API_KEY', | ||
| 'NVIDIA_NIM_API_KEY_SUB', | ||
| 'BYTEZ_API_KEY', | ||
| 'OPENROUTER_API_KEY', | ||
| 'OPENAI_API_KEY', | ||
| ) | ||
| leaked = [ | ||
| name | ||
| for name in names | ||
| if os.environ[name].rstrip('\r\n') | ||
| and os.environ[name].rstrip('\r\n') in report | ||
| ] | ||
| if leaked: | ||
| raise SystemExit(f'provider bootstrap report leaked secret values for: {leaked}') | ||
| PY |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
| import threading | ||
| from dataclasses import dataclass, field | ||
| from decimal import ROUND_HALF_UP, Decimal | ||
| import math | ||
| import time | ||
| from typing import Any, Dict, List, Optional, Protocol | ||
| import uuid | ||
|
|
@@ -162,11 +163,30 @@ def get_price(self, provider: str, model: str) -> Optional[PriceEntry]: | |
| raw = self._config.get(_PRICE_CATEGORY, _price_key(provider, "*"), None) | ||
| if raw is None: | ||
| return None | ||
| if not isinstance(raw, dict): | ||
| return None | ||
| try: | ||
| if ( | ||
| "prompt_price_per_1k" not in raw | ||
| or "completion_price_per_1k" not in raw | ||
| ): | ||
| return None | ||
| prompt_price = float(raw["prompt_price_per_1k"]) | ||
| completion_price = float(raw["completion_price_per_1k"]) | ||
| except (OverflowError, TypeError, ValueError): | ||
| return None | ||
| if ( | ||
| not math.isfinite(prompt_price) | ||
| or not math.isfinite(completion_price) | ||
| or prompt_price < 0 | ||
| or completion_price < 0 | ||
| ): | ||
| return None | ||
|
Comment on lines
+166
to
+184
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: get_price now returns None for partial/corrupt rows, changing compute_cost for those rows
Was this helpful? React with 👍 or 👎 to provide feedback.
Comment on lines
163
to
+184
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: get_price does not fall back to wildcard entry when the specific row is corrupt In (Refers to this code) Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| return PriceEntry( | ||
| provider_name=raw.get("provider_name", provider), | ||
| model_name=raw.get("model_name", model), | ||
| prompt_price_per_1k=float(raw.get("prompt_price_per_1k", 0.0)), | ||
| completion_price_per_1k=float(raw.get("completion_price_per_1k", 0.0)), | ||
| prompt_price_per_1k=prompt_price, | ||
| completion_price_per_1k=completion_price, | ||
| currency_code=raw.get("currency_code", self.default_currency), | ||
| ) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 Info: --enable-cheapest flag now performs provider-diverse selection despite its name
The CLI flag
--enable-cheapest(main.py) now drivesselect_bootstrap_discovered_agents, which prefers one candidate per provider family before taking a second from an already-represented family. So--enable-cheapest Nno longer strictly enables the N globally-cheapest agents; it enables a provider-diverse pool ordered by cost. The help text was updated to describe this, but the flag name retains 'cheapest', which may surprise operators expecting pure cost ordering. Behavioral change is intentional per the PR.Was this helpful? React with 👍 or 👎 to provide feedback.