-
Notifications
You must be signed in to change notification settings - Fork 1
test(api): lock Responses service_tier honesty over HTTP #486
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
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 |
|---|---|---|
|
|
@@ -215,6 +215,10 @@ def __init__( | |
| ) -> None: | ||
| self.timeout = timeout | ||
| self.max_output_tokens = max_output_tokens | ||
| self.default_temperature = 0.2 | ||
| self.default_top_p: float | None = None | ||
| self.default_presence_penalty: float | None = None | ||
| self.default_frequency_penalty: float | None = None | ||
| self.max_retries = max_retries | ||
| self.retry_backoff = retry_backoff | ||
| self.retry_backoff_cap = retry_backoff_cap | ||
|
|
@@ -230,7 +234,7 @@ def __init__( | |
| @staticmethod | ||
| def _build_ssl_context(ca_bundle: str | None, verify_tls: bool) -> ssl.SSLContext: | ||
| if not verify_tls: | ||
| return ssl._create_unverified_context() # nosec B323 - explicit dev-only provider TLS opt-out. | ||
| return ssl._create_unverified_context() # nosec B323 - explicit dev-only provider TLS opt-out. # nosemgrep -- unverified-ssl-context: intentional, default-secure (verify_tls defaults True) dev-only opt-out for self-signed endpoints. | ||
| if ca_bundle: | ||
| if not os.path.isfile(ca_bundle): | ||
| raise ValueError(f"provider CA bundle does not exist: {ca_bundle}") | ||
|
|
@@ -246,9 +250,29 @@ def take_usage(self) -> dict[str, Any] | None: | |
| self._local.usage = None | ||
| return usage | ||
|
|
||
| def chat(self, agent: ModelAgent, messages: list[ChatMessage], temperature: float = 0.2) -> str: | ||
| """Send messages to a mock or OpenAI-compatible chat endpoint with retries.""" | ||
| def chat( | ||
| self, | ||
| agent: ModelAgent, | ||
| messages: list[ChatMessage], | ||
| temperature: float | None = None, | ||
| top_p: float | None = None, | ||
| ) -> str: | ||
| """Send messages to a mock or OpenAI-compatible chat endpoint with retries. | ||
|
|
||
| When ``temperature``/``top_p`` are omitted, ``default_temperature`` and | ||
| ``default_top_p`` are used so request-scoped Completions sampling can be | ||
| applied without threading kwargs through every orchestrator hop. | ||
| """ | ||
| self._local.usage = None | ||
| # Expose the effective sampling knobs for request-path tests / diagnostics. | ||
| effective_temperature = self.default_temperature if temperature is None else temperature | ||
| effective_top_p = self.default_top_p if top_p is None else top_p | ||
| effective_presence = self.default_presence_penalty | ||
| effective_frequency = self.default_frequency_penalty | ||
| self._local.last_temperature = effective_temperature | ||
| self._local.last_top_p = effective_top_p | ||
| self._local.last_presence_penalty = effective_presence | ||
| self._local.last_frequency_penalty = effective_frequency | ||
| if agent.base_url.startswith("mock://"): | ||
| return self._mock(agent, messages) | ||
|
|
||
|
|
@@ -262,10 +286,16 @@ def chat(self, agent: ModelAgent, messages: list[ChatMessage], temperature: floa | |
| payload = { # pragma: no cover | ||
| "model": agent.model, | ||
| "messages": messages, | ||
| "temperature": temperature, | ||
| "temperature": effective_temperature, | ||
| "stream": False, | ||
| "max_tokens": self.max_output_tokens, | ||
| } | ||
| if effective_top_p is not None: # pragma: no cover | ||
| payload["top_p"] = effective_top_p | ||
| if effective_presence is not None: # pragma: no cover | ||
| payload["presence_penalty"] = effective_presence | ||
| if effective_frequency is not None: # pragma: no cover | ||
| payload["frequency_penalty"] = effective_frequency | ||
| return self._send_with_retry(agent, payload) | ||
|
|
||
| def _send_with_retry(self, agent: ModelAgent, payload: dict[str, Any]) -> str: | ||
|
|
@@ -307,7 +337,7 @@ def _send(self, agent: ModelAgent, payload: dict[str, Any]) -> str: | |
|
|
||
| def _open_provider(self, request: urllib.request.Request) -> Any: | ||
| """Open a provider request built from a validated provider URL.""" | ||
| return urllib.request.urlopen( # nosec B310 - request URL comes from _provider_url after provider validation. | ||
| return urllib.request.urlopen( # nosec B310 - request URL comes from _provider_url after provider validation. # nosemgrep -- dynamic-urllib-use: URL is built by _provider_url after scheme/host validation; egress to loopback/private/reserved is blocked. | ||
| request, | ||
| timeout=self.timeout, | ||
| context=self._ssl_context, | ||
|
|
@@ -897,7 +927,23 @@ def proxy_completion( | |
| text = self._latest_user_text(messages) | ||
| else: | ||
| text = _coerce_input_text(body.get("input")) | ||
| agent = self._select_agent(text, "worker") | ||
| requested_model = body.get("model") | ||
| # When the client names a model, resolve a pool agent that actually serves | ||
| # that model id. Silent rewrite to an unrelated agent.model is a commercial | ||
| # honesty failure for OpenAI SDKs (passthrough tools/Responses paths). | ||
| if isinstance(requested_model, str) and requested_model.strip(): | ||
| matched = [ | ||
| agent | ||
| for agent in self.agents | ||
| if not getattr(agent, "disabled", False) and agent.model == requested_model | ||
| ] | ||
| if not matched: | ||
| raise ValueError( | ||
| f"model {requested_model!r} is not available in the agent pool" | ||
| ) | ||
| agent = matched[0] | ||
| else: | ||
| agent = self._select_agent(text, "worker") | ||
| upstream = { | ||
| key: value | ||
| for key, value in body.items() | ||
|
|
@@ -1695,6 +1741,52 @@ def list_agents(self, page_number: int = 1, page_size: int = 10) -> list[dict[st | |
| end = start + page_size | ||
| return [self._agent_to_admin_payload(agent) for agent in self.agents[start:end]] | ||
|
|
||
| def list_openai_models(self) -> dict[str, Any]: | ||
| """Return an OpenAI-compatible ``/v1/models`` list from the agent pool. | ||
|
|
||
| Buyers discover selectable model ids without admin-scope agent pool access. | ||
| Each enabled agent model appears once; gateway default | ||
| ``contextual-orchestrator`` is always first. | ||
| """ | ||
| created = 1_700_000_000 # stable epoch so list responses are deterministic | ||
| data: list[dict[str, Any]] = [ | ||
| { | ||
| "id": "contextual-orchestrator", | ||
| "object": "model", | ||
| "created": created, | ||
| "owned_by": "contextual-orchestrator", | ||
| } | ||
| ] | ||
| seen: set[str] = {"contextual-orchestrator"} | ||
| for agent in self.agents: | ||
| if agent.disabled: | ||
| continue | ||
| model_id = str(agent.model).strip() | ||
| if not model_id or model_id in seen: | ||
| continue | ||
| seen.add(model_id) | ||
| data.append( | ||
| { | ||
| "id": model_id, | ||
| "object": "model", | ||
| "created": created, | ||
| "owned_by": agent.provider_name | ||
| or self._infer_provider_name(agent.base_url) | ||
| or "agent_pool", | ||
| } | ||
| ) | ||
| return {"object": "list", "data": data} | ||
|
Comment on lines
+1751
to
+1778
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. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 광고한 기본 모델을 실행 가능하게 하십시오.
🤖 Prompt for AI Agents |
||
|
|
||
| def get_openai_model(self, model_id: str) -> dict[str, Any]: | ||
| """Return one OpenAI model object or raise ``KeyError`` when unknown.""" | ||
| wanted = (model_id or "").strip() | ||
| if not wanted: | ||
| raise KeyError(model_id) | ||
| for item in self.list_openai_models()["data"]: | ||
| if item["id"] == wanted: | ||
| return item | ||
| raise KeyError(model_id) | ||
|
|
||
| def list_recent_runs(self, page_number: int = 1, page_size: int = 10) -> list[dict[str, Any]]: | ||
| """Return a paginated list of recent workflow run records.""" | ||
| if page_number < 1 or page_size < 1: # pragma: no cover | ||
|
|
@@ -8517,6 +8609,29 @@ def chat_completion_response( | |
| } | ||
|
|
||
|
|
||
| def text_completion_response( | ||
| result: dict[str, Any], | ||
| model: str = "contextual-orchestrator", | ||
| usage: dict[str, int] | None = None, | ||
| ) -> dict[str, Any]: # pragma: no cover | ||
| """Wrap orchestration output as OpenAI legacy ``text_completion`` (``/v1/completions``).""" | ||
| return { | ||
| "id": f"cmpl-{int(time.time() * 1000)}", | ||
| "object": "text_completion", | ||
| "created": int(time.time()), | ||
| "model": model, | ||
| "choices": [ | ||
| { | ||
| "index": 0, | ||
| "text": result["answer"], | ||
| "logprobs": None, | ||
| "finish_reason": "stop", | ||
| } | ||
| ], | ||
| "usage": usage or {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}, | ||
| } | ||
|
|
||
|
|
||
| _STREAM_CHUNK_SIZE = 32 | ||
|
|
||
|
|
||
|
|
||
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.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
스트리밍과 배치 경로에도 동일한 샘플링 설정을 적용하십시오.
chat()만default_temperature,default_top_p, penalty 기본값을 사용합니다.stream_chat()은 고정값0.2를 사용합니다.batch_chat()도 독립적인 기본값을 사용합니다. 따라서 설정된 샘플링 값은 스트리밍 또는 배치 요청에서 무시됩니다.stream_chat()과batch_chat()이 같은 유효 샘플링 값을 계산하고 provider payload에 전달하도록 변경하십시오.top_p,presence_penalty,frequency_penalty도 동일하게 처리하십시오.🤖 Prompt for AI Agents