Skip to content

SDK regeneration - #57

Open
chiragjn wants to merge 6 commits into
mainfrom
chiragjn-nullable-optional
Open

SDK regeneration#57
chiragjn wants to merge 6 commits into
mainfrom
chiragjn-nullable-optional

Conversation

@chiragjn

@chiragjn chiragjn commented Jul 29, 2026

Copy link
Copy Markdown
Member

Note

Medium Risk
Large auto-generated diff with new clients and renamed types that can break typed imports and call sites; runtime behavior follows the backing API spec.

Overview
Regenerates the TrueFoundry Python SDK from the updated API spec using Fern CLI 5.82.0 and fern-python-sdk 5.24.0 (from 5.59 / 5.15), with a new originGitCommit in .fern/metadata.json.

The generated surface adds client.gateway_budgets (list, create/update manifests, get/delete, usage, simulate, leaderboard) and client.agents.get_token for on-demand agent identity tokens. users.delete gains optional force_delete to strip collaborations and team memberships before removal.

Across clients, list/filter parameters are typed as typing.List[...] instead of comma-separated Union[str, Sequence[...]], and several request enum types are renamed (e.g. ApplicationsListRequest*ListApplicationsRequest*, internal AI gateway/metrics types). Response type names align with the new generator (e.g. cancel deployment, internal workflows). README.md documents per-request timeout as request_options["timeout"] instead of timeout_in_seconds.

poetry.lock picks up patch bumps (e.g. aiohttp, httpx-aiohttp); pyproject.toml relaxes the httpx-aiohttp version constraint to ^0.1.8.

Reviewed by Cursor Bugbot for commit e2836b5. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 297 files, which is 147 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to Pro+ to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0f8f192a-048c-4b0a-942a-66b41c9d21d7

📥 Commits

Reviewing files that changed from the base of the PR and between e73109c and e2836b5.

⛔ Files ignored due to path filters (1)
  • poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (297)
  • .fern/metadata.json
  • README.md
  • pyproject.toml
  • reference.md
  • src/truefoundry_sdk/__init__.py
  • src/truefoundry_sdk/agent_skill_versions/client.py
  • src/truefoundry_sdk/agent_skills/client.py
  • src/truefoundry_sdk/agent_versions/client.py
  • src/truefoundry_sdk/agents/__init__.py
  • src/truefoundry_sdk/agents/client.py
  • src/truefoundry_sdk/agents/raw_client.py
  • src/truefoundry_sdk/agents/types/__init__.py
  • src/truefoundry_sdk/agents/types/list_agents_request_type.py
  • src/truefoundry_sdk/alerts/client.py
  • src/truefoundry_sdk/applications/__init__.py
  • src/truefoundry_sdk/applications/client.py
  • src/truefoundry_sdk/applications/raw_client.py
  • src/truefoundry_sdk/applications/types/__init__.py
  • src/truefoundry_sdk/applications/types/cancel_deployment_applications_response.py
  • src/truefoundry_sdk/applications/types/list_applications_request_device_type_filter.py
  • src/truefoundry_sdk/applications/types/list_applications_request_lifecycle_stage.py
  • src/truefoundry_sdk/artifact_versions/client.py
  • src/truefoundry_sdk/artifact_versions/raw_client.py
  • src/truefoundry_sdk/artifacts/client.py
  • src/truefoundry_sdk/base_client.py
  • src/truefoundry_sdk/clusters/client.py
  • src/truefoundry_sdk/clusters/raw_client.py
  • src/truefoundry_sdk/core/http_client.py
  • src/truefoundry_sdk/core/http_sse/_api.py
  • src/truefoundry_sdk/core/http_sse/_decoders.py
  • src/truefoundry_sdk/core/request_options.py
  • src/truefoundry_sdk/data_directories/client.py
  • src/truefoundry_sdk/events/client.py
  • src/truefoundry_sdk/events/raw_client.py
  • src/truefoundry_sdk/gateway_budgets/__init__.py
  • src/truefoundry_sdk/gateway_budgets/client.py
  • src/truefoundry_sdk/gateway_budgets/raw_client.py
  • src/truefoundry_sdk/gateway_budgets/types/__init__.py
  • src/truefoundry_sdk/gateway_budgets/types/create_or_update_budget_request_manifest.py
  • src/truefoundry_sdk/gateway_budgets/types/list_gateway_budgets_request_type.py
  • src/truefoundry_sdk/internal/__init__.py
  • src/truefoundry_sdk/internal/ai_gateway/__init__.py
  • src/truefoundry_sdk/internal/ai_gateway/client.py
  • src/truefoundry_sdk/internal/ai_gateway/raw_client.py
  • src/truefoundry_sdk/internal/ai_gateway/types/__init__.py
  • src/truefoundry_sdk/internal/ai_gateway/types/get_gateway_config_ai_gateway_request_type.py
  • src/truefoundry_sdk/internal/applications/client.py
  • src/truefoundry_sdk/internal/artifact_versions/client.py
  • src/truefoundry_sdk/internal/artifact_versions/raw_client.py
  • src/truefoundry_sdk/internal/build_logs/client.py
  • src/truefoundry_sdk/internal/deployments/client.py
  • src/truefoundry_sdk/internal/docker_registries/client.py
  • src/truefoundry_sdk/internal/metrics/__init__.py
  • src/truefoundry_sdk/internal/metrics/client.py
  • src/truefoundry_sdk/internal/metrics/raw_client.py
  • src/truefoundry_sdk/internal/metrics/types/__init__.py
  • src/truefoundry_sdk/internal/metrics/types/get_charts_metrics_request_filter_entity.py
  • src/truefoundry_sdk/internal/workflows/__init__.py
  • src/truefoundry_sdk/internal/workflows/client.py
  • src/truefoundry_sdk/internal/workflows/raw_client.py
  • src/truefoundry_sdk/internal/workflows/types/__init__.py
  • src/truefoundry_sdk/internal/workflows/types/execute_workflow_workflows_response.py
  • src/truefoundry_sdk/jobs/client.py
  • src/truefoundry_sdk/jobs/raw_client.py
  • src/truefoundry_sdk/logs/client.py
  • src/truefoundry_sdk/logs/raw_client.py
  • src/truefoundry_sdk/ml_repos/client.py
  • src/truefoundry_sdk/ml_repos/raw_client.py
  • src/truefoundry_sdk/model_versions/client.py
  • src/truefoundry_sdk/model_versions/raw_client.py
  • src/truefoundry_sdk/models/client.py
  • src/truefoundry_sdk/personal_access_tokens/client.py
  • src/truefoundry_sdk/prompt_versions/client.py
  • src/truefoundry_sdk/prompts/client.py
  • src/truefoundry_sdk/secret_groups/client.py
  • src/truefoundry_sdk/secret_groups/raw_client.py
  • src/truefoundry_sdk/secrets/client.py
  • src/truefoundry_sdk/teams/client.py
  • src/truefoundry_sdk/teams/raw_client.py
  • src/truefoundry_sdk/traces/raw_client.py
  • src/truefoundry_sdk/types/__init__.py
  • src/truefoundry_sdk/types/addon_component_status.py
  • src/truefoundry_sdk/types/agent.py
  • src/truefoundry_sdk/types/agent_channel.py
  • src/truefoundry_sdk/types/agent_channel_agent.py
  • src/truefoundry_sdk/types/agent_channel_config.py
  • src/truefoundry_sdk/types/agent_channel_manifest.py
  • src/truefoundry_sdk/types/agent_channel_slack_auth.py
  • src/truefoundry_sdk/types/agent_channel_slack_bot_token_auth.py
  • src/truefoundry_sdk/types/agent_channel_slack_config.py
  • src/truefoundry_sdk/types/agent_identity.py
  • src/truefoundry_sdk/types/agent_identity_manifest.py
  • src/truefoundry_sdk/types/agent_version_metadata.py
  • src/truefoundry_sdk/types/ai21provider_account.py
  • src/truefoundry_sdk/types/alert_config_entity.py
  • src/truefoundry_sdk/types/anthropic_provider_account.py
  • src/truefoundry_sdk/types/application.py
  • src/truefoundry_sdk/types/application_summary.py
  • src/truefoundry_sdk/types/aws_bedrock_mantle_provider_account.py
  • src/truefoundry_sdk/types/aws_bedrock_provider_account.py
  • src/truefoundry_sdk/types/aws_claude_platform_provider_account.py
  • src/truefoundry_sdk/types/aws_sagemaker_provider_account.py
  • src/truefoundry_sdk/types/azure_foundry_provider_account.py
  • src/truefoundry_sdk/types/azure_open_ai_provider_account.py
  • src/truefoundry_sdk/types/baseten_provider_account.py
  • src/truefoundry_sdk/types/budget_entity_usage.py
  • src/truefoundry_sdk/types/budget_usage_entry.py
  • src/truefoundry_sdk/types/budget_usage_entry_mode.py
  • src/truefoundry_sdk/types/budget_usage_entry_type.py
  • src/truefoundry_sdk/types/budget_usage_response.py
  • src/truefoundry_sdk/types/budget_v2alert.py
  • src/truefoundry_sdk/types/budget_v2in_not_in_filter.py
  • src/truefoundry_sdk/types/budget_v2limits.py
  • src/truefoundry_sdk/types/budget_v2override_limits.py
  • src/truefoundry_sdk/types/budget_v2when_team_scoped.py
  • src/truefoundry_sdk/types/budget_v2when_tenant_scoped.py
  • src/truefoundry_sdk/types/cartesia_provider_account.py
  • src/truefoundry_sdk/types/cerebras_provider_account.py
  • src/truefoundry_sdk/types/cisco_ai_defense_guardrail_config.py
  • src/truefoundry_sdk/types/cisco_ai_defense_guardrail_config_config.py
  • src/truefoundry_sdk/types/cisco_ai_defense_guardrail_config_config_region.py
  • src/truefoundry_sdk/types/cisco_ai_defense_key_auth.py
  • src/truefoundry_sdk/types/cloudera_provider_account.py
  • src/truefoundry_sdk/types/cluster_gateway.py
  • src/truefoundry_sdk/types/cohere_provider_account.py
  • src/truefoundry_sdk/types/complexity_based_load_balance_target.py
  • src/truefoundry_sdk/types/complexity_based_load_balance_target_tier.py
  • src/truefoundry_sdk/types/complexity_based_load_balancing.py
  • src/truefoundry_sdk/types/complexity_based_load_balancing_classification_strategy.py
  • src/truefoundry_sdk/types/complexity_sticky_routing.py
  • src/truefoundry_sdk/types/create_docker_repository_response.py
  • src/truefoundry_sdk/types/custom_endpoint_provider_account.py
  • src/truefoundry_sdk/types/databricks_provider_account.py
  • src/truefoundry_sdk/types/deepgram_provider_account.py
  • src/truefoundry_sdk/types/deepinfra_provider_account.py
  • src/truefoundry_sdk/types/deployment.py
  • src/truefoundry_sdk/types/deployment_build.py
  • src/truefoundry_sdk/types/deployment_build_status.py
  • src/truefoundry_sdk/types/eleven_labs_provider_account.py
  • src/truefoundry_sdk/types/environment_manifest.py
  • src/truefoundry_sdk/types/event.py
  • src/truefoundry_sdk/types/external_identity_provider.py
  • src/truefoundry_sdk/types/gateway_budget.py
  • src/truefoundry_sdk/types/gateway_budget_manifest.py
  • src/truefoundry_sdk/types/gateway_config.py
  • src/truefoundry_sdk/types/gateway_configuration.py
  • src/truefoundry_sdk/types/gateway_data_created_by_filter.py
  • src/truefoundry_sdk/types/gateway_data_created_by_filter_operator.py
  • src/truefoundry_sdk/types/gateway_data_metadata_filter.py
  • src/truefoundry_sdk/types/gateway_data_metadata_filter_operator.py
  • src/truefoundry_sdk/types/gateway_installation.py
  • src/truefoundry_sdk/types/gateway_logging_config.py
  • src/truefoundry_sdk/types/gcp_api_key_auth.py
  • src/truefoundry_sdk/types/gcp_gke_integration.py
  • src/truefoundry_sdk/types/gcp_gke_integration_location.py
  • src/truefoundry_sdk/types/gcp_region.py
  • src/truefoundry_sdk/types/get_agent_identity_token_response.py
  • src/truefoundry_sdk/types/get_authenticated_vcsurl_response.py
  • src/truefoundry_sdk/types/get_docker_registry_credentials_response.py
  • src/truefoundry_sdk/types/google_gemini_provider_account.py
  • src/truefoundry_sdk/types/google_vertex_provider_account.py
  • src/truefoundry_sdk/types/graph.py
  • src/truefoundry_sdk/types/groq_provider_account.py
  • src/truefoundry_sdk/types/guardrail_config_group.py
  • src/truefoundry_sdk/types/guardrail_config_integrations.py
  • src/truefoundry_sdk/types/guardrails_rule.py
  • src/truefoundry_sdk/types/hashicorp_app_role_auth.py
  • src/truefoundry_sdk/types/header_routing_config.py
  • src/truefoundry_sdk/types/headers_override.py
  • src/truefoundry_sdk/types/heuristic_classification_strategy.py
  • src/truefoundry_sdk/types/heuristic_fallback_strategy.py
  • src/truefoundry_sdk/types/http_error.py
  • src/truefoundry_sdk/types/i_change.py
  • src/truefoundry_sdk/types/i_change_type.py
  • src/truefoundry_sdk/types/identity_provider_backed_identity.py
  • src/truefoundry_sdk/types/identity_provider_mapping.py
  • src/truefoundry_sdk/types/in_not_in.py
  • src/truefoundry_sdk/types/is_cluster_connected_response.py
  • src/truefoundry_sdk/types/job_run.py
  • src/truefoundry_sdk/types/job_run_status.py
  • src/truefoundry_sdk/types/json_schema.py
  • src/truefoundry_sdk/types/list_budgets_response.py
  • src/truefoundry_sdk/types/list_files_request.py
  • src/truefoundry_sdk/types/llm_classification_strategy.py
  • src/truefoundry_sdk/types/llm_classification_strategy_fallback_strategy.py
  • src/truefoundry_sdk/types/log.py
  • src/truefoundry_sdk/types/logging_when.py
  • src/truefoundry_sdk/types/mcp_server.py
  • src/truefoundry_sdk/types/mcp_server_auth_status_info.py
  • src/truefoundry_sdk/types/mcp_server_auth_status_info_method.py
  • src/truefoundry_sdk/types/mcp_server_auth_status_info_status.py
  • src/truefoundry_sdk/types/mcp_server_o_auth2.py
  • src/truefoundry_sdk/types/mcp_server_o_auth2grant_type.py
  • src/truefoundry_sdk/types/mcp_server_o_auth2provider_okta_id_jag_settings.py
  • src/truefoundry_sdk/types/mcp_server_o_auth2provider_okta_settings.py
  • src/truefoundry_sdk/types/mcp_tool_annotations.py
  • src/truefoundry_sdk/types/mistral_ai_provider_account.py
  • src/truefoundry_sdk/types/multi_part_upload.py
  • src/truefoundry_sdk/types/noma_security_api_key_auth.py
  • src/truefoundry_sdk/types/noma_security_guardrail_config.py
  • src/truefoundry_sdk/types/noma_security_guardrail_config_config.py
  • src/truefoundry_sdk/types/nomic_provider_account.py
  • src/truefoundry_sdk/types/ollama_provider_account.py
  • src/truefoundry_sdk/types/open_router_provider_account.py
  • src/truefoundry_sdk/types/openai_provider_account.py
  • src/truefoundry_sdk/types/palm_provider_account.py
  • src/truefoundry_sdk/types/period_usage.py
  • src/truefoundry_sdk/types/permission_set_v2.py
  • src/truefoundry_sdk/types/permission_set_v2resource_type.py
  • src/truefoundry_sdk/types/perplexity_ai_provider_account.py
  • src/truefoundry_sdk/types/policy.py
  • src/truefoundry_sdk/types/policy_version.py
  • src/truefoundry_sdk/types/private_pricing_tier.py
  • src/truefoundry_sdk/types/prometheus_alert_rule.py
  • src/truefoundry_sdk/types/provider_account.py
  • src/truefoundry_sdk/types/provider_account_provider.py
  • src/truefoundry_sdk/types/provider_integration.py
  • src/truefoundry_sdk/types/provider_integration_type.py
  • src/truefoundry_sdk/types/py_spark_task_config.py
  • src/truefoundry_sdk/types/py_spark_task_config_image.py
  • src/truefoundry_sdk/types/redaction.py
  • src/truefoundry_sdk/types/role.py
  • src/truefoundry_sdk/types/role_binding.py
  • src/truefoundry_sdk/types/role_binding_permission.py
  • src/truefoundry_sdk/types/role_binding_subject.py
  • src/truefoundry_sdk/types/role_binding_subject_type.py
  • src/truefoundry_sdk/types/role_manifest.py
  • src/truefoundry_sdk/types/role_resource_type.py
  • src/truefoundry_sdk/types/role_with_resource_resource_type.py
  • src/truefoundry_sdk/types/samba_nova_provider_account.py
  • src/truefoundry_sdk/types/self_hosted_model_provider_account.py
  • src/truefoundry_sdk/types/settings.py
  • src/truefoundry_sdk/types/smallest_ai_provider_account.py
  • src/truefoundry_sdk/types/snowflake_cortex_provider_account.py
  • src/truefoundry_sdk/types/spark_job.py
  • src/truefoundry_sdk/types/spark_job_trigger.py
  • src/truefoundry_sdk/types/spark_job_trigger_input.py
  • src/truefoundry_sdk/types/static_fallback_strategy.py
  • src/truefoundry_sdk/types/static_fallback_strategy_default_tier.py
  • src/truefoundry_sdk/types/subject.py
  • src/truefoundry_sdk/types/subject_permission.py
  • src/truefoundry_sdk/types/subject_subject_type.py
  • src/truefoundry_sdk/types/subject_type.py
  • src/truefoundry_sdk/types/sync_token_in_secret_store_info.py
  • src/truefoundry_sdk/types/sync_virtual_account_token_response.py
  • src/truefoundry_sdk/types/task_spark_image.py
  • src/truefoundry_sdk/types/team.py
  • src/truefoundry_sdk/types/team_budget_config.py
  • src/truefoundry_sdk/types/team_budget_config_mode.py
  • src/truefoundry_sdk/types/team_manifest.py
  • src/truefoundry_sdk/types/team_subject_row.py
  • src/truefoundry_sdk/types/tenant_budget_config.py
  • src/truefoundry_sdk/types/tenant_budget_config_mode.py
  • src/truefoundry_sdk/types/terminate_job_response.py
  • src/truefoundry_sdk/types/together_ai_provider_account.py
  • src/truefoundry_sdk/types/token_pagination.py
  • src/truefoundry_sdk/types/trace_span.py
  • src/truefoundry_sdk/types/tracing_project.py
  • src/truefoundry_sdk/types/trigger_job_run_response.py
  • src/truefoundry_sdk/types/true_foundry_agent_git_source_skill.py
  • src/truefoundry_sdk/types/true_foundry_agent_mcp_server.py
  • src/truefoundry_sdk/types/true_foundry_agent_mcp_server_inline.py
  • src/truefoundry_sdk/types/true_foundry_agent_mcp_server_registry.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_auth_data.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_auth_inject.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_auth_inject_match.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_basic_auth_data.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_config.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_git_auth_inject.py
  • src/truefoundry_sdk/types/true_foundry_agent_sandbox_network_policy.py
  • src/truefoundry_sdk/types/true_foundry_agent_skill.py
  • src/truefoundry_sdk/types/true_foundry_agent_true_foundry_skill.py
  • src/truefoundry_sdk/types/true_foundry_agent_user_message.py
  • src/truefoundry_sdk/types/true_foundry_apply_request_manifest.py
  • src/truefoundry_sdk/types/true_foundry_apply_response.py
  • src/truefoundry_sdk/types/true_foundry_apply_response_data.py
  • src/truefoundry_sdk/types/true_foundry_apply_response_existing_manifest.py
  • src/truefoundry_sdk/types/true_foundry_delete_request_manifest.py
  • src/truefoundry_sdk/types/user.py
  • src/truefoundry_sdk/types/user_resource.py
  • src/truefoundry_sdk/types/user_team_info.py
  • src/truefoundry_sdk/types/vertex_region.py
  • src/truefoundry_sdk/types/virtual_account.py
  • src/truefoundry_sdk/types/virtual_model_model_type.py
  • src/truefoundry_sdk/types/wafer_provider_account.py
  • src/truefoundry_sdk/types/workspace.py
  • src/truefoundry_sdk/types/xai_provider_account.py
  • src/truefoundry_sdk/users/__init__.py
  • src/truefoundry_sdk/users/client.py
  • src/truefoundry_sdk/users/raw_client.py
  • src/truefoundry_sdk/users/types/__init__.py
  • src/truefoundry_sdk/users/types/update_user_roles_request_resource_type.py
  • src/truefoundry_sdk/virtual_accounts/client.py
  • src/truefoundry_sdk/virtual_accounts/raw_client.py
  • src/truefoundry_sdk/workspaces/client.py
  • src/truefoundry_sdk/workspaces/raw_client.py
  • tests/utils/test_http_client.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands.

@chiragjn

Copy link
Copy Markdown
Member Author

@coderabbitai Review this PR

Please specifically point out interface breaking changes. These include but not limited to

  • Some argument was removed from some function that belongs in the public api client.v1...
    You can read reference.md at root of repo to figure out the changed methods. Ignore the internal group
  • breaking changes in types - fields getting removed or type changing
  • types being removed completely
  • enum members getting removed
  • Anything that break code relying on this SDK

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Branch and merge-base =="
git status --short
git branch --show-current
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
printf 'MERGE_BASE=%s\n' "$base"
printf 'HEAD=%s\n' "$(git rev-parse HEAD)"

echo
echo "== Changed files (name/status) =="
git diff --name-status "$base"...HEAD

echo
echo "== Changed-file summary =="
git diff --stat "$base"...HEAD

echo
echo "== Root documentation candidates =="
fd -HI '^reference\.md$|^README\.md$' . -d 2

echo
echo "== reference.md outline / public headings =="
if [ -f reference.md ]; then
  rg -n '^(#{1,4})\s|^##\s+client\.v1|internal' reference.md | head -n 240
fi

echo
echo "== Generated SDK top-level candidates =="
fd -HI -t d 'truefoundry_sdk' . | head -n 40

Length of output: 40741


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="e73109c6cf800314789ce9a5a927ca38d104f6c0"

python3 - "$base" <<'PY'
import ast, subprocess, sys

base = sys.argv[1]
head = "HEAD"
root = "src/truefoundry_sdk/"

def files(rev):
    text = subprocess.check_output(
        ["git", "ls-tree", "-r", "--name-only", rev, root], text=True
    )
    return [p for p in text.splitlines() if p.endswith(".py") and "/internal/" not in p]

def source(rev, path):
    try:
        return subprocess.check_output(["git", "show", f"{rev}:{path}"], text=True)
    except subprocess.CalledProcessError:
        return ""

def unparse(n):
    return ast.unparse(n) if n is not None else None

def args(fn):
    a = fn.args
    out = []
    positional = list(a.posonlyargs) + list(a.args)
    defaults = [None] * (len(positional) - len(a.defaults)) + list(a.defaults)
    for v, d in zip(positional, defaults):
        if v.arg in ("self", "cls"):
            continue
        out.append((v.arg, unparse(v.annotation), d is not None))
    if a.vararg:
        out.append(("*" + a.vararg.arg, unparse(a.vararg.annotation), False))
    for v, d in zip(a.kwonlyargs, a.kw_defaults):
        out.append((v.arg, unparse(v.annotation), d is not None))
    if a.kwarg:
        out.append(("**" + a.kwarg.arg, unparse(a.kwarg.annotation), False))
    return out

def parse(rev):
    methods, classes, exports = {}, {}, {}
    for path in files(rev):
        tree = ast.parse(source(rev, path), filename=path)
        module = path[len(root):-3].replace("/", ".")
        for n in tree.body:
            if isinstance(n, (ast.ClassDef,)):
                bases = [unparse(x) for x in n.bases]
                fields = {}
                enum = {}
                for item in n.body:
                    if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
                        fields[item.target.id] = unparse(item.annotation)
                    elif isinstance(item, ast.Assign):
                        for target in item.targets:
                            if isinstance(target, ast.Name) and (
                                "Enum" in " ".join(bases) or "Literal" not in " ".join(bases)
                            ):
                                # Collected only used where the class is confirmed Enum below.
                                enum[target.id] = unparse(item.value)
                    elif isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)) and not item.name.startswith("_"):
                        methods[f"{module}.{n.name}.{item.name}"] = args(item)
                classes[f"{module}.{n.name}"] = {
                    "bases": bases, "fields": fields,
                    "enum": enum if any("Enum" in x for x in bases) else {}
                }
            elif isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and not n.name.startswith("_"):
                methods[f"{module}.{n.name}"] = args(n)
        if path.endswith("/__init__.py") or path == root + "__init__.py":
            names = set()
            for n in tree.body:
                if isinstance(n, ast.ImportFrom):
                    names.update(a.asname or a.name for a in n.names if a.name != "*")
                elif isinstance(n, ast.Assign):
                    if any(isinstance(t, ast.Name) and t.id == "__all__" for t in n.targets):
                        if isinstance(n.value, (ast.List, ast.Tuple)):
                            names.update(e.value for e in n.value.elts if isinstance(e, ast.Constant) and isinstance(e.value, str))
            exports[module] = names
    return methods, classes, exports

bm, bc, be = parse(base)
hm, hc, he = parse(head)

print("== Removed required/optional method parameters in public non-raw clients ==")
count = 0
for key in sorted(set(bm) & set(hm)):
    # exclude raw client implementations; public standard client only
    if ".raw_client." in key:
        continue
    old = {x[0]: x for x in bm[key]}
    new = {x[0]: x for x in hm[key]}
    removed = [old[k] for k in old.keys() - new.keys()]
    if removed:
        print(key, "REMOVED", removed)
        count += 1
print("count:", count)

print("\n== Existing public methods with changed parameter annotation/defaultness ==")
count = 0
for key in sorted(set(bm) & set(hm)):
    if ".raw_client." in key: continue
    old, new = dict(bm[key]), dict(hm[key])
    changes = [(k, old[k], new[k]) for k in old.keys() & new.keys() if old[k] != new[k]]
    if changes:
        print(key, changes)
        count += 1
print("count:", count)

print("\n== Removed public client methods/classes ==")
for key in sorted(set(bm) - set(hm)):
    if ".raw_client." not in key:
        print("METHOD", key)
for key in sorted(set(bc) - set(hc)):
    print("CLASS", key)

print("\n== Data-model fields removed or field annotations changed (non-Enum classes) ==")
count = 0
for key in sorted(set(bc) & set(hc)):
    old, new = bc[key], hc[key]
    if old["enum"] or new["enum"]:
        continue
    removed = sorted(set(old["fields"]) - set(new["fields"]))
    changed = [(f, old["fields"][f], new["fields"][f])
               for f in sorted(set(old["fields"]) & set(new["fields"]))
               if old["fields"][f] != new["fields"][f]]
    if removed or changed:
        print(key, "removed_fields=", removed, "changed_fields=", changed)
        count += 1
print("count:", count)

print("\n== Enum members removed or value changed ==")
count = 0
for key in sorted(set(bc) & set(hc)):
    old, new = bc[key]["enum"], hc[key]["enum"]
    if not old and not new: continue
    removed = sorted(set(old) - set(new))
    changed = [(e, old[e], new[e]) for e in sorted(set(old) & set(new)) if old[e] != new[e]]
    if removed or changed:
        print(key, "removed_members=", removed, "changed_values=", changed)
        count += 1
print("count:", count)

print("\n== Removed imports/re-exports from package __init__ modules ==")
for key in sorted(set(be) & set(he)):
    removed = sorted(be[key] - he[key])
    if removed:
        print(key, removed)
PY

echo
echo "== Exact public client and reference documentation diff (excluding internal) =="
git diff --unified=5 "$base"...HEAD -- \
  reference.md \
  'src/truefoundry_sdk/*/client.py' \
  ':(exclude)src/truefoundry_sdk/internal/**' \
  | sed -n '1,2600p'

echo
echo "== Exact diffs of renamed/removed public type modules and package exports =="
git diff --find-renames --unified=5 "$base"...HEAD -- \
  src/truefoundry_sdk/__init__.py \
  src/truefoundry_sdk/types/__init__.py \
  src/truefoundry_sdk/applications/types/__init__.py \
  src/truefoundry_sdk/agents/types/__init__.py \
  src/truefoundry_sdk/users/types/__init__.py \
  'src/truefoundry_sdk/types/build_status.py' \
  'src/truefoundry_sdk/types/deployment_build_status.py' \
  'src/truefoundry_sdk/types/resource_type.py' \
  'src/truefoundry_sdk/types/role_resource_type.py' \
  'src/truefoundry_sdk/types/i_change_operation.py' \
  'src/truefoundry_sdk/types/i_change_type.py' \
  'src/truefoundry_sdk/types/gateway_logging_when.py' \
  'src/truefoundry_sdk/types/agent_channel_agent.py' \
  'src/truefoundry_sdk/types/gateway_logging_rule.py' \
  'src/truefoundry_sdk/types/noma_security_api_key_auth.py' \
  | sed -n '1,2600p'

Length of output: 8101


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="e73109c6cf800314789ce9a5a927ca38d104f6c0"

python3 - "$base" <<'PY'
import ast, subprocess, sys
base=sys.argv[1]; head="HEAD"; root="src/truefoundry_sdk/"

def git(rev,path):
    try: return subprocess.check_output(["git","show",f"{rev}:{path}"],text=True)
    except subprocess.CalledProcessError: return ""
def paths(rev):
    x=subprocess.check_output(["git","ls-tree","-r","--name-only",rev,root],text=True).splitlines()
    return [p for p in x if p.endswith(".py") and "/internal/" not in p]
def up(x): return ast.unparse(x) if x is not None else None
def params(node):
    a=node.args; result=[]
    pos=list(a.posonlyargs)+list(a.args)
    defaults=[None]*(len(pos)-len(a.defaults))+list(a.defaults)
    for x,d in zip(pos,defaults):
        if x.arg not in ("self","cls"): result.append((x.arg,up(x.annotation),d is not None))
    if a.vararg: result.append(("*"+a.vararg.arg,up(a.vararg.annotation),False))
    for x,d in zip(a.kwonlyargs,a.kw_defaults): result.append((x.arg,up(x.annotation),d is not None))
    if a.kwarg: result.append(("**"+a.kwarg.arg,up(a.kwarg.annotation),False))
    return result
def load(rev):
    meth={}; cls={}; exports={}
    for path in paths(rev):
        t=ast.parse(git(rev,path)); mod=path[len(root):-3].replace("/",".")
        for n in t.body:
            if isinstance(n,ast.ClassDef):
                bases=[up(b) for b in n.bases]; fields={}; enum={}; methods={}
                isenum=any("Enum" in b for b in bases)
                for z in n.body:
                    if isinstance(z,ast.AnnAssign) and isinstance(z.target,ast.Name):
                        fields[z.target.id]=up(z.annotation)
                    elif isenum and isinstance(z,ast.Assign):
                        for target in z.targets:
                            if isinstance(target,ast.Name): enum[target.id]=up(z.value)
                    elif isinstance(z,(ast.FunctionDef,ast.AsyncFunctionDef)) and not z.name.startswith("_"):
                        methods[z.name]=params(z)
                cls[f"{mod}.{n.name}"]={"bases":bases,"fields":fields,"enum":enum}
                if path.endswith("/client.py") and not path.endswith("/raw_client.py"):
                    for name,p in methods.items(): meth[f"{mod}.{n.name}.{name}"]=p
            elif path.endswith("/client.py") and not path.endswith("/raw_client.py") and isinstance(n,(ast.FunctionDef,ast.AsyncFunctionDef)) and not n.name.startswith("_"):
                meth[f"{mod}.{n.name}"]=params(n)
        if path.endswith("__init__.py"):
            names=set()
            for n in t.body:
                if isinstance(n,ast.ImportFrom):
                    names |= {a.asname or a.name for a in n.names if a.name!="*"}
                if isinstance(n,ast.Assign) and any(isinstance(q,ast.Name) and q.id=="__all__" for q in n.targets):
                    if isinstance(n.value,(ast.List,ast.Tuple)):
                        names |= {q.value for q in n.value.elts if isinstance(q,ast.Constant) and isinstance(q.value,str)}
            exports[mod]=names
    return meth,cls,exports
bm,bc,be=load(base); hm,hc,he=load(head)

print("== PUBLIC CLIENT METHODS: removed arguments ==")
n=0
for k in sorted(bm.keys() & hm.keys()):
    o={v[0]:v for v in bm[k]}; h={v[0]:v for v in hm[k]}
    r=[o[x] for x in o.keys()-h.keys()]
    if r: print(k, r);n+=1
print("COUNT",n)

print("\n== PUBLIC CLIENT METHODS: changed compatible-looking parameter contract ==")
n=0
for k in sorted(bm.keys() & hm.keys()):
    o={v[0]:v for v in bm[k]}; h={v[0]:v for v in hm[k]}
    c=[(x,o[x],h[x]) for x in o.keys()&h.keys() if o[x][1:]!=h[x][1:]]
    if c: print(k,c);n+=1
print("COUNT",n)

print("\n== PUBLIC CLIENT METHODS: removed ==")
for k in sorted(bm.keys()-hm.keys()): print(k)

print("\n== PUBLIC TYPES: fields removed or annotations changed ==")
n=0
for k in sorted(bc.keys()&hc.keys()):
    o,h=bc[k],hc[k]
    if o["enum"] or h["enum"]: continue
    r=sorted(o["fields"].keys()-h["fields"].keys())
    c=[(x,o["fields"][x],h["fields"][x]) for x in sorted(o["fields"].keys()&h["fields"].keys()) if o["fields"][x]!=h["fields"][x]]
    if r or c: print(k,"REMOVED",r,"CHANGED",c);n+=1
print("COUNT",n)

print("\n== PUBLIC ENUMS: members removed or values changed ==")
n=0
for k in sorted(bc.keys()&hc.keys()):
    o,h=bc[k]["enum"],hc[k]["enum"]
    if not o and not h: continue
    r=sorted(o.keys()-h.keys())
    c=[(x,o[x],h[x]) for x in sorted(o.keys()&h.keys()) if o[x]!=h[x]]
    if r or c: print(k,"REMOVED",r,"CHANGED",c);n+=1
print("COUNT",n)

print("\n== PUBLIC MODULE CLASSES REMOVED ==")
for k in sorted(bc.keys()-hc.keys()): print(k)

print("\n== REMOVED RE-EXPORTS ==")
for k in sorted(be.keys()&he.keys()):
    r=sorted(be[k]-he[k])
    if r: print(k,r)
PY

echo
echo "== Client/signature and renamed public-type diffs (non-internal) =="
git diff --find-renames --unified=4 "$base"...HEAD -- \
  'src/truefoundry_sdk/*/client.py' \
  ':(exclude)src/truefoundry_sdk/internal/**' \
  src/truefoundry_sdk/__init__.py \
  src/truefoundry_sdk/types/__init__.py \
  src/truefoundry_sdk/applications/__init__.py \
  src/truefoundry_sdk/applications/types/__init__.py \
  src/truefoundry_sdk/agents/__init__.py \
  src/truefoundry_sdk/agents/types/__init__.py \
  src/truefoundry_sdk/users/__init__.py \
  src/truefoundry_sdk/users/types/__init__.py \
  | rg -n -C3 '^(diff|@@)|^[-+].*(def |import |[A-Z][A-Za-z0-9_]+\b|typing\.)' | sed -n '1,3000p'

echo
echo "== Diffs for two removed public union variants =="
git diff --unified=8 "$base"...HEAD -- \
  src/truefoundry_sdk/types/role_binding_subject_type.py \
  src/truefoundry_sdk/types/subject_type.py \
  src/truefoundry_sdk/types/role_binding_subject.py \
  src/truefoundry_sdk/types/subject.py \
  | sed -n '1,1000p'

Length of output: 149020


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="e73109c6cf800314789ce9a5a927ca38d104f6c0"

echo "== Current line locations for confirmed breaking changes =="
for f in \
  src/truefoundry_sdk/__init__.py \
  src/truefoundry_sdk/types/budget_v2alert.py \
  src/truefoundry_sdk/types/gateway_logging_config.py \
  src/truefoundry_sdk/types/true_foundry_agent_user_message.py \
  src/truefoundry_sdk/types/identity_provider_backed_identity.py \
  src/truefoundry_sdk/types/role_binding_subject_type.py \
  src/truefoundry_sdk/types/subject_type.py \
  src/truefoundry_sdk/types/true_foundry_agent_mcp_server.py \
  src/truefoundry_sdk/types/true_foundry_agent_skill.py \
  src/truefoundry_sdk/types/mcp_server.py \
  src/truefoundry_sdk/types/true_foundry_agent_mcp_server_inline.py \
  src/truefoundry_sdk/types/true_foundry_agent_true_foundry_skill.py \
  src/truefoundry_sdk/agents/raw_client.py \
  src/truefoundry_sdk/artifact_versions/raw_client.py
do
  echo "--- $f"
  if [ -f "$f" ]; then
    cat -n "$f" | sed -n '1,260p'
  else
    echo "(absent at HEAD)"
  fi
done

echo
echo "== Exact diffs for all detected model field/type breaks =="
git diff --unified=6 "$base"...HEAD -- \
  src/truefoundry_sdk/types/agent_identity_manifest.py \
  src/truefoundry_sdk/types/budget_v2alert.py \
  src/truefoundry_sdk/types/deployment_build.py \
  src/truefoundry_sdk/types/gateway_logging_config.py \
  src/truefoundry_sdk/types/gcp_gke_integration.py \
  src/truefoundry_sdk/types/i_change.py \
  src/truefoundry_sdk/types/identity_provider_backed_identity.py \
  src/truefoundry_sdk/types/mcp_server_o_auth2.py \
  src/truefoundry_sdk/types/team_budget_config.py \
  src/truefoundry_sdk/types/tenant_budget_config.py \
  src/truefoundry_sdk/types/true_foundry_agent_user_message.py \
  src/truefoundry_sdk/types/true_foundry_apply_response.py \
  | sed -n '1,2400p'

echo
echo "== Old removed agent union definitions (base) =="
for f in \
  src/truefoundry_sdk/types/true_foundry_agent_mcp_server.py \
  src/truefoundry_sdk/types/true_foundry_agent_skill.py \
  src/truefoundry_sdk/types/gateway_logging_rule.py \
  src/truefoundry_sdk/types/gateway_logging_when.py
do
  echo "--- $f @ base"
  git show "$base:$f" | cat -n | sed -n '1,240p'
done

Length of output: 74234


@chiragjn I completed a public-surface compatibility audit against the merge base, excluding internal.

No public client.* methods or method arguments were removed. The removals in reference.md examples are documentation simplifications; the underlying method signatures remain present.

However, this PR contains several interface-breaking changes:

  1. Removed/renamed public imports and type names
    Existing imports fail because the old names are removed from the top-level package and relevant subpackages:

    • AgentsListRequestTypeListAgentsRequestType
    • ApplicationsCancelDeploymentResponseCancelDeploymentApplicationsResponse
    • ApplicationsListRequestDeviceTypeFilterListApplicationsRequestDeviceTypeFilter
    • ApplicationsListRequestLifecycleStageListApplicationsRequestLifecycleStage
    • BuildStatusDeploymentBuildStatus
    • IChangeOperationIChangeType
    • ResourceTypeRoleResourceType in the general types package, while users.update_roles() now uses UpdateUserRolesRequestResourceType
    • GatewayLoggingRule and GatewayLoggingWhen are removed rather than retained as aliases.

    For example, from truefoundry_sdk import BuildStatus and from truefoundry_sdk.applications import ApplicationsCancelDeploymentResponse now raise import errors.

  2. GatewayLoggingConfig is structurally incompatible
    GatewayLoggingConfig.rules: List[GatewayLoggingRule] is removed. The model now uses when, required log, and optional redact_with instead. Existing manifests and code that construct or read rules will break. See src/truefoundry_sdk/types/gateway_logging_config.py Line 11.

  3. Agent model classes changed into non-constructible union aliases
    TrueFoundryAgentMcpServer and TrueFoundryAgentSkill are no longer models that callers can instantiate. They are now typing.Union aliases of newer variants. Code such as:

    TrueFoundryAgentMcpServer(name="...")
    TrueFoundryAgentSkill(fqn="...")

    therefore breaks at runtime. Callers must construct the new concrete variant classes instead.

  4. Removed model fields

    • BudgetV2Alert.notify_breaching_user was removed (src/truefoundry_sdk/types/budget_v2alert.py Line 10).
    • TrueFoundryAgentUserMessage.role was removed and replaced by type="user.message" (src/truefoundry_sdk/types/true_foundry_agent_user_message.py Line 9).
    • GatewayLoggingConfig.rules was removed as noted above.
  5. Enum members removed

    • RoleBindingSubjectType.EXTERNAL_IDENTITY was removed, along with the corresponding visit(external_identity=...) callback parameter (src/truefoundry_sdk/types/role_binding_subject_type.py Lines 10–42).
    • SubjectType.EXTERNAL_IDENTITY and its visitor callback were removed (src/truefoundry_sdk/types/subject_type.py Lines 10–54).

    This breaks source that references the member or exhaustively dispatches over the old enum.

  6. Serialized discriminator changed
    IdentityProviderBackedIdentity.type changes from literal "idp-backed" to "identity-provider-backed" (src/truefoundry_sdk/types/identity_provider_backed_identity.py Line 15). This changes both construction/validation and the wire value emitted by existing client code.

  7. Response/model type contract changes

    • TrueFoundryApplyResponse.data changes from Optional[Dict[str, Any]] to Optional[TrueFoundryApplyResponseData]. Consumers using dictionary operations/subscript access on data may break.
    • DeploymentBuild.status changes from BuildStatus to DeploymentBuildStatus.
    • GcpGkeIntegration.location changes from GcpRegion to GcpGkeIntegrationLocation.
    • IChange.type changes from IChangeOperation to IChangeType.
    • Subject.subject_type changes from SubjectType to SubjectSubjectType.
  8. List-filter parameter types are narrowed
    Several public methods drop the scalar branch from Union[T, Sequence[T]] and now declare only Sequence[T], including:

    • agents.list(attributes=...)
    • artifact_versions.list(run_ids=..., run_steps=...)
    • clusters.list/get_addons(attributes=...)
    • events.get(pod_names=...)
    • jobs.list_runs(triggered_by=..., version_numbers=...)
    • logs.get(pod_names=...)
    • ml_repos, model_versions, secret_groups, teams, virtual_accounts, and workspaces list filters.

    This is at least a static typing compatibility break for callers passing scalar strings/numbers. The raw clients pass these parameters through directly, so it may remain runtime-tolerant in common cases, but it is no longer part of the declared SDK contract.

Given the number of removed symbols and incompatible model changes, this should be treated as a major-version release unless compatibility aliases/adapters are restored for the old public names and model shapes.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chiragjn

chiragjn commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

Breaking Changes Report: chiragjn-nullable-optional vs main

Branch chiragjn-nullable-optional
Base main
Commits 2619285, 681ee5f, 9e3ad50, edc6e38 (SDK regeneration)
Diff size ~293 files, +9414 / −1995
Last updated for edc6e38
Scope Public SDK only (client.*, package exports, types/). client.internal.* ignored.
Note This SDK has no client.v1 prefix; public methods are client.<resource>.<method>.

Verdict: No public methods were removed and no method arguments were deleted. Breaking impact is concentrated in renamed/removed exported types, enum member removals, model shape changes (especially gateway logging and agent MCP/skill types), and narrowed list-filter parameter types (bare scalars no longer accepted).

Update from edc6e38 (vs previous report)

Change vs main impact
Budget *Dto type renames (BudgetUsageResponseDtoBudgetUsageResponse, etc.) None for main upgradersclient.gateway_budgets is new on this branch; only breaks code written against intermediate branch commits
CreateOrUpdateBudgetDtoManifestCreateOrUpdateBudgetRequestManifest Same — new API only
PySparkTaskConfig.image: TaskPySparkBuildPySparkTaskConfigImage (Union[TaskPySparkBuild, TaskSparkImage]) Soft — existing TaskPySparkBuild values remain valid; annotations expecting exactly TaskPySparkBuild need updating
CiscoAiDefenseGuardrailConfig added to guardrail union Additive (non-breaking)

Severity legend

Level Meaning
Hard Import fails, attribute missing, constructor/validation fails, or enum member gone
Soft Type rename / annotation narrowing — often still works at runtime with string/dict inputs, but breaks typed code and some call patterns

1. Removed public exports / types (Hard)

These names are no longer exported from truefoundry_sdk (and their modules were deleted or replaced).

Removed symbol Replacement / notes
ResourceType UpdateUserRolesRequestResourceType (used by client.users.update_roles). Members are a superset of the old enum (added AGENT_CHANNEL, GATEWAY_APPROVAL_REQUEST, GATEWAY_POLICY).
BuildStatus DeploymentBuildStatus (same members: STARTED, SUCCEEDED, FAILED)
IChangeOperation IChangeType (same members: REMOVE, ADD, UPDATE)
GatewayLoggingRule Removed with logging-config redesign (see §3)
GatewayLoggingWhen Replaced conceptually by LoggingWhen (different shape)
AgentsListRequestType ListAgentsRequestType
ApplicationsListRequestDeviceTypeFilter ListApplicationsRequestDeviceTypeFilter
ApplicationsListRequestLifecycleStage ListApplicationsRequestLifecycleStage
ApplicationsCancelDeploymentResponse CancelDeploymentApplicationsResponse

Deleted type modules:

  • src/truefoundry_sdk/types/build_status.py
  • src/truefoundry_sdk/types/gateway_logging_rule.py
  • src/truefoundry_sdk/types/gateway_logging_when.py
  • src/truefoundry_sdk/types/i_change_operation.py
  • src/truefoundry_sdk/types/resource_type.py

2. Enum member removals (Hard)

Enum Removed member Value
SubjectType EXTERNAL_IDENTITY "external-identity"
RoleBindingSubjectType EXTERNAL_IDENTITY "external-identity"

Impact:

  • SubjectType.EXTERNAL_IDENTITY / RoleBindingSubjectType.EXTERNAL_IDENTITY attribute access fails.
  • .visit(...) callbacks that previously required external_identity= will fail (parameter removed from visit signature).
  • Subject.subject_type now types as SubjectSubjectType (new export). Relative to old SubjectType, that type also lacks EXTERNAL_IDENTITY.

No other enum member removals were found across the public type tree. (VertexRegion only adds members.)


3. Model / type shape breaking changes (Hard)

3.1 GatewayLoggingConfig — redesigned

Before After
Required payload rules: List[GatewayLoggingRule] name: str, log: bool
Conditions Per-rule GatewayLoggingWhen (subjects: Optional[List[str]]) Top-level when: Optional[LoggingWhen] (subjects/models as InNotIn, plus metadata)
Removed rules, GatewayLoggingRule, GatewayLoggingWhen
Added name, log, when, redact_with

Any code constructing or reading GatewayLoggingConfig.rules breaks.

3.2 BudgetV2Alert.notify_breaching_user removed

Field notify_breaching_user: Optional[bool] removed from BudgetV2Alert. Keyword/getattr usage breaks; leftover JSON may still parse if extra="allow", but the attribute is gone from the model.

3.3 TrueFoundryAgentUserMessage discriminator change

Before After
role: Literal["user"] (default "user") removed
type: Literal["user.message"] (default "user.message")

Code that sets/reads .role breaks. .type is the new discriminator.

3.4 TrueFoundryAgentMcpServer — class → discriminated union

Before: single model with name, preload, tool lists (no type / url).

After:

TrueFoundryAgentMcpServer = Union[
    TrueFoundryAgentMcpServerRegistry,  # type="truefoundry-mcp-registry", name=...
    TrueFoundryAgentMcpServerInline,    # type="inline", name=..., url=...
]

Old instances without a type discriminator (and without url for inline) are no longer valid as the previous flat class.

3.5 TrueFoundryAgentSkill — class → discriminated union

Before: model with fqn, preload.

After:

TrueFoundryAgentSkill = Union[
    TrueFoundryAgentTrueFoundrySkill,  # type="truefoundry-skills-registry", fqn=..., preload=...
    TrueFoundryAgentGitSourceSkill,    # type="git", url=..., name=..., ref=..., path=?
]

Constructing the old flat {fqn, preload} object as TrueFoundryAgentSkill(...) no longer works; use TrueFoundryAgentTrueFoundrySkill (or include type).

3.6 IdentityProviderBackedIdentity.type literal changed

Before After
"idp-backed" "identity-provider-backed"

Breaks discriminator checks / serialized payloads that hard-code the old literal.

3.7 TrueFoundryApplyResponse.data type changed

Before After
Optional[Dict[str, Any]] Optional[TrueFoundryApplyResponseData] (union of entity models)

Dict-style access patterns (response.data["id"], etc.) may break depending on runtime object type.

3.8 Field type renames (import / annotation breaks)

Type.field Before After
DeploymentBuild.status Optional[BuildStatus] Optional[DeploymentBuildStatus]
IChange.type IChangeOperation IChangeType
GcpGkeIntegration.location GcpRegion GcpGkeIntegrationLocation (superset; all old GcpRegion values remain)
Subject.subject_type SubjectType SubjectSubjectType
PySparkTaskConfig.image TaskPySparkBuild PySparkTaskConfigImage = Union[TaskPySparkBuild, TaskSparkImage] (widening; TaskPySparkBuild still accepted)

4. Client method breaking / soft-breaking changes

4.1 No removed methods; no removed arguments

Public method inventory: 142 → 150. Added (non-breaking):

  • client.agents.get_token
  • client.gateway_budgets.* (create_or_update, delete, get, get_leaderboard, get_my_usage, list, simulate)

Current public type names for the new gateway budgets API (after edc6e38):

Method Parameter / return Type
client.gateway_budgets.create_or_update manifest CreateOrUpdateBudgetRequestManifest
client.gateway_budgets.get_leaderboard / get_my_usage / simulate return BudgetUsageResponse

4.2 Scalar→sequence narrowing (Soft → Hard for some call sites)

These parameters no longer accept a bare scalar; pass a sequence/list.

Optional[Union[T, Sequence[T]]]Optional[Sequence[T]]

Method Parameter(s)
client.agents.list attributes
client.artifact_versions.list run_ids, run_steps
client.clusters.get_addons attributes
client.clusters.list attributes
client.events.get pod_names
client.jobs.list_runs triggered_by, version_numbers
client.logs.get pod_names
client.ml_repos.list attributes
client.model_versions.list run_ids, run_steps
client.secret_groups.list attributes
client.teams.list attributes
client.virtual_accounts.list owned_by_teams
client.workspaces.list attributes

Example break: client.agents.list(attributes="id") → use attributes=["id"].

4.3 Request/response type renames on methods (Hard for typed imports)

Method Parameter / return Before After
client.agents.list type AgentsListRequestType ListAgentsRequestType
client.applications.list device_type_filter ApplicationsListRequestDeviceTypeFilter ListApplicationsRequestDeviceTypeFilter
client.applications.list lifecycle_stage ApplicationsListRequestLifecycleStage ListApplicationsRequestLifecycleStage
client.users.update_roles resource_type ResourceType UpdateUserRolesRequestResourceType
client.applications.cancel_deployment return ApplicationsCancelDeploymentResponse CancelDeploymentApplicationsResponse

5. Non-breaking / additive type changes (for context)

Not breaking by themselves, but useful for migration awareness:

  • Several fields became optional: AgentIdentityManifest.owned_by, McpServerOAuth2.jwt_source, McpServerOAuth2.token_url, TeamBudgetConfig.when, TenantBudgetConfig.when.
  • Union widenings: AgentChannelManifest added to apply/delete manifest unions; NomaSecurityGuardrailConfig and CiscoAiDefenseGuardrailConfig added to guardrail integrations; ComplexityBasedLoadBalancing added to header routing; TaskSparkImage added as alternate PySparkTaskConfig.image; GatewayLoggingConfig reordered inside GatewayConfig union (still present).
  • Many new exports (gateway budgets, agent channels, MCP variants, etc.).

5.1 Intermediate-branch-only renames (edc6e38)

These symbols never existed on main. They only break consumers of earlier commits on this branch:

Previous branch name Current name
BudgetEntityUsageDto BudgetEntityUsage
BudgetUsageEntryDto BudgetUsageEntry
BudgetUsageEntryDtoMode BudgetUsageEntryMode
BudgetUsageEntryDtoType BudgetUsageEntryType
BudgetUsageResponseDto BudgetUsageResponse
PeriodUsageDto PeriodUsage
CreateOrUpdateBudgetDtoManifest CreateOrUpdateBudgetRequestManifest

6. Migration checklist (highest impact first)

  1. Replace imports for renamed/removed types in §1 (ResourceType, BuildStatus, IChangeOperation, list-request enums, cancel-deployment response).
  2. Stop using SubjectType.EXTERNAL_IDENTITY / RoleBindingSubjectType.EXTERNAL_IDENTITY; update any .visit(external_identity=...) call sites.
  3. Rewrite GatewayLoggingConfig construction/consumption for the new name / log / when / redact_with model; drop rules / GatewayLoggingRule.
  4. Update agent manifests:
    • MCP servers → TrueFoundryAgentMcpServerRegistry or TrueFoundryAgentMcpServerInline with type.
    • Skills → TrueFoundryAgentTrueFoundrySkill or TrueFoundryAgentGitSourceSkill with type.
    • User messages → type="user.message" instead of role="user".
  5. Fix list filters that passed a bare str/float — wrap in a list/sequence (§4.2).
  6. Update IdentityProviderBackedIdentity discriminator to "identity-provider-backed".
  7. Remove uses of BudgetV2Alert.notify_breaching_user.
  8. Revisit client.apply response handling if code treated data as dict.
  9. Optional: if typing PySparkTaskConfig.image, use PySparkTaskConfigImage (still pass TaskPySparkBuild at runtime).

7. Analysis method / coverage

Check How
Method add/remove/params Parsed reference.md (main vs HEAD); verified with AST on **/client.py (excl. internal)
Public export add/remove Diffed src/truefoundry_sdk/__init__.py exports
Type field / enum / alias diffs AST compare of shared type modules under types/ and resource types/
Removed type modules git ls-tree diff of src/truefoundry_sdk/types/
Latest commit refresh git diff HEAD~1 / export diff for edc6e38

Progress checklist

  • Method inventory from reference.md
  • Method parameter / return-type diffs (docs + client AST)
  • Type field removals / type changes
  • Enum member removals
  • Removed public exports / types
  • Final summary
  • Refreshed for edc6e38

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e2836b5. Configure here.

Comment thread reference.md
<dd>

**lifecycle_stage:** `typing.Optional[ApplicationsListRequestLifecycleStage]` — Application lifecycle stage to filter by
**lifecycle_stage:** `typing.Optional[ListApplicationsRequestLifecycleStage]` — Application lifecycle stage to filter by

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Public request type names renamed

High Severity

Public types were renamed without aliases, which breaks existing imports. ApplicationsListRequestDeviceTypeFilter / ApplicationsListRequestLifecycleStage became ListApplicationsRequest*, ApplicationsCancelDeploymentResponse became CancelDeploymentApplicationsResponse, and AgentsListRequestType became ListAgentsRequestType. This violates the PR request to flag interface-breaking type renames/removals in the public SDK.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e2836b5. Configure here.

Comment thread reference.md
<dd>

**owned_by_teams:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Comma-separated team names. Return virtual accounts owned by these teams.
**owned_by_teams:** `typing.Optional[typing.List[str]]` — Comma-separated team names. Return virtual accounts owned by these teams.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Array params no longer accept strings

Medium Severity

Several public list filters narrowed from Union[str, Sequence[...]] to List[...] only, including owned_by_teams, triggered_by, version_numbers, pod_names, run_ids, run_steps, and multiple attributes parameters. Call sites that passed a bare string will no longer type-check. This violates the PR request to flag public API argument/type breaking changes.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e2836b5. Configure here.

Comment thread reference.md
<dd>

**resource_type:** `typing.Optional[ResourceType]` — Resource type scope for the role assignment.
**resource_type:** `typing.Optional[UpdateUserRolesRequestResourceType]` — Resource type scope for the role assignment.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Roles resource type renamed

Medium Severity

client.users.update_roles changed resource_type from ResourceType to UpdateUserRolesRequestResourceType. Imports and annotations using the old public type name will break. This violates the PR request to flag breaking type renames in the public SDK.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e2836b5. Configure here.

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.

1 participant