@@ -47,6 +47,81 @@ set_aicore_config(instance_name="aicore-production")
4747
4848---
4949
50+ ## Credential Rotation
51+
52+ BTP rotates AI Core service binding credentials automatically. The SDK
53+ handles this transparently — no pod restart required.
54+
55+ ### Reactive reload (completion wrapper)
56+
57+ ` sap_cloud_sdk.aicore.completion ` / ` acompletion ` catch ` AuthenticationError `
58+ (HTTP 401), reload credentials via ` set_aicore_config() ` , and retry the call
59+ once. The caller never sees the error.
60+
61+ ``` python
62+ from sap_cloud_sdk.aicore import completion, set_aicore_config
63+
64+ set_aicore_config()
65+
66+ # 401s are retried transparently — no extra code needed
67+ response = completion(model = " sap/anthropic--claude-4.5-sonnet" , messages = [... ])
68+ ```
69+
70+ ### Proactive reload (recommended for all agents)
71+
72+ ` watch_aicore_config() ` starts a daemon thread that polls the mounted secret
73+ directory every 60 seconds. When the directory mtime changes (Kubernetes
74+ performs an atomic symlink swap on rotation), it calls ` set_aicore_config() `
75+ before the cached OAuth token expires — so agents never see a 401 at all.
76+
77+ ``` python
78+ import threading
79+ from sap_cloud_sdk.aicore import set_aicore_config, watch_aicore_config
80+
81+ set_aicore_config() # load credentials at startup
82+ watch_aicore_config() # proactive reload on secret rotation
83+
84+ # Optional: stop cleanly at shutdown
85+ _stop = threading.Event()
86+ watch_aicore_config(stop_event = _stop)
87+ # at shutdown: _stop.set()
88+ ```
89+
90+ ### LangGraph / ChatLiteLLM agents
91+
92+ ` ChatLiteLLM ` (used in LangGraph agent templates) calls ` litellm.completion `
93+ directly, bypassing the SDK's reactive handler. Two options:
94+
95+ ** Option A — proactive watcher only (recommended, one line):**
96+
97+ ``` python
98+ from sap_cloud_sdk.aicore import set_aicore_config, watch_aicore_config
99+
100+ set_aicore_config()
101+ watch_aicore_config() # ADD THIS — no other changes needed
102+ ```
103+
104+ ** Option B — also add reactive reload for ChatLiteLLM:**
105+
106+ ``` python
107+ from sap_cloud_sdk.aicore import (
108+ set_aicore_config,
109+ patch_litellm_for_credential_rotation,
110+ watch_aicore_config,
111+ )
112+
113+ set_aicore_config()
114+ patch_litellm_for_credential_rotation() # patches litellm.completion globally
115+ watch_aicore_config()
116+ ```
117+
118+ ` patch_litellm_for_credential_rotation() ` wraps ` litellm.completion ` /
119+ ` litellm.acompletion ` globally so every caller in the process — including
120+ ` ChatLiteLLM ` — gets transparent 401 reload. Idempotent; call it once at
121+ startup.
122+
123+ ---
124+
50125## What It Does
51126
52127The ` set_aicore_config() ` function:
0 commit comments