Files
lingma-openai-gateway/scripts/smoke_tool_calls.sh
mmc 94a8025ae5 feat: add emulated tool-calling bridge for Lingma
Add a proxy-side tool emulation layer so Lingma requests can surface stable OpenAI tool_calls and Anthropic tool_use blocks even when upstream tool events are missing or inconsistent.

Constraint: Keep native Lingma tool event bridging as the first path and layer emulation as a fallback

Rejected: Depend exclusively on Lingma native tool/invoke events | tool visibility remains inconsistent across models and transports

Confidence: high

Scope-risk: moderate
2026-05-07 18:10:01 +08:00

118 lines
3.9 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
ENV_FILE="$ROOT_DIR/.env"
if [[ ! -f "$ENV_FILE" ]]; then
printf 'missing .env: %s\n' "$ENV_FILE" >&2
exit 1
fi
PORT="$(python3 - <<'PY'
from pathlib import Path
env = Path("/root/lingma-openai-gateway/.env")
vals = {}
for line in env.read_text().splitlines():
line = line.strip()
if not line or line.startswith('#') or '=' not in line:
continue
k, v = line.split('=', 1)
vals[k.strip()] = v.strip()
print(vals.get('PORT', '13013'))
PY
)"
API_KEY="$(python3 - <<'PY'
from pathlib import Path
env = Path("/root/lingma-openai-gateway/.env")
vals = {}
for line in env.read_text().splitlines():
line = line.strip()
if not line or line.startswith('#') or '=' not in line:
continue
k, v = line.split('=', 1)
vals[k.strip()] = v.strip()
keys = vals.get('API_KEYS', '')
print(keys.split(',')[0].strip())
PY
)"
BASE_URL="http://127.0.0.1:${PORT}"
printf '\n[1/5] /v1/models\n'
curl -fsS "$BASE_URL/v1/models" \
-H "Authorization: Bearer ${API_KEY}" | python3 -m json.tool
printf '\n[2/5] OpenAI non-stream tool call\n'
curl -fsS "$BASE_URL/v1/chat/completions" \
-H "Authorization: Bearer ${API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"model": "org_auto",
"stream": false,
"messages": [
{"role": "system", "content": "Use tools when available."},
{"role": "user", "content": "Use fetch_weather for Hangzhou and return the tool call."}
],
"tools": [
{"type": "function", "function": {"name": "fetch_weather", "description": "Get weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}
],
"tool_choice": {"type": "function", "function": {"name": "fetch_weather"}}
}' | python3 -m json.tool
printf '\n[3/5] Anthropic non-stream tool use\n'
curl -fsS "$BASE_URL/v1/messages" \
-H "x-api-key: ${API_KEY}" \
-H 'anthropic-version: 2023-06-01' \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 256,
"stream": false,
"messages": [
{"role": "user", "content": "Use fetch_weather for Hangzhou and return the tool call."}
],
"tools": [
{"name": "fetch_weather", "description": "Get weather for a city", "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}
],
"tool_choice": {"type": "tool", "name": "fetch_weather"}
}' | python3 -m json.tool
printf '\n[4/5] OpenAI stream tool call\n'
curl -fsS -N "$BASE_URL/v1/chat/completions" \
-H "Authorization: Bearer ${API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"model": "org_auto",
"stream": true,
"messages": [
{"role": "system", "content": "Use tools when available."},
{"role": "user", "content": "Use fetch_weather for Hangzhou and return the tool call."}
],
"tools": [
{"type": "function", "function": {"name": "fetch_weather", "description": "Get weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}
],
"tool_choice": {"type": "function", "function": {"name": "fetch_weather"}}
}'
printf '\n[5/5] Anthropic stream tool use\n'
curl -fsS -N "$BASE_URL/v1/messages" \
-H "x-api-key: ${API_KEY}" \
-H 'anthropic-version: 2023-06-01' \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 256,
"stream": true,
"messages": [
{"role": "user", "content": "Use fetch_weather for Hangzhou and return the tool call."}
],
"tools": [
{"name": "fetch_weather", "description": "Get weather for a city", "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}
],
"tool_choice": {"type": "tool", "name": "fetch_weather"}
}'
printf '\nsmoke tool-call checks completed\n'