Proxy: ADT REST write+activate fallback when EPOD does not activate a second PROG/FUNC write

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014aUaQeLnwbb1zTpN7kHeat
This commit is contained in:
Kral
2026-10-03 14:29:37 +02:00
parent 39769afce8
commit 428b3565b2
4 changed files with 61 additions and 1 deletions

View File

@@ -50,6 +50,8 @@ class ToolProxy:
self.fail_streak = 0
self.max_fail_streak = 0
self.log = open(log_path, "a")
self.adt = None
self.fallbacks = [] # writes that needed the ADT activation fallback
def schemas(self):
tools = [t for t in self.mcp.list_tools() if t["name"] in MODEL_TOOLS]
@@ -123,6 +125,8 @@ class ToolProxy:
if tool in WRITE_TOOLS and (tool == "sap_activate" or args.get("activate", True)):
self.activations += 1
err, text = self.mcp.call(tool, args)
if tool == "sap_push_source":
err, text = self._activation_fallback(args, err, text)
result = (err, self._filter(tool, text))
if tool in WRITE_TOOLS:
failed = err or '"success":false' in text.replace(" ", "")
@@ -133,6 +137,32 @@ class ToolProxy:
self.log.flush()
return result
def _activation_fallback(self, args, err, text):
"""EPOD does not activate a second write of a PROG or FUNC (outcome notExecuted, and sap_activate
cannot help). Write and activate the same source through ADT REST; the agent sees one normal result."""
otype = str(args.get("objectType", "")).upper()
if otype not in ("PROG", "FUNC") or args.get("includeType") or args.get("activate") is False \
or '"outcome":"notExecuted"' not in text.replace(" ", ""):
return err, text
name = str(args.get("objectName", "")).lower()
uri = (f"/sap/bc/adt/programs/programs/{name}" if otype == "PROG" else
f"/sap/bc/adt/functions/groups/{str(args.get('functionGroup', '')).lower()}/fmodules/{name}")
try:
if self.adt is None:
from .adt_client import AdtClient
self.adt = AdtClient()
done, msgs = self.adt.write_activate(uri, name.upper(), args.get("source", ""))
except Exception as e: # noqa: BLE001 keep the EPOD result when the fallback fails
self.fallbacks.append({"object": name, "error": str(e)[:200]})
return err, text
self.fallbacks.append({"object": name, "activated": done})
out = {"success": done,
"message": "Source written and activation requested." if done else
"Source written. Activation failed. See the activation messages.",
"activation": {"messages": [{"severity": sv, "message": tx} for sv, tx in msgs],
"activationExecuted": done, "success": done}}
return False, json.dumps(out)
def note(self, kind, content):
self.log.write(json.dumps({"t": time.time(), "kind": kind, "content": content}) + "\n")
self.log.flush()