Skip to content

Refactor capi.py: provider pattern for endpoint-specific logic#187

Merged
anticomputer merged 2 commits intomainfrom
anticomputer/capi-cleanup
Apr 2, 2026
Merged

Refactor capi.py: provider pattern for endpoint-specific logic#187
anticomputer merged 2 commits intomainfrom
anticomputer/capi-cleanup

Conversation

@anticomputer
Copy link
Copy Markdown
Contributor

Replace the StrEnum + three scattered match/case blocks with a single APIProvider dataclass registry. Endpoint-specific behavior (catalog path, response parsing, tool-call detection, headers) now lives in one place per provider. Copilot-Integration-Id header is no longer leaked to non-Copilot endpoints.

Copilot AI review requested due to automatic review settings April 2, 2026 15:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the CAPI integration to centralize endpoint-specific behavior behind an APIProvider registry, reducing scattered endpoint conditionals and preventing Copilot-only headers from being sent to other providers.

Changes:

  • Introduces an APIProvider dataclass + provider registry to encapsulate per-endpoint logic (catalog path, parsing, tool-call detection, headers).
  • Updates model catalog + tool-call capability helpers to delegate behavior to the selected provider.
  • Updates the agent client construction to only attach provider-specific headers (e.g., Copilot-Integration-Id) when appropriate, and adjusts tests accordingly.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/seclab_taskflow_agent/capi.py Replaces endpoint enum/match blocks with provider registry and provider-based model/tool-call logic.
src/seclab_taskflow_agent/agent.py Uses provider-derived defaults and ensures provider-specific headers are only sent to matching endpoints.
tests/test_capi_extended.py Updates/expands tests to cover provider registry and new tool-call capability semantics.
tests/test_api_endpoint_config.py Removes enum-based assertions and adds provider base URL resolution coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@p- p- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We just changed the default models this morning

@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from b4b89c0 to 5776ca1 Compare April 2, 2026 15:51
Copy link
Copy Markdown
Contributor Author

@anticomputer anticomputer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebased on main, addressed feedback:

Default models (p-): Updated all provider defaults to gpt-4.1 to match main.

base_url unused (copilot-reviewer): list_capi_models() now uses provider.base_url as the canonical URL instead of the raw parameter. Known providers always resolve to their configured base URL.

_DEFAULT_PROVIDER dead code (copilot-reviewer): Removed. get_provider() constructs the fallback inline.

check_tool_calls default (copilot-reviewer): Keeping bool(model_info) as the base default. The previous heuristic ("gpt-" in model.lower()) was worse — it missed o1, o3-mini, o3, and any non-gpt model. Defaulting to False would break custom endpoints that don't publish capability metadata. This only affects CLI -l listing, not runtime behavior.

Copilot AI review requested due to automatic review settings April 2, 2026 16:01
@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from 5776ca1 to 11538ac Compare April 2, 2026 16:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (4)

src/seclab_taskflow_agent/capi.py:169

  • httpx.URL(base).join(provider.models_catalog) will drop the last path segment when base has a path and doesn’t end with / (urljoin semantics). With the OpenAI provider’s base_url="https://api.openai.com/v1" and models_catalog="models", this will likely request https://api.openai.com/models instead of .../v1/models. Consider either (a) ensuring provider base URLs intended for joining end with a trailing slash, or (b) making models_catalog an absolute/fully-qualified path for providers like OpenAI (e.g., v1/models) so the final catalog URL is correct.
        r = httpx.get(
            httpx.URL(base).join(provider.models_catalog),
            headers=headers,

src/seclab_taskflow_agent/capi.py:66

  • APIProvider.check_tool_calls() currently defaults to return bool(model_info), which makes list_tool_call_models() treat every catalog entry as tool-call capable for providers that don’t override this (notably the OpenAI provider). That contradicts the list_tool_call_models docstring (“only models that support tool calls”) and regresses prior OpenAI filtering behavior. Suggest adding an explicit OpenAI provider implementation (or other reliable rule) so non-chat models (embeddings/audio/etc.) don’t get incorrectly reported as tool-call capable.
    def check_tool_calls(self, _model: str, model_info: dict) -> bool:
        """Return True if *model* supports tool calls according to its catalog entry."""
        # Default: optimistically assume support when present in catalog
        return bool(model_info)

src/seclab_taskflow_agent/capi.py:124

  • For unknown endpoints, get_provider() returns APIProvider(name="custom", base_url=url) which inherits the default default_model="gpt-4.1". This silently changes the previous behavior where unknown endpoints forced an explicit default model, and it can cause confusing runtime failures for custom/self-hosted providers that don’t have a gpt-4.1 model. Consider setting a sentinel/empty default_model for the custom provider (or requiring COPILOT_DEFAULT_MODEL when name=="custom") to preserve the explicit configuration requirement.
def get_provider(endpoint: str | None = None) -> APIProvider:
    """Return the ``APIProvider`` for the given (or configured) endpoint URL."""
    url = endpoint or get_AI_endpoint()
    netloc = urlparse(url).netloc
    provider = _PROVIDERS.get(netloc)
    if provider is not None:
        return provider
    # Unknown endpoint — return a generic provider with the given base URL
    return APIProvider(name="custom", base_url=url)

src/seclab_taskflow_agent/capi.py:197

  • list_tool_call_models() behavior changed to use the provider registry (and now depends on each provider’s check_tool_calls implementation), but there are no direct tests covering list_tool_call_models for the built-in providers (Copilot/GitHub Models/OpenAI). Adding tests here would help catch regressions like over-including non-tool-capable models for OpenAI or incorrect catalog URL construction.
def list_tool_call_models(token: str, endpoint: str | None = None) -> dict[str, dict]:
    """Return only models that support tool calls."""
    models = list_capi_models(token, endpoint)
    provider = get_provider(endpoint)
    return {
        mid: info
        for mid, info in models.items()
        if provider.check_tool_calls(mid, info)
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from 11538ac to e1029a9 Compare April 2, 2026 16:07
Copilot AI review requested due to automatic review settings April 2, 2026 16:13
@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from e1029a9 to 01041fd Compare April 2, 2026 16:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/seclab_taskflow_agent/capi.py:188

  • The catalog URL is constructed with httpx.URL(base).join(provider.models_catalog). When base_url includes a path segment like /v1 (OpenAI) or a custom endpoint with versioned paths, URL.join() treats the base path as a file and can drop the last segment (e.g. https://api.openai.com/v1 + models becomes https://api.openai.com/models). This will break list_capi_models() for those endpoints. Consider storing models_catalog as an absolute path (e.g. /v1/models) or adjusting URL construction so it reliably appends/overrides paths as intended for each provider.
        r = httpx.get(
            httpx.URL(base).join(provider.models_catalog),
            headers=headers,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

p-
p- previously approved these changes Apr 2, 2026
Consolidate endpoint-specific logic (catalog path, response parsing,
tool-call detection, headers) into an APIProvider dataclass with a
hostname-keyed registry. Adding a new endpoint is now a single registry
entry instead of changes across three match/case blocks.

- Remove AI_API_ENDPOINT_ENUM StrEnum and strenum dependency
- Only send Copilot-Integration-Id header to Copilot endpoints
- Accept optional endpoint parameter in public functions
- Drop fragile "gpt-" substring heuristic for OpenAI tool-call check
- Update tests to use new provider API
@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from 01041fd to 13aef99 Compare April 2, 2026 16:30
@anticomputer anticomputer marked this pull request as ready for review April 2, 2026 16:40
@anticomputer anticomputer requested a review from m-y-mo as a code owner April 2, 2026 16:40
Copilot AI review requested due to automatic review settings April 2, 2026 16:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@anticomputer
Copy link
Copy Markdown
Contributor Author

@kevinbackhouse heads up — this PR has merge-order conflicts with #186, #189, #195 (and mildly #191, #203, #205). Those PRs fix linter rules in the StrEnum/to_url()/match-case code that this refactor deletes entirely. If they land first we'd just be resolving conflicts against dead code. Cleanest path is to merge this first, then rebase the lint-fix PRs — the capi.py hunks become no-ops and the agent.py changes should still apply.

p-
p- previously approved these changes Apr 2, 2026
@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from 0acd002 to e71c52b Compare April 2, 2026 17:11
Copilot AI review requested due to automatic review settings April 2, 2026 17:24
@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from e71c52b to 3c42d67 Compare April 2, 2026 17:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@anticomputer anticomputer force-pushed the anticomputer/capi-cleanup branch from 3c42d67 to a0e4d3a Compare April 2, 2026 17:51
@anticomputer anticomputer merged commit 1897f51 into main Apr 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants