mirror of
https://github.com/superdesigndev/treg.git
synced 2026-10-02 03:24:35 +08:00
feat(octen): register API key provider
This commit is contained in:
@@ -290,6 +290,10 @@ unrenewable one earns a warning (`EXPIRING_SOON_DAYS=7`). `connection_view()` is
|
||||
(no token material) the dashboard/CLI read, with a single actionable `needs_reconnect` flag.
|
||||
|
||||
## Curated OAuth provider registry (`oauth_providers.py`)
|
||||
Octen is an API-key provider with an `x-api-key` binding. Its connection probe sends an empty
|
||||
Search query: a valid key receives an unbilled 400 validation response, while an invalid key
|
||||
receives 401. No account balance endpoint is documented for this credential.
|
||||
|
||||
Connecting a provider persists its API `base_url` and indexed `host` on the team's tool. Changing
|
||||
the registry's base URL affects new connections and direct catalog calls, but an existing named
|
||||
tool or URL-passthrough call keeps using its stored host until reconnect or a scoped data migration.
|
||||
|
||||
@@ -19,6 +19,7 @@ Bare `treg upload` does **both** sides of the dir; `treg upload env` / `treg upl
|
||||
|
||||
- **env side** (`providers.py`): scans a `.env`, detects third-party **provider API keys**, and
|
||||
registers the chosen ones as secrets + tools.
|
||||
Octen's `OCTEN` token uses an `x-api-key` header on `https://api.octen.ai`.
|
||||
- **skill side** (`skills.py`): scans a directory of skills (each a subdir with SKILL.md) and registers
|
||||
each as a tool (+ recipe) or a recipe-only bundle — see "Skill directories" below.
|
||||
|
||||
|
||||
@@ -2529,6 +2529,35 @@ TAVILY = OAuthProvider(
|
||||
probe_path="/usage",
|
||||
)
|
||||
|
||||
OCTEN = OAuthProvider(
|
||||
service="octen",
|
||||
display_name="Octen",
|
||||
auth_kind="key",
|
||||
token_label="API key",
|
||||
token_placeholder="your Octen API key",
|
||||
token_header="x-api-key",
|
||||
token_format="{secret}",
|
||||
setup_url="https://octen.ai/platform",
|
||||
setup_action_label="Get your Octen API key",
|
||||
setup_steps=(
|
||||
"Sign in to the Octen API Platform and create or copy an API key.",
|
||||
"Paste the key here.",
|
||||
),
|
||||
setup_note="Search and extraction calls spend your Octen pay-as-you-go balance.",
|
||||
auth_uri="", token_uri="",
|
||||
scopes={},
|
||||
client_id_setting="", client_secret_setting="",
|
||||
category="SEO",
|
||||
summary="Search the web and news, run broad searches, and extract page content.",
|
||||
base_url="https://api.octen.ai",
|
||||
docs_url="https://docs.octen.ai/",
|
||||
probe_path="/search",
|
||||
probe_method="POST",
|
||||
probe_json={"query": ""},
|
||||
probe_reject_statuses=(401, 403),
|
||||
probe_deferred_statuses=(400,),
|
||||
)
|
||||
|
||||
LINKUP = OAuthProvider(
|
||||
service="linkup",
|
||||
display_name="Linkup",
|
||||
@@ -3759,7 +3788,7 @@ REGISTRY: dict[str, OAuthProvider] = {
|
||||
TIKHUB, BRIGHTDATA, SEMRUSH, JUSTONEAPI,
|
||||
SCRAPECREATORS,
|
||||
# SEO API-key providers
|
||||
DATAFORSEO, SERANKING, MOZ, MAJESTIC, SERPSTAT, EXA, TAVILY, LINKUP, YOU, KEENABLE, OLOSTEP, FIRECRAWL, SPIDERCLOUD, PERPLEXITY,
|
||||
DATAFORSEO, SERANKING, MOZ, MAJESTIC, SERPSTAT, EXA, TAVILY, OCTEN, LINKUP, YOU, KEENABLE, OLOSTEP, FIRECRAWL, SPIDERCLOUD, PERPLEXITY,
|
||||
SCRAPEGRAPHAI, SERPER, LITESCRAPE, CLORO,
|
||||
# more Enrichment API-key providers
|
||||
LUSHA, CORESIGNAL, DIFFBOT, THECOMPANIESAPI, LEADMAGIC, FIBER_AI, CRUSTDATA, AVIATO,
|
||||
|
||||
@@ -174,6 +174,7 @@ CATALOG: list[dict] = [
|
||||
{"provider": "Cartesia", "tokens": ["CARTESIA"], "base_url": "https://api.cartesia.ai", "auth": {"shape": "api_key_header", "header": "X-API-Key"}},
|
||||
# --- search / scraping ---
|
||||
{"provider": "Tavily", "tokens": ["TAVILY"], "base_url": "https://api.tavily.com", "auth": {"shape": "bearer"}},
|
||||
{"provider": "Octen", "tokens": ["OCTEN"], "base_url": "https://api.octen.ai", "auth": {"shape": "api_key_header", "header": "x-api-key"}},
|
||||
{"provider": "Linkup", "tokens": ["LINKUP"], "base_url": "https://api.linkup.so/v1", "auth": {"shape": "bearer"}, "probe": "credits/balance"},
|
||||
{"provider": "You.com", "tokens": ["YDC_API_KEY", "YOU_API_KEY"], "base_url": "https://api.you.com", "auth": {"shape": "api_key_header", "header": "X-API-Key"}, "probe": "v1/billing/account_balance"},
|
||||
{"provider": "Keenable", "tokens": ["KEENABLE"], "base_url": "https://api.keenable.ai", "auth": {"shape": "api_key_header", "header": "X-API-Key"}},
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_11981_6174)">
|
||||
<mask id="mask0_11981_6174" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="2" y="1" width="12" height="10">
|
||||
<path d="M2.69141 1.70605H10.6797C10.926 1.70605 11.1318 1.91377 11.1318 2.17578V2.90137C11.1318 3.10347 11.2096 3.29811 11.3486 3.44141L11.4326 3.52832C11.5717 3.67168 11.7627 3.75293 11.9609 3.75293H12.6426C12.8889 3.75293 13.0947 3.96064 13.0947 4.22266V9.91406C13.0851 10.1671 12.8849 10.3643 12.6445 10.3643H4.64551C4.39942 10.364 4.19448 10.1573 4.19434 9.89551V9.10449C4.19432 8.92405 4.12501 8.75107 4.00098 8.62305L3.99805 8.62012C3.83126 8.44832 3.60401 8.35067 3.36719 8.35059H2.69141C2.44506 8.35059 2.23926 8.14384 2.23926 7.88184V2.17578C2.23926 1.91377 2.44506 1.70605 2.69141 1.70605ZM4.66016 3.52344C4.29007 3.5237 3.99512 3.8325 3.99512 4.20605V7.7002C3.99522 7.91159 4.06607 8.11549 4.19531 8.27832L4.25488 8.3457C4.37977 8.47351 4.54909 8.54688 4.72656 8.54688H10.6748C11.045 8.54673 11.3398 8.23788 11.3398 7.86426V4.28809C11.3398 4.16127 11.3062 4.03878 11.249 3.92871H11.3008L11.123 3.74805L11.0098 3.65234C10.8882 3.56912 10.7443 3.52347 10.5957 3.52344H4.66016Z" fill="white" stroke="#70FE7E" stroke-width="0.213439"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_11981_6174)">
|
||||
<path d="M2.69141 1.70605H10.6797C10.926 1.70605 11.1318 1.91377 11.1318 2.17578V2.90137C11.1318 3.10347 11.2096 3.29811 11.3486 3.44141L11.4326 3.52832C11.5717 3.67168 11.7627 3.75293 11.9609 3.75293H12.6426C12.8889 3.75293 13.0947 3.96064 13.0947 4.22266V9.91406C13.0851 10.1671 12.8849 10.3643 12.6445 10.3643H4.64551C4.39942 10.364 4.19448 10.1573 4.19434 9.89551V9.10449C4.19432 8.92405 4.12501 8.75107 4.00098 8.62305L3.99805 8.62012C3.83126 8.44832 3.60401 8.35067 3.36719 8.35059H2.69141C2.44506 8.35059 2.23926 8.14384 2.23926 7.88184V2.17578C2.23926 1.91377 2.44506 1.70605 2.69141 1.70605ZM4.66016 3.52344C4.29007 3.5237 3.99512 3.8325 3.99512 4.20605V7.7002C3.99522 7.91159 4.06607 8.11549 4.19531 8.27832L4.25488 8.3457C4.37977 8.47351 4.54909 8.54688 4.72656 8.54688H10.6748C11.045 8.54673 11.3398 8.23788 11.3398 7.86426V4.28809C11.3398 4.16127 11.3062 4.03878 11.249 3.92871H11.3008L11.123 3.74805L11.0098 3.65234C10.8882 3.56912 10.7443 3.52347 10.5957 3.52344H4.66016Z" fill="#70FE7E" stroke="#70FE7E" stroke-width="0.213439"/>
|
||||
</g>
|
||||
<path d="M6.52849 5.14551H5.74605C5.43757 5.14551 5.1875 5.40332 5.1875 5.72134V6.52798C5.1875 6.846 5.43757 7.10381 5.74605 7.10381H6.52849C6.83697 7.10381 7.08704 6.846 7.08704 6.52798V5.72134C7.08704 5.40332 6.83697 5.14551 6.52849 5.14551Z" fill="#70FE7E"/>
|
||||
<path d="M9.55388 5.14551H8.77144C8.46296 5.14551 8.21289 5.40332 8.21289 5.72134V6.52798C8.21289 6.846 8.46296 7.10381 8.77144 7.10381H9.55388C9.86236 7.10381 10.1124 6.846 10.1124 6.52798V5.72134C10.1124 5.40332 9.86236 5.14551 9.55388 5.14551Z" fill="#70FE7E"/>
|
||||
<path d="M6.79707 12.3242H5.9023C5.59382 12.3242 5.34375 12.582 5.34375 12.9V13.8225C5.34375 14.1405 5.59382 14.3983 5.9023 14.3983H6.79707C7.10555 14.3983 7.35562 14.1405 7.35562 13.8225V12.9C7.35562 12.582 7.10555 12.3242 6.79707 12.3242Z" fill="#70FE7E"/>
|
||||
<path d="M10.1096 12.3242H9.2148C8.90632 12.3242 8.65625 12.582 8.65625 12.9V13.8225C8.65625 14.1405 8.90632 14.3983 9.2148 14.3983H10.1096C10.418 14.3983 10.6681 14.1405 10.6681 13.8225V12.9C10.6681 12.582 10.418 12.3242 10.1096 12.3242Z" fill="#70FE7E"/>
|
||||
<path d="M15.9921 11.7491V10.8258C15.9921 10.508 15.7419 10.25 15.4335 10.25H14.538C14.2297 10.25 13.9794 10.508 13.9794 10.8258V11.7491C13.9794 11.9016 13.9206 12.0478 13.816 12.1564C13.7114 12.2642 13.5696 12.3249 13.4209 12.3249H12.5253C12.217 12.3249 11.9668 12.5829 11.9668 12.9007V13.824C11.9668 14.1418 12.217 14.3998 12.5253 14.3998H13.4209C13.7292 14.3998 13.9794 14.1418 13.9794 13.824V13.0724C13.9794 12.9199 14.0383 12.7737 14.1429 12.6651L14.3095 12.4934C14.414 12.3856 14.5558 12.3249 14.7046 12.3249H15.4335C15.7419 12.3249 15.9921 12.0669 15.9921 11.7491Z" fill="#70FE7E"/>
|
||||
<path d="M2.07242 11.705V10.8249C2.07242 10.507 1.82219 10.249 1.51386 10.249H0.619098C0.310772 10.2498 0.0605469 10.507 0.0605469 10.8249V11.7481C0.0605469 12.066 0.310772 12.3239 0.619098 12.3239H1.33181C1.51774 12.3239 1.69592 12.3998 1.82684 12.5356C1.95854 12.6713 2.03213 12.8542 2.03213 13.0459V13.823C2.03213 14.1409 2.28236 14.3988 2.59068 14.3988H3.48623C3.79455 14.3988 4.04478 14.1409 4.04478 13.823V12.8998C4.04478 12.5819 3.79455 12.3239 3.48623 12.3239H2.73245C2.54653 12.3239 2.36835 12.2481 2.23743 12.1123C2.13284 12.0037 2.07397 11.8575 2.07397 11.705H2.07242Z" fill="#70FE7E"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_11981_6174">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -60,6 +60,23 @@ async def test_perplexity_key_uses_free_model_list_probe(clients, monkeypatch):
|
||||
assert response.status_code == 200, response.text
|
||||
|
||||
|
||||
async def test_octen_key_uses_unbilled_validation_probe(clients, monkeypatch):
|
||||
def probe(request):
|
||||
assert request.method == "POST"
|
||||
assert request.url.path == "/search"
|
||||
assert json.loads(request.content) == {"query": ""}
|
||||
assert request.headers["x-api-key"] == "own-key"
|
||||
return httpx.Response(400, json={"code": 400, "msg": "Invalid params. Missing parameter query"})
|
||||
|
||||
async with AsyncClient(transport=httpx.MockTransport(probe)) as upstream:
|
||||
monkeypatch.setattr(app.state, "http", upstream)
|
||||
response = await clients.post(
|
||||
"/connections/token", json={"provider": "octen", "token": "own-key"},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json()["health"] == "unknown"
|
||||
|
||||
|
||||
async def test_adyntel_connect_collects_both_credentials_before_provisioning(clients, monkeypatch):
|
||||
def probe(request):
|
||||
assert request.method == "POST"
|
||||
|
||||
Reference in New Issue
Block a user