Make OpenAPI tool names provider-safe
This commit is contained in:
32
agent.py
32
agent.py
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -38,6 +39,34 @@ PATH_PARAMETER_RE = re.compile(r"{([^}/]+)}")
|
|||||||
SOURCE_ROOT = Path(globals().get("__file__", "agent.py")).resolve().parent
|
SOURCE_ROOT = Path(globals().get("__file__", "agent.py")).resolve().parent
|
||||||
SOURCE_SKILLS_DIR = SOURCE_ROOT / "skills"
|
SOURCE_SKILLS_DIR = SOURCE_ROOT / "skills"
|
||||||
RUNTIME_SKILLS_DIR = ".deepagents/openapi-skills/"
|
RUNTIME_SKILLS_DIR = ".deepagents/openapi-skills/"
|
||||||
|
MAX_OPENAI_TOOL_NAME_LENGTH = 64
|
||||||
|
|
||||||
|
|
||||||
|
def _openai_safe_tool_name(name: str, used: set[str]) -> str:
|
||||||
|
safe = re.sub(r"[^a-zA-Z0-9_-]+", "_", name).strip("_") or "operation"
|
||||||
|
if len(safe) > MAX_OPENAI_TOOL_NAME_LENGTH:
|
||||||
|
digest = hashlib.sha1(safe.encode("utf-8")).hexdigest()[:10]
|
||||||
|
prefix = safe[: MAX_OPENAI_TOOL_NAME_LENGTH - len(digest) - 1].rstrip("_-")
|
||||||
|
safe = f"{prefix or 'operation'}_{digest}"
|
||||||
|
candidate = safe
|
||||||
|
index = 2
|
||||||
|
while candidate in used:
|
||||||
|
suffix = f"_{index}"
|
||||||
|
candidate = safe[: MAX_OPENAI_TOOL_NAME_LENGTH - len(suffix)].rstrip("_-") + suffix
|
||||||
|
index += 1
|
||||||
|
used.add(candidate)
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_operation_tool_names() -> None:
|
||||||
|
used: set[str] = set()
|
||||||
|
for operation_id, operation in OPERATIONS.items():
|
||||||
|
original = str(operation.get("skill_name") or operation_id)
|
||||||
|
operation["original_skill_name"] = original
|
||||||
|
operation["skill_name"] = _openai_safe_tool_name(original, used)
|
||||||
|
|
||||||
|
|
||||||
|
_normalize_operation_tool_names()
|
||||||
|
|
||||||
|
|
||||||
class OperationInput(BaseModel):
|
class OperationInput(BaseModel):
|
||||||
@@ -241,6 +270,7 @@ class Learnhouse(A2AAgent):
|
|||||||
)
|
)
|
||||||
if operation.get("request_body") is not None:
|
if operation.get("request_body") is not None:
|
||||||
parts.append("Accepts a JSON request body.")
|
parts.append("Accepts a JSON request body.")
|
||||||
|
parts.append(f"Operation ID: {operation.get('operation_id') or operation.get('original_skill_name')}")
|
||||||
return "\n".join(part for part in parts if part)
|
return "\n".join(part for part in parts if part)
|
||||||
|
|
||||||
async def _request(
|
async def _request(
|
||||||
@@ -287,6 +317,7 @@ class Learnhouse(A2AAgent):
|
|||||||
"ok": False,
|
"ok": False,
|
||||||
"status_code": response.status_code,
|
"status_code": response.status_code,
|
||||||
"operation_id": operation_id,
|
"operation_id": operation_id,
|
||||||
|
"tool_name": operation.get("skill_name"),
|
||||||
"error": payload,
|
"error": payload,
|
||||||
}
|
}
|
||||||
if response.status_code in {404, 405, 410, 422}:
|
if response.status_code in {404, 405, 410, 422}:
|
||||||
@@ -299,6 +330,7 @@ class Learnhouse(A2AAgent):
|
|||||||
"ok": True,
|
"ok": True,
|
||||||
"status_code": response.status_code,
|
"status_code": response.status_code,
|
||||||
"operation_id": operation_id,
|
"operation_id": operation_id,
|
||||||
|
"tool_name": operation.get("skill_name"),
|
||||||
"result": payload,
|
"result": payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user