From 5b347ef3d46af85f7f3fde03b33328d9fbc9a788 Mon Sep 17 00:00:00 2001 From: aimlapi Date: Thu, 3 Sep 2026 04:25:05 +0500 Subject: [PATCH 1/3] feat(llm): add aimlapi.com as an OpenAI-compatible provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hindsight operators who already route models through a gateway currently have OpenRouter, Requesty and Atlas Cloud to choose from. aimlapi.com is the same shape of thing — one key, one OpenAI-compatible endpoint, several hundred chat models — so it is wired the same way the last three gateways were rather than introducing any new plumbing: a named string in the factory list, the valid-provider list and the API-key-required list, plus a base-URL default. The gateway serves embeddings from the same host and key, so the embeddings factory gets the matching branch. Its key falls back through HINDSIGHT_API_AIMLAPI_API_KEY to HINDSIGHT_API_LLM_API_KEY, mirroring the chain OpenRouter and Requesty already use, so a single-key setup needs one variable. Only the /v1 root is declared: the gateway has no /v1/completions route, and declaring one would turn a 404 into a confusing "model is broken" report. Requests to the gateway carry attribution headers. There is precedent for them — create_llm_provider already threads default_headers into the OpenAI-compatible client for operators fronting a proxy — so this reuses that seam instead of adding one. They are merged *under* any operator-supplied headers so a configured HINDSIGHT_API_LLM_DEFAULT_HEADERS still wins, built into a fresh dict per client so the module constant is never mutated, and gated on both the provider name and the resolved host, so they cannot ride a request to another provider or to a private proxy that merely speaks the same wire format. A malformed partner id is dropped by the gateway without failing the request, i.e. invisibly, so its shape is pinned by a test rather than left to review. Default model openai/gpt-5-mini and embedding model openai/text-embedding-3-small were both checked against the live catalog (ids and aliases) rather than copied from another gateway's list. --- .env.example | 9 +- hindsight-api-slim/hindsight_api/config.py | 52 +++++ .../hindsight_api/engine/embeddings.py | 28 ++- .../hindsight_api/engine/llm_wrapper.py | 4 + .../engine/providers/openai_compatible_llm.py | 7 +- .../tests/test_aimlapi_provider.py | 205 ++++++++++++++++++ .../docs/developer/configuration.md | 13 +- hindsight-docs/src/data/llmProviders.json | 1 + .../control_center/providers.py | 1 + hindsight-embed/hindsight_embed/env.example | 9 +- .../references/developer/configuration.md | 13 +- .../references/developer/models.md | 3 + skills/hindsight-docs/references/faq.md | 1 + 13 files changed, 334 insertions(+), 12 deletions(-) create mode 100644 hindsight-api-slim/tests/test_aimlapi_provider.py diff --git a/.env.example b/.env.example index 97681cc5fd..51a02e5b89 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ # Copy this file to .env and fill in your values # LLM Configuration (Required) -# Supported providers: openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, volcano, openai-codex, claude-code, github-copilot +# Supported providers: openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, aimlapi, volcano, openai-codex, claude-code, github-copilot HINDSIGHT_API_LLM_PROVIDER=openai HINDSIGHT_API_LLM_API_KEY=your-api-key-here HINDSIGHT_API_LLM_MODEL=gpt-4o-mini @@ -128,6 +128,11 @@ HINDSIGHT_API_LLM_MODEL=gpt-4o-mini # HINDSIGHT_API_LLM_API_KEY=your-atlascloud-api-key # HINDSIGHT_API_LLM_MODEL=deepseek-ai/deepseek-v4-pro # reasoning model; also Qwen / GLM / Kimi / MiniMax, etc. +# Example: aimlapi.com configuration (OpenAI-compatible gateway, https://api.aimlapi.com/v1) +# HINDSIGHT_API_LLM_PROVIDER=aimlapi +# HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +# HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini # catalog at https://api.aimlapi.com/v1/models + # Example: LM Studio local configuration (Qwen 2.5 32B recommended) # HINDSIGHT_API_LLM_PROVIDER=lmstudio # HINDSIGHT_API_LLM_API_KEY=lmstudio @@ -307,7 +312,7 @@ HINDSIGHT_API_LOG_LEVEL=info # HINDSIGHT_API_FILE_PARSER_MARKITDOWN_OCR_DEFAULT_HEADERS= # Embeddings Configuration (Optional - uses local by default) -# Provider: "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "zeroentropy", "litellm", or "litellm-sdk" +# Provider: "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "aimlapi", "zeroentropy", "litellm", or "litellm-sdk" # HINDSIGHT_API_EMBEDDINGS_PROVIDER=local # For local provider: # HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5 diff --git a/hindsight-api-slim/hindsight_api/config.py b/hindsight-api-slim/hindsight_api/config.py index 2e4d7fc817..9f69db05b9 100644 --- a/hindsight-api-slim/hindsight_api/config.py +++ b/hindsight-api-slim/hindsight_api/config.py @@ -12,6 +12,7 @@ from dataclasses import dataclass, field, fields from datetime import datetime, timezone from typing import Any, Literal +from urllib.parse import urlparse from dotenv import find_dotenv, load_dotenv @@ -449,6 +450,11 @@ def _parse_boolean_env(env_name: str, default: bool) -> bool: ENV_EMBEDDINGS_REQUESTY_API_KEY = "HINDSIGHT_API_EMBEDDINGS_REQUESTY_API_KEY" ENV_EMBEDDINGS_REQUESTY_MODEL = "HINDSIGHT_API_EMBEDDINGS_REQUESTY_MODEL" +# AI/ML API configuration (aimlapi.com — OpenAI-compatible gateway; embeddings) +ENV_AIMLAPI_API_KEY = "HINDSIGHT_API_AIMLAPI_API_KEY" +ENV_EMBEDDINGS_AIMLAPI_API_KEY = "HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY" +ENV_EMBEDDINGS_AIMLAPI_MODEL = "HINDSIGHT_API_EMBEDDINGS_AIMLAPI_MODEL" + # ZeroEntropy configuration (embeddings) ENV_EMBEDDINGS_ZEROENTROPY_API_KEY = "HINDSIGHT_API_EMBEDDINGS_ZEROENTROPY_API_KEY" ENV_EMBEDDINGS_ZEROENTROPY_MODEL = "HINDSIGHT_API_EMBEDDINGS_ZEROENTROPY_MODEL" @@ -955,6 +961,7 @@ def _parse_worker_slot_reservations() -> dict[str, int]: "volcano": "doubao-pro-32k", "openrouter": "qwen/qwen3.5-9b", "requesty": "openai/gpt-4o-mini", + "aimlapi": "openai/gpt-5-mini", "fireworks": "accounts/fireworks/models/llama-v3p1-8b-instruct", "nous": "deepseek/deepseek-v4-flash", "xai-oauth": "grok-4.5", @@ -1218,6 +1225,44 @@ def _parse_strategy_boosts(raw: str | None) -> dict[str, str]: # Requesty defaults DEFAULT_EMBEDDINGS_REQUESTY_MODEL = "openai/text-embedding-3-small" +# AI/ML API defaults +DEFAULT_EMBEDDINGS_AIMLAPI_MODEL = "openai/text-embedding-3-small" + +# Attribution headers sent with AI/ML API requests. The gateway reads them to +# attribute traffic to the calling application; a request without them is +# indistinguishable from anonymous use. They identify Hindsight — nothing about +# the operator or their data is in them — and are applied only when the resolved +# base URL is the aimlapi.com host below, so they can never ride a request to a +# different provider or to a proxy that merely fronts the same wire format. +AIMLAPI_ATTRIBUTION_HOST = "api.aimlapi.com" +AIMLAPI_ATTRIBUTION_HEADERS: dict[str, str] = { + "HTTP-Referer": "https://github.com/vectorize-io/hindsight", + "X-Title": "Hindsight", + "X-AIMLAPI-Partner-ID": "part_hindsight", + "X-AIMLAPI-Source": "agent/hindsight", +} + + +def aimlapi_default_headers( + provider: str, + base_url: str | None, + default_headers: dict[str, str] | None, +) -> dict[str, str] | None: + """Merge the AI/ML API attribution headers *under* operator-supplied headers. + + Returns ``default_headers`` unchanged for any other provider or host, so no + existing provider's request shape moves. When it does apply it builds a new + dict: ``AIMLAPI_ATTRIBUTION_HEADERS`` is never mutated (it is shared by every + client in the process), and an operator who set the same key in + ``HINDSIGHT_API_LLM_DEFAULT_HEADERS`` still wins. + """ + if provider != "aimlapi" or not base_url: + return default_headers + if (urlparse(base_url).hostname or "").lower() != AIMLAPI_ATTRIBUTION_HOST: + return default_headers + return {**AIMLAPI_ATTRIBUTION_HEADERS, **(default_headers or {})} + + # ZeroEntropy defaults DEFAULT_EMBEDDINGS_ZEROENTROPY_MODEL = "zembed-1" # Shared between embeddings (zembed-1) and reranker (zerank-*) — the host is the same. @@ -2645,6 +2690,8 @@ class HindsightConfig: embeddings_openrouter_model: str embeddings_requesty_api_key: str | None embeddings_requesty_model: str + embeddings_aimlapi_api_key: str | None + embeddings_aimlapi_model: str embeddings_litellm_api_base: str embeddings_litellm_api_key: str | None embeddings_litellm_model: str @@ -3815,6 +3862,11 @@ def from_env(cls) -> "HindsightConfig": or os.getenv(ENV_REQUESTY_API_KEY) or os.getenv(ENV_LLM_API_KEY), embeddings_requesty_model=os.getenv(ENV_EMBEDDINGS_REQUESTY_MODEL, DEFAULT_EMBEDDINGS_REQUESTY_MODEL), + # AI/ML API embeddings (with fallback to shared AI/ML API key, then LLM key) + embeddings_aimlapi_api_key=os.getenv(ENV_EMBEDDINGS_AIMLAPI_API_KEY) + or os.getenv(ENV_AIMLAPI_API_KEY) + or os.getenv(ENV_LLM_API_KEY), + embeddings_aimlapi_model=os.getenv(ENV_EMBEDDINGS_AIMLAPI_MODEL, DEFAULT_EMBEDDINGS_AIMLAPI_MODEL), # ZeroEntropy embeddings embeddings_zeroentropy_api_key=os.getenv(ENV_EMBEDDINGS_ZEROENTROPY_API_KEY) or os.getenv("ZEROENTROPY_API_KEY"), diff --git a/hindsight-api-slim/hindsight_api/engine/embeddings.py b/hindsight-api-slim/hindsight_api/engine/embeddings.py index b05c9a7d74..2debd4c8ab 100644 --- a/hindsight-api-slim/hindsight_api/engine/embeddings.py +++ b/hindsight-api-slim/hindsight_api/engine/embeddings.py @@ -57,6 +57,7 @@ ENV_EMBEDDINGS_ZEROENTROPY_DIMENSIONS, ENV_EMBEDDINGS_ZEROENTROPY_ENCODING_FORMAT, ENV_LLM_API_KEY, + aimlapi_default_headers, ) from .bank_attribution import apply_bank_attribution from .local_device import ( @@ -951,6 +952,7 @@ def __init__( max_retries: int = 3, query_prefix: str = "", passage_prefix: str = "", + default_headers: dict[str, str] | None = None, ): """ Initialize OpenAI embeddings client. @@ -964,6 +966,8 @@ def __init__( max_retries: Maximum number of retries for failed requests (default: 3) query_prefix: Prefix prepended to recall/search queries (default: none) passage_prefix: Prefix prepended to retained document text (default: none) + default_headers: Custom headers passed to the OpenAI client. None (the + default) sends no extra headers, so every existing caller is unchanged. """ self.api_key = api_key self.model = model @@ -973,6 +977,7 @@ def __init__( self.max_retries = max_retries self.query_prefix = query_prefix self.passage_prefix = passage_prefix + self.default_headers = default_headers self._client = None self._dimension: int | None = None @@ -1003,6 +1008,8 @@ async def initialize(self) -> None: # Parse query parameters from base_url (e.g. ?api-version=xxx for Azure OpenAI) # and pass them as default_query so they're included in every request. client_kwargs = {"api_key": self.api_key, "max_retries": self.max_retries} + if self.default_headers: + client_kwargs["default_headers"] = self.default_headers if self.base_url: parsed = urlparse(self.base_url) if parsed.query: @@ -2199,6 +2206,24 @@ def create_embeddings_from_env() -> Embeddings: query_prefix=query_prefix, passage_prefix=passage_prefix, ) + elif provider == "aimlapi": + api_key = config.embeddings_aimlapi_api_key + if not api_key: + raise ValueError( + "HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY, HINDSIGHT_API_AIMLAPI_API_KEY, " + f"or {ENV_LLM_API_KEY} is required when {ENV_EMBEDDINGS_PROVIDER} is 'aimlapi'" + ) + aimlapi_base_url = "https://api.aimlapi.com/v1" + return OpenAIEmbeddings( + api_key=api_key, + model=config.embeddings_aimlapi_model, + base_url=aimlapi_base_url, + batch_size=config.embeddings_openai_batch_size, + dimensions=config.embeddings_openai_dimensions, + query_prefix=query_prefix, + passage_prefix=passage_prefix, + default_headers=aimlapi_default_headers("aimlapi", aimlapi_base_url, None), + ) elif provider == "zeroentropy": api_key = config.embeddings_zeroentropy_api_key if not api_key: @@ -2269,6 +2294,7 @@ def create_embeddings_from_env() -> Embeddings: else: raise ValueError( f"Unknown embeddings provider: {provider}. " - f"Supported: 'local', 'onnx', 'tei', 'openai', 'openai-codex', 'openrouter', 'requesty', 'cohere', 'google', " + f"Supported: 'local', 'onnx', 'tei', 'openai', 'openai-codex', 'openrouter', 'requesty', 'aimlapi', " + f"'cohere', 'google', " f"'zeroentropy', 'litellm', 'litellm-sdk'" ) diff --git a/hindsight-api-slim/hindsight_api/engine/llm_wrapper.py b/hindsight-api-slim/hindsight_api/engine/llm_wrapper.py index e9912d1022..0b6200a1c5 100644 --- a/hindsight-api-slim/hindsight_api/engine/llm_wrapper.py +++ b/hindsight-api-slim/hindsight_api/engine/llm_wrapper.py @@ -768,6 +768,7 @@ def create_llm_provider( "volcano", "openrouter", "requesty", + "aimlapi", "zai", "opencode-go", "atlas", @@ -962,6 +963,7 @@ def __init__( "volcano", "openrouter", "requesty", + "aimlapi", "zai", "opencode-go", "atlas", @@ -990,6 +992,8 @@ def __init__( self.base_url = "https://openrouter.ai/api/v1" elif self.provider == "requesty": self.base_url = "https://router.requesty.ai/v1" + elif self.provider == "aimlapi": + self.base_url = "https://api.aimlapi.com/v1" elif self.provider == "zai": self.base_url = "https://api.z.ai/api/coding/paas/v4" elif self.provider == "opencode-go": diff --git a/hindsight-api-slim/hindsight_api/engine/providers/openai_compatible_llm.py b/hindsight-api-slim/hindsight_api/engine/providers/openai_compatible_llm.py index 8d8642959a..57e460fc1f 100644 --- a/hindsight-api-slim/hindsight_api/engine/providers/openai_compatible_llm.py +++ b/hindsight-api-slim/hindsight_api/engine/providers/openai_compatible_llm.py @@ -35,7 +35,7 @@ import httpx from openai import APIConnectionError, APIStatusError, AsyncOpenAI, LengthFinishReasonError -from hindsight_api.config import DEFAULT_LLM_TIMEOUT, ENV_LLM_TIMEOUT +from hindsight_api.config import DEFAULT_LLM_TIMEOUT, ENV_LLM_TIMEOUT, aimlapi_default_headers from hindsight_api.engine.bank_attribution import apply_bank_attribution from hindsight_api.engine.cache_affinity import ( CacheAffinityMode, @@ -735,6 +735,7 @@ def __init__( "volcano", "openrouter", "requesty", + "aimlapi", "zai", "opencode-go", "atlas", @@ -761,6 +762,8 @@ def __init__( self.base_url = "https://openrouter.ai/api/v1" elif self.provider == "requesty": self.base_url = "https://router.requesty.ai/v1" + elif self.provider == "aimlapi": + self.base_url = "https://api.aimlapi.com/v1" elif self.provider == "zai": self.base_url = "https://api.z.ai/api/coding/paas/v4" elif self.provider == "opencode-go": @@ -791,6 +794,7 @@ def __init__( "deepseek", "openrouter", "requesty", + "aimlapi", "zai", "opencode-go", "atlas", @@ -820,6 +824,7 @@ def __init__( # Create OpenAI client — extract query params from base_url (e.g. Azure api-version) client_kwargs: dict[str, Any] = {"api_key": self.api_key, "max_retries": 0} + default_headers = aimlapi_default_headers(self.provider, self.base_url, default_headers) if default_headers: client_kwargs["default_headers"] = default_headers if self.base_url: diff --git a/hindsight-api-slim/tests/test_aimlapi_provider.py b/hindsight-api-slim/tests/test_aimlapi_provider.py new file mode 100644 index 0000000000..c227840910 --- /dev/null +++ b/hindsight-api-slim/tests/test_aimlapi_provider.py @@ -0,0 +1,205 @@ +"""Tests for the aimlapi.com OpenAI-compatible LLM provider and its attribution headers.""" + +import re + +import pytest + + +def test_aimlapi_config_has_expected_default_model(monkeypatch): + """HindsightConfig should default aimlapi to a model that exists in the catalog.""" + from hindsight_api.config import PROVIDER_DEFAULT_MODELS, HindsightConfig, clear_config_cache + + monkeypatch.setenv("HINDSIGHT_API_LLM_PROVIDER", "aimlapi") + monkeypatch.delenv("HINDSIGHT_API_LLM_MODEL", raising=False) + clear_config_cache() + + try: + assert PROVIDER_DEFAULT_MODELS["aimlapi"] == "openai/gpt-5-mini" + config = HindsightConfig.from_env() + assert config.llm_provider == "aimlapi" + assert config.llm_model == "openai/gpt-5-mini" + finally: + clear_config_cache() + + +def test_aimlapi_llm_provider_from_env_has_expected_default_model(monkeypatch): + """LLMProvider.from_env should use the aimlapi provider default model and base URL.""" + from hindsight_api.config import clear_config_cache + from hindsight_api.engine.llm_wrapper import LLMProvider + + monkeypatch.setenv("HINDSIGHT_API_LLM_PROVIDER", "aimlapi") + monkeypatch.setenv("HINDSIGHT_API_LLM_API_KEY", "test-key") + monkeypatch.delenv("HINDSIGHT_API_LLM_MODEL", raising=False) + monkeypatch.delenv("HINDSIGHT_API_LLM_BASE_URL", raising=False) + clear_config_cache() + + try: + llm = LLMProvider.from_env() + assert llm.provider == "aimlapi" + assert llm.model == "openai/gpt-5-mini" + assert llm.base_url == "https://api.aimlapi.com/v1" + finally: + clear_config_cache() + + +def test_aimlapi_requires_api_key(): + """aimlapi is a cloud gateway and should require an API key.""" + from hindsight_api.engine.llm_wrapper import requires_api_key + + assert requires_api_key("aimlapi") is True + + +def test_aimlapi_uses_openai_compatible_provider_with_default_base_url(): + """The provider factory should route aimlapi to OpenAICompatibleLLM.""" + from hindsight_api.engine.llm_wrapper import LLMProvider + from hindsight_api.engine.providers.openai_compatible_llm import OpenAICompatibleLLM + + llm = LLMProvider( + provider="aimlapi", + api_key="test-key", + base_url="", + model="openai/gpt-5-mini", + ) + + assert llm.provider == "aimlapi" + assert llm.model == "openai/gpt-5-mini" + # /v1/completions does not exist on this gateway; only the /v1 root is declared + # and the OpenAI SDK appends /chat/completions to it. + assert llm.base_url == "https://api.aimlapi.com/v1" + assert not llm.base_url.endswith("/") + assert isinstance(llm._provider_impl, OpenAICompatibleLLM) + assert llm._provider_impl.base_url == "https://api.aimlapi.com/v1" + + +def test_aimlapi_rejects_missing_api_key(): + """aimlapi should fail fast without an API key, matching the other cloud gateways.""" + from hindsight_api.engine.llm_wrapper import LLMProvider + + with pytest.raises(ValueError, match="API key is required for aimlapi"): + LLMProvider( + provider="aimlapi", + api_key="", + base_url="", + model="openai/gpt-5-mini", + ) + + +def test_aimlapi_partner_id_matches_gateway_pattern(): + """A malformed partner id is dropped silently by the gateway, so assert its shape here. + + The gateway accepts ``^part_[A-Za-z0-9]{1,64}$`` and treats anything else as + untagged traffic without failing the request — a typo would be invisible at + runtime, which is why it is pinned in a test rather than only in review. + """ + from hindsight_api.config import AIMLAPI_ATTRIBUTION_HEADERS + + partner_id = AIMLAPI_ATTRIBUTION_HEADERS["X-AIMLAPI-Partner-ID"] + assert re.fullmatch(r"part_[A-Za-z0-9]{1,64}", partner_id), partner_id + # /, channel from a closed enum {web, agent, mcp}. + assert re.fullmatch(r"agent/[a-z0-9-]{1,32}", AIMLAPI_ATTRIBUTION_HEADERS["X-AIMLAPI-Source"]) + # HTTP-Referer / X-Title identify the calling application (Hindsight), not the gateway. + assert AIMLAPI_ATTRIBUTION_HEADERS["HTTP-Referer"] == "https://github.com/vectorize-io/hindsight" + assert AIMLAPI_ATTRIBUTION_HEADERS["X-Title"] == "Hindsight" + + +def test_aimlapi_attribution_headers_reach_the_client(): + """The OpenAI client for aimlapi should carry all four attribution headers.""" + from hindsight_api.config import AIMLAPI_ATTRIBUTION_HEADERS + from hindsight_api.engine.providers.openai_compatible_llm import OpenAICompatibleLLM + + llm = OpenAICompatibleLLM( + provider="aimlapi", + api_key="test-key", + base_url="", + model="openai/gpt-5-mini", + reasoning_effort=None, + ) + + sent = llm._client.default_headers + for header, value in AIMLAPI_ATTRIBUTION_HEADERS.items(): + assert sent.get(header) == value + + +def test_aimlapi_attribution_does_not_leak_to_other_providers(): + """Attribution must never ride a request to a different provider.""" + from hindsight_api.engine.providers.openai_compatible_llm import OpenAICompatibleLLM + + llm = OpenAICompatibleLLM( + provider="openrouter", + api_key="test-key", + base_url="", + model="qwen/qwen3.5-9b", + reasoning_effort=None, + ) + + assert "X-AIMLAPI-Partner-ID" not in llm._client.default_headers + + +def test_aimlapi_attribution_is_scoped_to_the_aimlapi_host(): + """A proxy fronting the same wire format must not receive our attribution.""" + from hindsight_api.engine.providers.openai_compatible_llm import OpenAICompatibleLLM + + llm = OpenAICompatibleLLM( + provider="aimlapi", + api_key="test-key", + base_url="https://gateway.internal.example.com/v1", + model="openai/gpt-5-mini", + reasoning_effort=None, + ) + + assert "X-AIMLAPI-Partner-ID" not in llm._client.default_headers + + +def test_aimlapi_attribution_merges_under_operator_headers(): + """Operator-supplied default headers win, and the shared constant is never mutated.""" + from hindsight_api.config import AIMLAPI_ATTRIBUTION_HEADERS, aimlapi_default_headers + + before = dict(AIMLAPI_ATTRIBUTION_HEADERS) + operator = {"X-Title": "Operator Override", "X-Component-Id": "hindsight"} + + merged = aimlapi_default_headers("aimlapi", "https://api.aimlapi.com/v1", operator) + + assert merged is not None + assert merged["X-Title"] == "Operator Override" + assert merged["X-Component-Id"] == "hindsight" + assert merged["X-AIMLAPI-Partner-ID"] == AIMLAPI_ATTRIBUTION_HEADERS["X-AIMLAPI-Partner-ID"] + # Neither the module constant nor the caller's dict was mutated in place. + assert AIMLAPI_ATTRIBUTION_HEADERS == before + assert operator == {"X-Title": "Operator Override", "X-Component-Id": "hindsight"} + + +def test_aimlapi_embeddings_carry_attribution(monkeypatch): + """The embeddings surface talks to the same gateway and should be tagged too.""" + from hindsight_api.config import AIMLAPI_ATTRIBUTION_HEADERS, clear_config_cache + from hindsight_api.engine.embeddings import create_embeddings_from_env + + monkeypatch.setenv("HINDSIGHT_API_EMBEDDINGS_PROVIDER", "aimlapi") + monkeypatch.setenv("HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY", "test-key") + clear_config_cache() + + try: + embeddings = create_embeddings_from_env() + assert embeddings.base_url == "https://api.aimlapi.com/v1" + assert embeddings.model == "openai/text-embedding-3-small" + assert embeddings.default_headers == AIMLAPI_ATTRIBUTION_HEADERS + assert embeddings.default_headers is not AIMLAPI_ATTRIBUTION_HEADERS + finally: + clear_config_cache() + + +def test_aimlapi_embeddings_require_a_key(monkeypatch): + """Missing key should name every env var that can supply one.""" + from hindsight_api.config import clear_config_cache + from hindsight_api.engine.embeddings import create_embeddings_from_env + + monkeypatch.setenv("HINDSIGHT_API_EMBEDDINGS_PROVIDER", "aimlapi") + monkeypatch.delenv("HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY", raising=False) + monkeypatch.delenv("HINDSIGHT_API_AIMLAPI_API_KEY", raising=False) + monkeypatch.delenv("HINDSIGHT_API_LLM_API_KEY", raising=False) + clear_config_cache() + + try: + with pytest.raises(ValueError, match="HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY"): + create_embeddings_from_env() + finally: + clear_config_cache() diff --git a/hindsight-docs/docs/developer/configuration.md b/hindsight-docs/docs/developer/configuration.md index eabc31575c..6cc3226266 100644 --- a/hindsight-docs/docs/developer/configuration.md +++ b/hindsight-docs/docs/developer/configuration.md @@ -268,7 +268,7 @@ For non-English banks (especially CJK) and the language/extraction-language trad | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `none` | `openai` | +| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `aimlapi`, `none` | `openai` | | `HINDSIGHT_API_LLM_API_KEY` | API key for providers that require one; unused by `github-copilot` | - | | `HINDSIGHT_API_LLM_MODEL` | Model name | `gpt-5-mini` | | `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default | @@ -432,6 +432,11 @@ export HINDSIGHT_API_LLM_PROVIDER=requesty export HINDSIGHT_API_LLM_API_KEY=your-requesty-api-key export HINDSIGHT_API_LLM_MODEL=openai/gpt-4o-mini +# aimlapi.com (OpenAI-compatible gateway, https://api.aimlapi.com/v1) +export HINDSIGHT_API_LLM_PROVIDER=aimlapi +export HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +export HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini + # DeepSeek (OpenAI-compatible, https://api.deepseek.com) export HINDSIGHT_API_LLM_PROVIDER=deepseek export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx @@ -713,9 +718,9 @@ server-level only (not overridable per tenant/bank) and a change requires a rest | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | +| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | | `HINDSIGHT_API_EMBEDDINGS_MAX_INPUT_TOKENS` | Applies to **every** provider. If set, truncate each text to this many tokens (counted with `HINDSIGHT_API_TOKENIZER_ENCODING`, approximate) before embedding. Set it to the model's real input limit (e.g. `8192` for Bedrock Titan V2, or a llama.cpp server's context, with a little headroom) so oversized content is truncated instead of failing the embed call permanently. Off by default. (Deprecated alias: `HINDSIGHT_API_EMBEDDINGS_LITELLM_SDK_MAX_INPUT_TOKENS`.) | - | -| `HINDSIGHT_API_EMBEDDINGS_QUERY_PREFIX` | Text prepended to every search before it is embedded. Set it when your endpoint serves an asymmetric model that expects a search instruction — e.g. `task: search result \| query: ` for `google/embeddinggemma-300m`, or `query: ` for E5. Applies to the providers that only accept plain text (`tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `litellm`, `litellm-sdk`); see the note below for the ones that don't need it. Trailing spaces are kept as written. | - (no prefix) | +| `HINDSIGHT_API_EMBEDDINGS_QUERY_PREFIX` | Text prepended to every search before it is embedded. Set it when your endpoint serves an asymmetric model that expects a search instruction — e.g. `task: search result \| query: ` for `google/embeddinggemma-300m`, or `query: ` for E5. Applies to the providers that only accept plain text (`tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `litellm`, `litellm-sdk`); see the note below for the ones that don't need it. Trailing spaces are kept as written. | - (no prefix) | | `HINDSIGHT_API_EMBEDDINGS_PASSAGE_PREFIX` | Text prepended to every stored memory/document before it is embedded — e.g. `title: none \| text: ` for `google/embeddinggemma-300m`, or `passage: ` for E5. Same providers as above. Trailing spaces are kept as written. | - (no prefix) | | `HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL` | Model for local provider. Models that ship their own search-text and stored-text instructions (e.g. the Qwen3-Embedding family) have them applied automatically — see the note below. | `BAAI/bge-small-en-v1.5` | | `HINDSIGHT_API_EMBEDDINGS_LOCAL_TRUST_REMOTE_CODE` | Allow loading models with custom code (security risk, disabled by default) | `false` | @@ -748,6 +753,8 @@ server-level only (not overridable per tenant/bank) and a change requires a rest | `HINDSIGHT_API_EMBEDDINGS_OPENROUTER_API_KEY` | OpenRouter API key for embeddings (falls back to `HINDSIGHT_API_OPENROUTER_API_KEY`, then `HINDSIGHT_API_LLM_API_KEY`) | - | | `HINDSIGHT_API_EMBEDDINGS_REQUESTY_API_KEY` | Requesty API key for embeddings (falls back to `HINDSIGHT_API_REQUESTY_API_KEY`, then `HINDSIGHT_API_LLM_API_KEY`) | - | | `HINDSIGHT_API_EMBEDDINGS_REQUESTY_MODEL` | Requesty embedding model | `openai/text-embedding-3-small` | +| `HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY` | aimlapi.com API key for embeddings (falls back to `HINDSIGHT_API_AIMLAPI_API_KEY`, then `HINDSIGHT_API_LLM_API_KEY`) | - | +| `HINDSIGHT_API_EMBEDDINGS_AIMLAPI_MODEL` | aimlapi.com embedding model | `openai/text-embedding-3-small` | | `HINDSIGHT_API_EMBEDDINGS_OPENROUTER_MODEL` | OpenRouter embedding model | `perplexity/pplx-embed-v1-0.6b` | | `HINDSIGHT_API_EMBEDDINGS_ZEROENTROPY_API_KEY` | ZeroEntropy API key for embeddings | - | | `HINDSIGHT_API_EMBEDDINGS_ZEROENTROPY_MODEL` | ZeroEntropy embedding model | `zembed-1` | diff --git a/hindsight-docs/src/data/llmProviders.json b/hindsight-docs/src/data/llmProviders.json index 8bdf69b688..2e2e10a8f9 100644 --- a/hindsight-docs/src/data/llmProviders.json +++ b/hindsight-docs/src/data/llmProviders.json @@ -17,6 +17,7 @@ {"id": "volcano", "label": "Volcano Engine", "iconKey": "zap", "defaultModel": "doubao-pro-32k"}, {"id": "openrouter", "label": "OpenRouter", "iconKey": "globe", "defaultModel": "qwen/qwen3.5-9b"}, {"id": "requesty", "label": "Requesty", "iconKey": "openai-compatible", "defaultModel": "openai/gpt-4o-mini"}, + {"id": "aimlapi", "label": "aimlapi.com", "iconKey": "openai-compatible", "defaultModel": "openai/gpt-5-mini"}, {"id": "openai-codex", "label": "OpenAI Codex", "iconKey": "openai", "defaultModel": "gpt-5.4-mini"}, {"id": "claude-code", "label": "Claude Code", "iconKey": "anthropic", "defaultModel": "claude-sonnet-4-5-20250929"}, {"id": "github-copilot","label": "GitHub Copilot", "iconKey": "terminal", "defaultModel": "gpt-5.6-terra"}, diff --git a/hindsight-embed/hindsight_embed/control_center/providers.py b/hindsight-embed/hindsight_embed/control_center/providers.py index 5e337a9b0c..5fecaf6be1 100644 --- a/hindsight-embed/hindsight_embed/control_center/providers.py +++ b/hindsight-embed/hindsight_embed/control_center/providers.py @@ -31,5 +31,6 @@ class ProviderInfo: ProviderInfo("minimax", "MiniMax", needs_api_key=True), ProviderInfo("zai", "Z.ai", needs_api_key=True), ProviderInfo("atlas", "Atlas Cloud", needs_api_key=True, default_base_url="https://api.atlascloud.ai/v1"), + ProviderInfo("aimlapi", "aimlapi.com", needs_api_key=True, default_base_url="https://api.aimlapi.com/v1"), ProviderInfo("volcano", "Volcano", needs_api_key=True), ) diff --git a/hindsight-embed/hindsight_embed/env.example b/hindsight-embed/hindsight_embed/env.example index 97681cc5fd..51a02e5b89 100644 --- a/hindsight-embed/hindsight_embed/env.example +++ b/hindsight-embed/hindsight_embed/env.example @@ -2,7 +2,7 @@ # Copy this file to .env and fill in your values # LLM Configuration (Required) -# Supported providers: openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, volcano, openai-codex, claude-code, github-copilot +# Supported providers: openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, aimlapi, volcano, openai-codex, claude-code, github-copilot HINDSIGHT_API_LLM_PROVIDER=openai HINDSIGHT_API_LLM_API_KEY=your-api-key-here HINDSIGHT_API_LLM_MODEL=gpt-4o-mini @@ -128,6 +128,11 @@ HINDSIGHT_API_LLM_MODEL=gpt-4o-mini # HINDSIGHT_API_LLM_API_KEY=your-atlascloud-api-key # HINDSIGHT_API_LLM_MODEL=deepseek-ai/deepseek-v4-pro # reasoning model; also Qwen / GLM / Kimi / MiniMax, etc. +# Example: aimlapi.com configuration (OpenAI-compatible gateway, https://api.aimlapi.com/v1) +# HINDSIGHT_API_LLM_PROVIDER=aimlapi +# HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +# HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini # catalog at https://api.aimlapi.com/v1/models + # Example: LM Studio local configuration (Qwen 2.5 32B recommended) # HINDSIGHT_API_LLM_PROVIDER=lmstudio # HINDSIGHT_API_LLM_API_KEY=lmstudio @@ -307,7 +312,7 @@ HINDSIGHT_API_LOG_LEVEL=info # HINDSIGHT_API_FILE_PARSER_MARKITDOWN_OCR_DEFAULT_HEADERS= # Embeddings Configuration (Optional - uses local by default) -# Provider: "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "zeroentropy", "litellm", or "litellm-sdk" +# Provider: "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "aimlapi", "zeroentropy", "litellm", or "litellm-sdk" # HINDSIGHT_API_EMBEDDINGS_PROVIDER=local # For local provider: # HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5 diff --git a/skills/hindsight-docs/references/developer/configuration.md b/skills/hindsight-docs/references/developer/configuration.md index bf9c15a5b0..8ea013b675 100644 --- a/skills/hindsight-docs/references/developer/configuration.md +++ b/skills/hindsight-docs/references/developer/configuration.md @@ -268,7 +268,7 @@ For non-English banks (especially CJK) and the language/extraction-language trad | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `none` | `openai` | +| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `aimlapi`, `none` | `openai` | | `HINDSIGHT_API_LLM_API_KEY` | API key for providers that require one; unused by `github-copilot` | - | | `HINDSIGHT_API_LLM_MODEL` | Model name | `gpt-5-mini` | | `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default | @@ -432,6 +432,11 @@ export HINDSIGHT_API_LLM_PROVIDER=requesty export HINDSIGHT_API_LLM_API_KEY=your-requesty-api-key export HINDSIGHT_API_LLM_MODEL=openai/gpt-4o-mini +# aimlapi.com (OpenAI-compatible gateway, https://api.aimlapi.com/v1) +export HINDSIGHT_API_LLM_PROVIDER=aimlapi +export HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +export HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini + # DeepSeek (OpenAI-compatible, https://api.deepseek.com) export HINDSIGHT_API_LLM_PROVIDER=deepseek export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx @@ -713,9 +718,9 @@ server-level only (not overridable per tenant/bank) and a change requires a rest | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | +| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | | `HINDSIGHT_API_EMBEDDINGS_MAX_INPUT_TOKENS` | Applies to **every** provider. If set, truncate each text to this many tokens (counted with `HINDSIGHT_API_TOKENIZER_ENCODING`, approximate) before embedding. Set it to the model's real input limit (e.g. `8192` for Bedrock Titan V2, or a llama.cpp server's context, with a little headroom) so oversized content is truncated instead of failing the embed call permanently. Off by default. (Deprecated alias: `HINDSIGHT_API_EMBEDDINGS_LITELLM_SDK_MAX_INPUT_TOKENS`.) | - | -| `HINDSIGHT_API_EMBEDDINGS_QUERY_PREFIX` | Text prepended to every search before it is embedded. Set it when your endpoint serves an asymmetric model that expects a search instruction — e.g. `task: search result \| query: ` for `google/embeddinggemma-300m`, or `query: ` for E5. Applies to the providers that only accept plain text (`tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `litellm`, `litellm-sdk`); see the note below for the ones that don't need it. Trailing spaces are kept as written. | - (no prefix) | +| `HINDSIGHT_API_EMBEDDINGS_QUERY_PREFIX` | Text prepended to every search before it is embedded. Set it when your endpoint serves an asymmetric model that expects a search instruction — e.g. `task: search result \| query: ` for `google/embeddinggemma-300m`, or `query: ` for E5. Applies to the providers that only accept plain text (`tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `litellm`, `litellm-sdk`); see the note below for the ones that don't need it. Trailing spaces are kept as written. | - (no prefix) | | `HINDSIGHT_API_EMBEDDINGS_PASSAGE_PREFIX` | Text prepended to every stored memory/document before it is embedded — e.g. `title: none \| text: ` for `google/embeddinggemma-300m`, or `passage: ` for E5. Same providers as above. Trailing spaces are kept as written. | - (no prefix) | | `HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL` | Model for local provider. Models that ship their own search-text and stored-text instructions (e.g. the Qwen3-Embedding family) have them applied automatically — see the note below. | `BAAI/bge-small-en-v1.5` | | `HINDSIGHT_API_EMBEDDINGS_LOCAL_TRUST_REMOTE_CODE` | Allow loading models with custom code (security risk, disabled by default) | `false` | @@ -748,6 +753,8 @@ server-level only (not overridable per tenant/bank) and a change requires a rest | `HINDSIGHT_API_EMBEDDINGS_OPENROUTER_API_KEY` | OpenRouter API key for embeddings (falls back to `HINDSIGHT_API_OPENROUTER_API_KEY`, then `HINDSIGHT_API_LLM_API_KEY`) | - | | `HINDSIGHT_API_EMBEDDINGS_REQUESTY_API_KEY` | Requesty API key for embeddings (falls back to `HINDSIGHT_API_REQUESTY_API_KEY`, then `HINDSIGHT_API_LLM_API_KEY`) | - | | `HINDSIGHT_API_EMBEDDINGS_REQUESTY_MODEL` | Requesty embedding model | `openai/text-embedding-3-small` | +| `HINDSIGHT_API_EMBEDDINGS_AIMLAPI_API_KEY` | aimlapi.com API key for embeddings (falls back to `HINDSIGHT_API_AIMLAPI_API_KEY`, then `HINDSIGHT_API_LLM_API_KEY`) | - | +| `HINDSIGHT_API_EMBEDDINGS_AIMLAPI_MODEL` | aimlapi.com embedding model | `openai/text-embedding-3-small` | | `HINDSIGHT_API_EMBEDDINGS_OPENROUTER_MODEL` | OpenRouter embedding model | `perplexity/pplx-embed-v1-0.6b` | | `HINDSIGHT_API_EMBEDDINGS_ZEROENTROPY_API_KEY` | ZeroEntropy API key for embeddings | - | | `HINDSIGHT_API_EMBEDDINGS_ZEROENTROPY_MODEL` | ZeroEntropy embedding model | `zembed-1` | diff --git a/skills/hindsight-docs/references/developer/models.md b/skills/hindsight-docs/references/developer/models.md index 7b3c186493..fa16dba072 100644 --- a/skills/hindsight-docs/references/developer/models.md +++ b/skills/hindsight-docs/references/developer/models.md @@ -37,6 +37,7 @@ Used for fact extraction, entity resolution, mental model consolidation, and ans - Volcano Engine - OpenRouter - Requesty +- aimlapi.com - OpenAI Codex - Claude Code - GitHub Copilot @@ -120,6 +121,7 @@ Beyond basic generation, some providers support optional features that lower cos | Volcano Engine (`volcano`) | — | — | | OpenRouter (`openrouter`) | — | — | | Requesty (`requesty`) | — | — | +| aimlapi.com (`aimlapi`) | — | — | | OpenAI Codex (`openai-codex`) | — | — | | Claude Code (`claude-code`) | — | — | | GitHub Copilot (`github-copilot`) | — | — | @@ -186,6 +188,7 @@ Each provider has a recommended default model that's used when `HINDSIGHT_API_LL | `volcano` | `doubao-pro-32k` | | `openrouter` | `qwen/qwen3.5-9b` | | `requesty` | `openai/gpt-4o-mini` | +| `aimlapi` | `openai/gpt-5-mini` | | `openai-codex` | `gpt-5.4-mini` | | `claude-code` | `claude-sonnet-4-5-20250929` | | `github-copilot` | `gpt-5.6-terra` | diff --git a/skills/hindsight-docs/references/faq.md b/skills/hindsight-docs/references/faq.md index df1126cb68..dee0649dba 100644 --- a/skills/hindsight-docs/references/faq.md +++ b/skills/hindsight-docs/references/faq.md @@ -87,6 +87,7 @@ Browse all supported integrations in the Integrations Hub. - Volcano Engine - OpenRouter - Requesty +- aimlapi.com - OpenAI Codex - Claude Code - GitHub Copilot From 90132f67738448e768c2c8bb8aa77663f85d4f27 Mon Sep 17 00:00:00 2001 From: aimlapi Date: Thu, 3 Sep 2026 04:27:08 +0500 Subject: [PATCH 2/3] =?UTF-8?q?chore(aimlapi):=20fork-only=20placement=20?= =?UTF-8?q?=E2=80=94=20do=20not=20send=20upstream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves aimlapi.com to the front of the hand-ordered, user-facing provider lists: the docs provider grid/table source, the two provider enum rows in the configuration reference, the Provider Examples block, the .env.example supported-provider line and example blocks, and the embed control center's wizard dropdown catalog. The generated docs skill is refreshed from those sources. This is partnership placement, not a technical requirement. It is isolated in its own commit so it can be dropped with a single revert before the provider itself is offered upstream — reordering someone else's list to put ourselves first is not something a maintainer should have to argue about in review. No badge or "featured" flag was invented: llmProviders.json has no such field. The only marker used is the parenthetical the Provider Examples block already applies to Groq. Machine-readable orderings are untouched: the valid-provider and factory lists in llm_wrapper.py / openai_compatible_llm.py are validation sets whose order no user ever sees, and PROVIDER_DEFAULT_MODELS is a lookup table, so all of them keep aimlapi in the position the feature commit put it. --- .env.example | 14 +++++++------- hindsight-docs/docs/developer/configuration.md | 14 +++++++------- hindsight-docs/src/data/llmProviders.json | 2 +- .../hindsight_embed/control_center/providers.py | 2 +- hindsight-embed/hindsight_embed/env.example | 14 +++++++------- .../references/developer/configuration.md | 14 +++++++------- .../hindsight-docs/references/developer/models.md | 6 +++--- skills/hindsight-docs/references/faq.md | 2 +- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.env.example b/.env.example index 51a02e5b89..bc2498d5bf 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ # Copy this file to .env and fill in your values # LLM Configuration (Required) -# Supported providers: openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, aimlapi, volcano, openai-codex, claude-code, github-copilot +# Supported providers: aimlapi, openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, volcano, openai-codex, claude-code, github-copilot HINDSIGHT_API_LLM_PROVIDER=openai HINDSIGHT_API_LLM_API_KEY=your-api-key-here HINDSIGHT_API_LLM_MODEL=gpt-4o-mini @@ -85,6 +85,11 @@ HINDSIGHT_API_LLM_MODEL=gpt-4o-mini # For debugging otherwise-unreproducible rejected calls. Off by default. # HINDSIGHT_API_LLM_DEBUG_DUMP_4XX=false +# Example: aimlapi.com configuration (OpenAI-compatible gateway, https://api.aimlapi.com/v1) +# HINDSIGHT_API_LLM_PROVIDER=aimlapi +# HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +# HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini # catalog at https://api.aimlapi.com/v1/models + # Example: Anthropic Claude configuration # HINDSIGHT_API_LLM_PROVIDER=anthropic # HINDSIGHT_API_LLM_API_KEY=your-anthropic-api-key @@ -128,11 +133,6 @@ HINDSIGHT_API_LLM_MODEL=gpt-4o-mini # HINDSIGHT_API_LLM_API_KEY=your-atlascloud-api-key # HINDSIGHT_API_LLM_MODEL=deepseek-ai/deepseek-v4-pro # reasoning model; also Qwen / GLM / Kimi / MiniMax, etc. -# Example: aimlapi.com configuration (OpenAI-compatible gateway, https://api.aimlapi.com/v1) -# HINDSIGHT_API_LLM_PROVIDER=aimlapi -# HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key -# HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini # catalog at https://api.aimlapi.com/v1/models - # Example: LM Studio local configuration (Qwen 2.5 32B recommended) # HINDSIGHT_API_LLM_PROVIDER=lmstudio # HINDSIGHT_API_LLM_API_KEY=lmstudio @@ -312,7 +312,7 @@ HINDSIGHT_API_LOG_LEVEL=info # HINDSIGHT_API_FILE_PARSER_MARKITDOWN_OCR_DEFAULT_HEADERS= # Embeddings Configuration (Optional - uses local by default) -# Provider: "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "aimlapi", "zeroentropy", "litellm", or "litellm-sdk" +# Provider: "aimlapi", "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "zeroentropy", "litellm", or "litellm-sdk" # HINDSIGHT_API_EMBEDDINGS_PROVIDER=local # For local provider: # HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5 diff --git a/hindsight-docs/docs/developer/configuration.md b/hindsight-docs/docs/developer/configuration.md index 6cc3226266..65da3b34e9 100644 --- a/hindsight-docs/docs/developer/configuration.md +++ b/hindsight-docs/docs/developer/configuration.md @@ -268,7 +268,7 @@ For non-English banks (especially CJK) and the language/extraction-language trad | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `aimlapi`, `none` | `openai` | +| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `aimlapi`, `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `none` | `openai` | | `HINDSIGHT_API_LLM_API_KEY` | API key for providers that require one; unused by `github-copilot` | - | | `HINDSIGHT_API_LLM_MODEL` | Model name | `gpt-5-mini` | | `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default | @@ -319,6 +319,11 @@ When `HINDSIGHT_API_LLM_PROVIDER=ollama`, Hindsight no longer sends the previous **Provider Examples** ```bash +# aimlapi.com (recommended for breadth of model choice behind one key) +export HINDSIGHT_API_LLM_PROVIDER=aimlapi +export HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +export HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini + # Groq (recommended for fast inference) export HINDSIGHT_API_LLM_PROVIDER=groq export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx @@ -432,11 +437,6 @@ export HINDSIGHT_API_LLM_PROVIDER=requesty export HINDSIGHT_API_LLM_API_KEY=your-requesty-api-key export HINDSIGHT_API_LLM_MODEL=openai/gpt-4o-mini -# aimlapi.com (OpenAI-compatible gateway, https://api.aimlapi.com/v1) -export HINDSIGHT_API_LLM_PROVIDER=aimlapi -export HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key -export HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini - # DeepSeek (OpenAI-compatible, https://api.deepseek.com) export HINDSIGHT_API_LLM_PROVIDER=deepseek export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx @@ -718,7 +718,7 @@ server-level only (not overridable per tenant/bank) and a change requires a rest | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | +| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `aimlapi`, `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | | `HINDSIGHT_API_EMBEDDINGS_MAX_INPUT_TOKENS` | Applies to **every** provider. If set, truncate each text to this many tokens (counted with `HINDSIGHT_API_TOKENIZER_ENCODING`, approximate) before embedding. Set it to the model's real input limit (e.g. `8192` for Bedrock Titan V2, or a llama.cpp server's context, with a little headroom) so oversized content is truncated instead of failing the embed call permanently. Off by default. (Deprecated alias: `HINDSIGHT_API_EMBEDDINGS_LITELLM_SDK_MAX_INPUT_TOKENS`.) | - | | `HINDSIGHT_API_EMBEDDINGS_QUERY_PREFIX` | Text prepended to every search before it is embedded. Set it when your endpoint serves an asymmetric model that expects a search instruction — e.g. `task: search result \| query: ` for `google/embeddinggemma-300m`, or `query: ` for E5. Applies to the providers that only accept plain text (`tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `litellm`, `litellm-sdk`); see the note below for the ones that don't need it. Trailing spaces are kept as written. | - (no prefix) | | `HINDSIGHT_API_EMBEDDINGS_PASSAGE_PREFIX` | Text prepended to every stored memory/document before it is embedded — e.g. `title: none \| text: ` for `google/embeddinggemma-300m`, or `passage: ` for E5. Same providers as above. Trailing spaces are kept as written. | - (no prefix) | diff --git a/hindsight-docs/src/data/llmProviders.json b/hindsight-docs/src/data/llmProviders.json index 2e2e10a8f9..aa333d7ad5 100644 --- a/hindsight-docs/src/data/llmProviders.json +++ b/hindsight-docs/src/data/llmProviders.json @@ -1,4 +1,5 @@ [ + {"id": "aimlapi", "label": "aimlapi.com", "iconKey": "openai-compatible", "defaultModel": "openai/gpt-5-mini"}, {"id": "openai", "label": "OpenAI", "iconKey": "openai", "defaultModel": "gpt-4o-mini", "batchApi": true}, {"id": "openai-responses", "label": "OpenAI Responses", "iconKey": "openai", "defaultModel": "gpt-5.6"}, {"id": "anthropic", "label": "Anthropic", "iconKey": "anthropic", "defaultModel": "claude-haiku-4-5"}, @@ -17,7 +18,6 @@ {"id": "volcano", "label": "Volcano Engine", "iconKey": "zap", "defaultModel": "doubao-pro-32k"}, {"id": "openrouter", "label": "OpenRouter", "iconKey": "globe", "defaultModel": "qwen/qwen3.5-9b"}, {"id": "requesty", "label": "Requesty", "iconKey": "openai-compatible", "defaultModel": "openai/gpt-4o-mini"}, - {"id": "aimlapi", "label": "aimlapi.com", "iconKey": "openai-compatible", "defaultModel": "openai/gpt-5-mini"}, {"id": "openai-codex", "label": "OpenAI Codex", "iconKey": "openai", "defaultModel": "gpt-5.4-mini"}, {"id": "claude-code", "label": "Claude Code", "iconKey": "anthropic", "defaultModel": "claude-sonnet-4-5-20250929"}, {"id": "github-copilot","label": "GitHub Copilot", "iconKey": "terminal", "defaultModel": "gpt-5.6-terra"}, diff --git a/hindsight-embed/hindsight_embed/control_center/providers.py b/hindsight-embed/hindsight_embed/control_center/providers.py index 5fecaf6be1..504d370dd6 100644 --- a/hindsight-embed/hindsight_embed/control_center/providers.py +++ b/hindsight-embed/hindsight_embed/control_center/providers.py @@ -20,6 +20,7 @@ class ProviderInfo: # Ordered for display in the wizard dropdown. Mirrors the providers that # hindsight-api's PROVIDER_DEFAULT_MODELS supports. PROVIDER_CATALOG: tuple[ProviderInfo, ...] = ( + ProviderInfo("aimlapi", "aimlapi.com", needs_api_key=True, default_base_url="https://api.aimlapi.com/v1"), ProviderInfo("openai", "OpenAI", needs_api_key=True, default_base_url="https://api.openai.com/v1"), ProviderInfo("anthropic", "Anthropic", needs_api_key=True, default_base_url="https://api.anthropic.com"), ProviderInfo("gemini", "Google Gemini", needs_api_key=True), @@ -31,6 +32,5 @@ class ProviderInfo: ProviderInfo("minimax", "MiniMax", needs_api_key=True), ProviderInfo("zai", "Z.ai", needs_api_key=True), ProviderInfo("atlas", "Atlas Cloud", needs_api_key=True, default_base_url="https://api.atlascloud.ai/v1"), - ProviderInfo("aimlapi", "aimlapi.com", needs_api_key=True, default_base_url="https://api.aimlapi.com/v1"), ProviderInfo("volcano", "Volcano", needs_api_key=True), ) diff --git a/hindsight-embed/hindsight_embed/env.example b/hindsight-embed/hindsight_embed/env.example index 51a02e5b89..bc2498d5bf 100644 --- a/hindsight-embed/hindsight_embed/env.example +++ b/hindsight-embed/hindsight_embed/env.example @@ -2,7 +2,7 @@ # Copy this file to .env and fill in your values # LLM Configuration (Required) -# Supported providers: openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, aimlapi, volcano, openai-codex, claude-code, github-copilot +# Supported providers: aimlapi, openai, openai-responses, groq, ollama, gemini, anthropic, lmstudio, vertexai, minimax, deepseek, zai, atlas, volcano, openai-codex, claude-code, github-copilot HINDSIGHT_API_LLM_PROVIDER=openai HINDSIGHT_API_LLM_API_KEY=your-api-key-here HINDSIGHT_API_LLM_MODEL=gpt-4o-mini @@ -85,6 +85,11 @@ HINDSIGHT_API_LLM_MODEL=gpt-4o-mini # For debugging otherwise-unreproducible rejected calls. Off by default. # HINDSIGHT_API_LLM_DEBUG_DUMP_4XX=false +# Example: aimlapi.com configuration (OpenAI-compatible gateway, https://api.aimlapi.com/v1) +# HINDSIGHT_API_LLM_PROVIDER=aimlapi +# HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +# HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini # catalog at https://api.aimlapi.com/v1/models + # Example: Anthropic Claude configuration # HINDSIGHT_API_LLM_PROVIDER=anthropic # HINDSIGHT_API_LLM_API_KEY=your-anthropic-api-key @@ -128,11 +133,6 @@ HINDSIGHT_API_LLM_MODEL=gpt-4o-mini # HINDSIGHT_API_LLM_API_KEY=your-atlascloud-api-key # HINDSIGHT_API_LLM_MODEL=deepseek-ai/deepseek-v4-pro # reasoning model; also Qwen / GLM / Kimi / MiniMax, etc. -# Example: aimlapi.com configuration (OpenAI-compatible gateway, https://api.aimlapi.com/v1) -# HINDSIGHT_API_LLM_PROVIDER=aimlapi -# HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key -# HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini # catalog at https://api.aimlapi.com/v1/models - # Example: LM Studio local configuration (Qwen 2.5 32B recommended) # HINDSIGHT_API_LLM_PROVIDER=lmstudio # HINDSIGHT_API_LLM_API_KEY=lmstudio @@ -312,7 +312,7 @@ HINDSIGHT_API_LOG_LEVEL=info # HINDSIGHT_API_FILE_PARSER_MARKITDOWN_OCR_DEFAULT_HEADERS= # Embeddings Configuration (Optional - uses local by default) -# Provider: "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "aimlapi", "zeroentropy", "litellm", or "litellm-sdk" +# Provider: "aimlapi", "local" (default), "onnx", "tei", "openai", "cohere", "google", "openrouter", "zeroentropy", "litellm", or "litellm-sdk" # HINDSIGHT_API_EMBEDDINGS_PROVIDER=local # For local provider: # HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5 diff --git a/skills/hindsight-docs/references/developer/configuration.md b/skills/hindsight-docs/references/developer/configuration.md index 8ea013b675..fdd3aff2b1 100644 --- a/skills/hindsight-docs/references/developer/configuration.md +++ b/skills/hindsight-docs/references/developer/configuration.md @@ -268,7 +268,7 @@ For non-English banks (especially CJK) and the language/extraction-language trad | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `aimlapi`, `none` | `openai` | +| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `aimlapi`, `openai`, `openai-responses`, `openai-codex`, `claude-code`, `github-copilot`, `anthropic`, `gemini`, `groq`, `minimax`, `deepseek`, `zai`, `opencode-go`, `nous`, `xai-oauth`, `fireworks`, `ollama`, `ollama-cloud`, `lmstudio`, `llamacpp`, `vertexai`, `bedrock`, `litellm`, `litellmrouter`, `volcano`, `openrouter`, `requesty`, `none` | `openai` | | `HINDSIGHT_API_LLM_API_KEY` | API key for providers that require one; unused by `github-copilot` | - | | `HINDSIGHT_API_LLM_MODEL` | Model name | `gpt-5-mini` | | `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default | @@ -319,6 +319,11 @@ When `HINDSIGHT_API_LLM_PROVIDER=ollama`, Hindsight no longer sends the previous **Provider Examples** ```bash +# aimlapi.com (recommended for breadth of model choice behind one key) +export HINDSIGHT_API_LLM_PROVIDER=aimlapi +export HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key +export HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini + # Groq (recommended for fast inference) export HINDSIGHT_API_LLM_PROVIDER=groq export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx @@ -432,11 +437,6 @@ export HINDSIGHT_API_LLM_PROVIDER=requesty export HINDSIGHT_API_LLM_API_KEY=your-requesty-api-key export HINDSIGHT_API_LLM_MODEL=openai/gpt-4o-mini -# aimlapi.com (OpenAI-compatible gateway, https://api.aimlapi.com/v1) -export HINDSIGHT_API_LLM_PROVIDER=aimlapi -export HINDSIGHT_API_LLM_API_KEY=your-aimlapi-api-key -export HINDSIGHT_API_LLM_MODEL=openai/gpt-5-mini - # DeepSeek (OpenAI-compatible, https://api.deepseek.com) export HINDSIGHT_API_LLM_PROVIDER=deepseek export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx @@ -718,7 +718,7 @@ server-level only (not overridable per tenant/bank) and a change requires a rest | Variable | Description | Default | |----------|-------------|---------| -| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | +| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `aimlapi`, `local`, `onnx`, `tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `cohere`, `google`, `zeroentropy`, `litellm`, or `litellm-sdk` | `local` | | `HINDSIGHT_API_EMBEDDINGS_MAX_INPUT_TOKENS` | Applies to **every** provider. If set, truncate each text to this many tokens (counted with `HINDSIGHT_API_TOKENIZER_ENCODING`, approximate) before embedding. Set it to the model's real input limit (e.g. `8192` for Bedrock Titan V2, or a llama.cpp server's context, with a little headroom) so oversized content is truncated instead of failing the embed call permanently. Off by default. (Deprecated alias: `HINDSIGHT_API_EMBEDDINGS_LITELLM_SDK_MAX_INPUT_TOKENS`.) | - | | `HINDSIGHT_API_EMBEDDINGS_QUERY_PREFIX` | Text prepended to every search before it is embedded. Set it when your endpoint serves an asymmetric model that expects a search instruction — e.g. `task: search result \| query: ` for `google/embeddinggemma-300m`, or `query: ` for E5. Applies to the providers that only accept plain text (`tei`, `openai`, `openai-codex`, `openrouter`, `requesty`, `aimlapi`, `litellm`, `litellm-sdk`); see the note below for the ones that don't need it. Trailing spaces are kept as written. | - (no prefix) | | `HINDSIGHT_API_EMBEDDINGS_PASSAGE_PREFIX` | Text prepended to every stored memory/document before it is embedded — e.g. `title: none \| text: ` for `google/embeddinggemma-300m`, or `passage: ` for E5. Same providers as above. Trailing spaces are kept as written. | - (no prefix) | diff --git a/skills/hindsight-docs/references/developer/models.md b/skills/hindsight-docs/references/developer/models.md index fa16dba072..37cb9089fb 100644 --- a/skills/hindsight-docs/references/developer/models.md +++ b/skills/hindsight-docs/references/developer/models.md @@ -19,6 +19,7 @@ Used for fact extraction, entity resolution, mental model consolidation, and ans **Supported providers:** +- aimlapi.com - OpenAI - OpenAI Responses - Anthropic @@ -37,7 +38,6 @@ Used for fact extraction, entity resolution, mental model consolidation, and ans - Volcano Engine - OpenRouter - Requesty -- aimlapi.com - OpenAI Codex - Claude Code - GitHub Copilot @@ -103,6 +103,7 @@ Beyond basic generation, some providers support optional features that lower cos | Provider | Batch API | Explicit prompt caching | |----------|:---------:|:-----------------------:| +| aimlapi.com (`aimlapi`) | — | — | | OpenAI (`openai`) | ✅ | — | | OpenAI Responses (`openai-responses`) | — | — | | Anthropic (`anthropic`) | — | — | @@ -121,7 +122,6 @@ Beyond basic generation, some providers support optional features that lower cos | Volcano Engine (`volcano`) | — | — | | OpenRouter (`openrouter`) | — | — | | Requesty (`requesty`) | — | — | -| aimlapi.com (`aimlapi`) | — | — | | OpenAI Codex (`openai-codex`) | — | — | | Claude Code (`claude-code`) | — | — | | GitHub Copilot (`github-copilot`) | — | — | @@ -170,6 +170,7 @@ Each provider has a recommended default model that's used when `HINDSIGHT_API_LL | Provider | Default Model | |----------|--------------| +| `aimlapi` | `openai/gpt-5-mini` | | `openai` | `gpt-4o-mini` | | `openai-responses` | `gpt-5.6` | | `anthropic` | `claude-haiku-4-5` | @@ -188,7 +189,6 @@ Each provider has a recommended default model that's used when `HINDSIGHT_API_LL | `volcano` | `doubao-pro-32k` | | `openrouter` | `qwen/qwen3.5-9b` | | `requesty` | `openai/gpt-4o-mini` | -| `aimlapi` | `openai/gpt-5-mini` | | `openai-codex` | `gpt-5.4-mini` | | `claude-code` | `claude-sonnet-4-5-20250929` | | `github-copilot` | `gpt-5.6-terra` | diff --git a/skills/hindsight-docs/references/faq.md b/skills/hindsight-docs/references/faq.md index dee0649dba..93c252c896 100644 --- a/skills/hindsight-docs/references/faq.md +++ b/skills/hindsight-docs/references/faq.md @@ -69,6 +69,7 @@ Browse all supported integrations in the Integrations Hub. ### Which LLM providers are supported? +- aimlapi.com - OpenAI - OpenAI Responses - Anthropic @@ -87,7 +88,6 @@ Browse all supported integrations in the Integrations Hub. - Volcano Engine - OpenRouter - Requesty -- aimlapi.com - OpenAI Codex - Claude Code - GitHub Copilot From 18ac3a8425f75351a29e36432d1589ac3d2c0ed1 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 3 Sep 2026 18:07:41 +0500 Subject: [PATCH 3/3] fix(aimlapi): use the registered partner id The placeholder part_hindsight was a readable stand-in chosen before the partner was registered. Registration mints the id server-side, so the real value is part_fO6J5vQsER4jNM0YFhQkld2H. A wrong or unknown partner id is accepted with a 200 and silently not attributed, so this would not have surfaced at runtime. --- hindsight-api-slim/hindsight_api/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hindsight-api-slim/hindsight_api/config.py b/hindsight-api-slim/hindsight_api/config.py index 9f69db05b9..0308ea0a1b 100644 --- a/hindsight-api-slim/hindsight_api/config.py +++ b/hindsight-api-slim/hindsight_api/config.py @@ -1238,7 +1238,7 @@ def _parse_strategy_boosts(raw: str | None) -> dict[str, str]: AIMLAPI_ATTRIBUTION_HEADERS: dict[str, str] = { "HTTP-Referer": "https://github.com/vectorize-io/hindsight", "X-Title": "Hindsight", - "X-AIMLAPI-Partner-ID": "part_hindsight", + "X-AIMLAPI-Partner-ID": "part_fO6J5vQsER4jNM0YFhQkld2H", "X-AIMLAPI-Source": "agent/hindsight", }