Skip to content

feat: add SAP AI Core provider via Orchestration Service#1610

Open
Huimintai wants to merge 6 commits intokagent-dev:mainfrom
Huimintai:support-sap-gen-ai-hub
Open

feat: add SAP AI Core provider via Orchestration Service#1610
Huimintai wants to merge 6 commits intokagent-dev:mainfrom
Huimintai:support-sap-gen-ai-hub

Conversation

@Huimintai
Copy link
Copy Markdown

Add SAPAICore as a new model provider that routes through SAP AI Core's Orchestration Service, providing unified access to all model families (Anthropic, OpenAI, Gemini, Amazon, Meta, Mistral, DeepSeek, Qwen, etc.) via a single endpoint.

Go changes:

  • Add ModelProviderSAPAICore enum and SAPAICoreConfig CRD struct
  • Add SAPAICore ADK model type with MarshalJSON/ParseModel/ModelToEmbeddingConfig
  • Add translateModel case with OAuth2 credential injection via K8s Secret
  • Add HTTP API support (create/update/list/get) with proper flatten
  • Add CEL validation rules (XValidation, apiKeySecretKey exemption)
  • Add 48 supported models from Orchestration Service
  • Add SAP_AI_CORE_CLIENT_ID/SECRET env var registration

Python changes:

  • Add KAgentSAPAICoreLlm (BaseLlm) with Orchestration protocol support
  • Async OAuth2 token management (asyncio.to_thread, threading.Lock)
  • Cached httpx.AsyncClient with TLS configuration
  • Auto-discovery of orchestration deployment URL (1h TTL)
  • Automatic retry on 401/403/404/502/503/504 with cache invalidation
  • Full tool call support (streaming + non-streaming)
  • api_key_passthrough support via set_passthrough_key()

UI changes:

  • Add SAPAICore to provider type union, combobox icons, and form handling
  • Add SAPAICoreConfigPayload for create/update flows

Add SAPAICore as a new model provider that routes through SAP AI Core's
Orchestration Service, providing unified access to all model families
(Anthropic, OpenAI, Gemini, Amazon, Meta, Mistral, DeepSeek, Qwen, etc.)
via a single endpoint.

Go changes:
- Add ModelProviderSAPAICore enum and SAPAICoreConfig CRD struct
- Add SAPAICore ADK model type with MarshalJSON/ParseModel/ModelToEmbeddingConfig
- Add translateModel case with OAuth2 credential injection via K8s Secret
- Add HTTP API support (create/update/list/get) with proper flatten
- Add CEL validation rules (XValidation, apiKeySecretKey exemption)
- Add 48 supported models from Orchestration Service
- Add SAP_AI_CORE_CLIENT_ID/SECRET env var registration

Python changes:
- Add KAgentSAPAICoreLlm (BaseLlm) with Orchestration protocol support
- Async OAuth2 token management (asyncio.to_thread, threading.Lock)
- Cached httpx.AsyncClient with TLS configuration
- Auto-discovery of orchestration deployment URL (1h TTL)
- Automatic retry on 401/403/404/502/503/504 with cache invalidation
- Full tool call support (streaming + non-streaming)
- api_key_passthrough support via set_passthrough_key()

UI changes:
- Add SAPAICore to provider type union, combobox icons, and form handling
- Add SAPAICoreConfigPayload for create/update flows

Signed-off-by: Huimin Tai <huimin.tai@sap.com>
Copilot AI review requested due to automatic review settings April 1, 2026 11:55
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 pull request adds comprehensive support for SAP AI Core as a new model provider. The implementation enables users to access all SAP AI Core model families (Anthropic, OpenAI, Gemini, Amazon, Meta, Mistral, DeepSeek, Qwen, etc.) through a unified Orchestration Service endpoint.

Changes:

  • Adds SAPAICore model provider enum and configuration types across Go, Python, and UI layers
  • Implements KAgentSAPAICoreLlm with full Orchestration protocol support, OAuth2 token caching, and automatic deployment URL discovery
  • Integrates OAuth2 credential injection via Kubernetes secrets for secure authentication
  • Adds HTTP API endpoints (create/update/list/get) with proper configuration flattening
  • Implements CEL validation rules for provider-specific configuration enforcement
  • Registers 48 supported models from SAP's Orchestration Service
  • Adds environment variable registration for SAP_AI_CORE_CLIENT_ID and SAP_AI_CORE_CLIENT_SECRET
  • Updates UI components to include SAPAICore provider with appropriate icons and form handling

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated no comments.

Show a summary per file
File Description
go/api/v1alpha2/modelconfig_types.go Defines SAPAICoreConfig struct with BaseURL, ResourceGroup, and AuthURL fields; adds validation rules for provider configuration
go/api/adk/types.go Adds SAPAICore model type with JSON marshaling and embedding config support
go/core/internal/controller/translator/agent/adk_api_translator.go Implements translation of K8s ModelConfig resources to ADK SAPAICore models with OAuth2 secret injection
go/core/internal/httpserver/handlers/modelconfig.go Adds SAPAICore parameter handling in create, update, list, and get endpoints
go/core/internal/httpserver/handlers/modelproviderconfig.go Registers SAPAICore in supported provider list with required/optional field metadata
go/core/internal/httpserver/handlers/models.go Lists 48 supported models from SAP Orchestration Service with function calling capabilities
go/core/pkg/env/providers.go Registers SAP_AI_CORE_CLIENT_ID and SAP_AI_CORE_CLIENT_SECRET environment variables
go/api/httpapi/types.go Adds SAPAICoreParams to create/update model config request types
python/packages/kagent-adk/src/kagent/adk/types.py Adds SAPAICore Pydantic model and includes it in ModelUnion
python/packages/kagent-adk/src/kagent/adk/models/_sap_ai_core.py Implements KAgentSAPAICoreLlm with async OAuth2 token management, TLS configuration, deployment URL discovery, and stream/non-stream request handling
python/packages/kagent-adk/src/kagent/adk/models/init.py Exports KAgentSAPAICoreLlm from models package
ui/src/types/index.ts Adds SAPAICoreConfigPayload interface for UI form handling
ui/src/lib/providers.ts Registers SAPAICore in provider list with documentation links
ui/src/components/ProviderCombobox.tsx Adds SAPAICore to provider icon mapping
ui/src/components/ModelProviderCombobox.tsx Adds SAPAICore to model provider icon mapping
ui/src/components/icons/SAPAICore.tsx Adds SAPAICore provider SVG icon component
ui/src/app/models/new/page.tsx Adds SAPAICore payload handling in model configuration form
helm/kagent-crds/templates/kagent.dev_modelproviderconfigs.yaml Updates CRD to include SAPAICore enum value
helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml Adds SAPAICore configuration schema and validation rules to CRD
go/api/config/crd/bases/*.yaml Corresponding CRD base definitions for SAPAICore support
go/api/v1alpha2/zz_generated.deepcopy.go Auto-generated deep copy functions for SAPAICoreConfig

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

@Huimintai
Copy link
Copy Markdown
Author

Huimintai commented Apr 1, 2026

This is my local test for this feature:

  • use sap-ai-core model in k8s-agent
image
  • create the sap-ai-core model from kagent UI:
image
# kubectl -n kagent get mc sapaicore-anthropic-claude-4-6-opus-test -oyaml
apiVersion: kagent.dev/v1alpha2
kind: ModelConfig
metadata:
  creationTimestamp: "2026-04-01T10:53:45Z"
  generation: 2
  name: sapaicore-anthropic-claude-4-6-opus-test
  namespace: kagent
  resourceVersion: "1022539"
  uid: b35b78ca-2b43-4bad-a8b4-bde6cb8b198b
spec:
  apiKeySecret: sap-aicore-creds
  apiKeySecretKey: client_id
  model: anthropic--claude-4.6-opus
  provider: SAPAICore
  sapAICore:
    authUrl: <xxx>
    baseUrl: <xxx>
    resourceGroup: default
status:
  conditions:
  - lastTransitionTime: "2026-04-01T10:53:45Z"
    message: Model configuration accepted
    reason: ModelConfigReconciled
    status: "True"
    type: Accepted
  observedGeneration: 2
  secretHash: eef86f8dd6085f031893de65c395d2321539712dc138495c25310a34a6e0259b

@Huimintai Huimintai force-pushed the support-sap-gen-ai-hub branch from 7c83010 to 71e796a Compare April 1, 2026 14:27
skhedim and others added 5 commits April 2, 2026 13:38
…skills (kagent-dev#1551)

## Problem

When an `Agent` spec includes a container `securityContext` with
`allowPrivilegeEscalation: false` (PSS Restricted profile) **and** the
agent
has `spec.skills.refs` configured, the controller generates an invalid
pod spec:

```
cannot set allowPrivilegeEscalation to false and privileged to true
```

Kubernetes rejects this combination at admission time, leaving the agent
stuck
in a reconciliation loop with all pods failing to start.

## Root cause

`buildManifest()` sets `needSandbox = true` when skills are present
(because
skills use `BashTool` which calls `srt` → bubblewrap for sandboxing),
then
blindly sets `Privileged: true` on whatever `securityContext` is
provided —
including one that already has `AllowPrivilegeEscalation: false`.

The securityContext merge did not check for this conflict before setting
`Privileged: true`.

## Fix

Add a helper `allowPrivilegeEscalationExplicitlyFalse()` that detects
when the
user has opted out of privilege escalation, and skip `Privileged: true`
in
that case.

When `Privileged` is withheld, `srt` degrades gracefully: on modern
kernels
(EKS, GKE, AL2023 ≥ 5.10) that have unprivileged user namespaces enabled
(`user.max_user_namespaces > 0`), bubblewrap can still create sandboxes
using
`clone(CLONE_NEWUSER)` without requiring a privileged seccomp profile.

> **Note on seccomp**: The containerd `RuntimeDefault` seccomp profile
blocks
> `clone(CLONE_NEWUSER)` without `CAP_SYS_ADMIN`. Users who need full
bwrap
> sandbox execution (running bash scripts inside skills) must
additionally
> provide a custom `seccompProfile: Localhost` with a profile that
allows
> user namespace syscalls. This PR makes agent deployment possible for
> PSS-Restricted namespaces; the seccomp tuning is an operational
concern
> separate from this bug.

## Behaviour matrix

| Agent spec | needSandbox | Result |
|---|---|---|
| skills or executeCode, **no** custom securityContext | `true` |
`Privileged: true` — full bwrap sandbox (unchanged) |
| skills + `allowPrivilegeEscalation: false` | `true` | No `Privileged`
— srt uses user-namespace mode |
| executeCode + `allowPrivilegeEscalation: false` | `true` | No
`Privileged` — srt uses user-namespace mode |
| No skills, no executeCode | `false` | No securityContext created
(unchanged) |

## Changes

### `go/core/internal/controller/translator/agent/adk_api_translator.go`

- Add comment explaining *why* `needSandbox = true` for skills (BashTool
→ srt → bwrap)
- Fix securityContext merge: guard `Privileged: true` with
`allowPrivilegeEscalationExplicitlyFalse()`
- Add `allowPrivilegeEscalationExplicitlyFalse()` helper

###
`go/core/internal/controller/translator/agent/security_context_test.go`

- Replace `TestSecurityContext_WithSandbox` (which tested an internally
  contradictory state) with two focused tests:
  - `TestSecurityContext_SkillsDefaultPrivilegedSandbox`: no custom
    securityContext → `Privileged: true` (default sandbox path)
- `TestSecurityContext_SkillsPSSRestricted`: `allowPrivilegeEscalation:
false`
    → no `Privileged`, original securityContext fields preserved intact

## Testing

```bash
cd go
go test -race -skip 'TestE2E.*' -v ./core/internal/controller/translator/agent/...
```

All existing tests pass. Two new tests cover both code paths.

## Related

- PSS Restricted policy:
https://kubernetes.io/docs/concepts/security/pod-security-standards/
- Bubblewrap user namespaces:
https://github.com/containers/bubblewrap#usage

Signed-off-by: skhedim <sebastien.khedim@gmail.com>
Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
…#1604)

## Summary

Closes kagent-dev#1560

The bundled PostgreSQL deployment now ships with Pod Security Admission
restricted-compliant defaults and exposes both pod-level and
container-level security context values for overrides.

- add default `RuntimeDefault` seccomp profiles for the bundled
PostgreSQL pod and container
- drop all container capabilities by default while keeping
`allowPrivilegeEscalation: false`
- move the bundled PostgreSQL pod and container security contexts into
chart values so users can customize them without patching templates
- extend Helm unit coverage for the new defaults and override paths

## Testing

- `make helm-version`
- `helm unittest helm/kagent`
- `helm lint helm/kagent`

Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
Chromatic allows us to visually review UI changes:
https://www.chromatic.com/builds?appId=69ccd5e5ca68b9aa5a54b890

---------

Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
## Summary
- Bumps `github.com/a2aproject/a2a-go` from v0.3.6 to v0.3.13
- Updates `KAgentTaskStore.Save` to match the new `a2asrv.TaskStore`
interface which added a `prev *a2a.Task` parameter

Supersedes kagent-dev#1598 (dependabot PR that fails CI due to the breaking
interface change).

## Test plan
- [ ] CI go-lint passes
- [ ] CI go-unit-tests pass
- [ ] CI build (golang-adk) passes

Signed-off-by: Jaison Paul <paul.jaison@gmail.com>
Implement SAPAICoreModel in the Go ADK runtime, enabling the golang-adk
image to use SAP AI Core models via the Orchestration Service.

- Add SAPAICoreModel with OAuth2 token management (thread-safe cache)
- Add automatic orchestration deployment URL discovery (1h TTL)
- Implement model.LLM interface (GenerateContent) with Orchestration
  protocol: modules format request, orchestration_result/final_result
  SSE stream parsing
- Add retry logic on 401/403/404/502/503/504 with cache invalidation
- Add *adk.SAPAICore case in CreateLLM()

Verified with go vet, existing unit tests, and oneshot E2E against
live SAP AI Core (both streaming and non-streaming).

Signed-off-by: Huimin Tai <huimin.tai@sap.com>
@Huimintai Huimintai force-pushed the support-sap-gen-ai-hub branch from 71e796a to 1cfa50a Compare April 2, 2026 05:38
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.

6 participants