Skip to content

Commit 4b05984

Browse files
committed
Merge remote-tracking branch 'upstream/main' into responses_prompt_templates
2 parents ca251d0 + 4d8ec08 commit 4b05984

189 files changed

Lines changed: 17819 additions & 395 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Llama Stack uses GitHub Actions for Continuous Integration (CI). Below is a tabl
1515
| Integration Tests (Replay) | [integration-tests.yml](integration-tests.yml) | Run the integration test suites from tests/integration in replay mode |
1616
| Vector IO Integration Tests | [integration-vector-io-tests.yml](integration-vector-io-tests.yml) | Run the integration test suite with various VectorIO providers |
1717
| OpenAPI Generator SDK Validation | [openapi-generator-validation.yml](openapi-generator-validation.yml) | Validate OpenAPI Generator SDK generation |
18+
| OpenResponses Conformance Tests | [openresponses-conformance.yml](openresponses-conformance.yml) | Run OpenResponses conformance tests against llama-stack Responses API |
1819
| Pre-commit | [pre-commit.yml](pre-commit.yml) | Run pre-commit checks |
1920
| Test Llama Stack Build | [providers-build.yml](providers-build.yml) | Test llama stack build |
2021
| Test llama stack list-deps | [providers-list-deps.yml](providers-list-deps.yml) | Test llama stack list-deps |

.github/workflows/openapi-generator-validation.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ on:
77
paths:
88
# OpenAPI Generator files
99
- 'client-sdks/openapi/Makefile'
10-
- 'client-sdks/openapi/merge_stainless_to_openapi.py'
10+
- 'client-sdks/openapi/merge_stainless_config.py'
11+
- 'client-sdks/openapi/build_hierarchy.py'
12+
- 'client-sdks/openapi/patch_hierarchy.py'
1113
- 'client-sdks/openapi/patches.yml'
1214
- 'client-sdks/openapi/openapi-config.json'
1315
- 'client-sdks/openapi/openapitools.json'
@@ -56,7 +58,9 @@ jobs:
5658
filters: |
5759
critical:
5860
- 'client-sdks/openapi/Makefile'
59-
- 'client-sdks/openapi/merge_stainless_to_openapi.py'
61+
- 'client-sdks/openapi/merge_stainless_config.py'
62+
- 'client-sdks/openapi/build_hierarchy.py'
63+
- 'client-sdks/openapi/patch_hierarchy.py'
6064
- 'client-sdks/openapi/patches.yml'
6165
- 'client-sdks/openapi/openapitools.json'
6266
- 'client-sdks/stainless/openapi.yml'
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
name: OpenResponses Conformance Tests
2+
3+
run-name: Run OpenResponses conformance tests against llama-stack Responses API
4+
5+
# This job is OPTIONAL and informational — it tracks progress toward full
6+
# conformance with the OpenResponses spec (https://openresponses.org).
7+
# Failures are expected while gaps remain in the Responses API implementation.
8+
# See: https://github.com/llamastack/llama-stack/issues/4818
9+
#
10+
# Inference calls are replayed from checked-in recordings under
11+
# tests/integration/openresponses/recordings/. To add or update recordings,
12+
# run the server locally with LLAMA_STACK_TEST_INFERENCE_MODE=record-if-missing
13+
# pointed at that directory, run the compliance tests, and commit the results.
14+
15+
on:
16+
push:
17+
branches:
18+
- main
19+
- 'release-[0-9]+.[0-9]+.x'
20+
paths:
21+
- 'src/llama_stack/providers/inline/agents/**'
22+
- 'src/llama_stack/apis/agents/**'
23+
- 'tests/integration/openresponses/**'
24+
- '.github/workflows/openresponses-conformance.yml'
25+
pull_request:
26+
branches:
27+
- main
28+
- 'release-[0-9]+.[0-9]+.x'
29+
paths:
30+
- 'src/llama_stack/providers/inline/agents/**'
31+
- 'src/llama_stack/apis/agents/**'
32+
- 'tests/integration/openresponses/**'
33+
- '.github/workflows/openresponses-conformance.yml'
34+
workflow_dispatch:
35+
36+
concurrency:
37+
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.ref }}
38+
cancel-in-progress: true
39+
40+
permissions:
41+
contents: read
42+
43+
jobs:
44+
openresponses-conformance:
45+
name: OpenResponses Conformance (Informational)
46+
runs-on: ubuntu-latest
47+
# Failures are expected — this job does NOT block PRs or merges.
48+
# It exists solely to track progress toward OpenResponses API conformance.
49+
continue-on-error: true
50+
51+
env:
52+
# Dummy key satisfies config parsing; actual inference is replayed from recordings
53+
OPENAI_API_KEY: "dummy-key-for-replay-mode"
54+
INFERENCE_MODEL: "openai/gpt-4o-mini"
55+
LLAMA_STACK_PORT: 8321
56+
LLAMA_STACK_TEST_INFERENCE_MODE: "replay"
57+
LLAMA_STACK_TEST_RECORDING_DIR: ${{ github.workspace }}/tests/integration/openresponses
58+
59+
steps:
60+
- name: Checkout repository
61+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
62+
63+
- name: Check for recordings
64+
id: check-recordings
65+
run: |
66+
RECORDINGS_DIR="${{ github.workspace }}/tests/integration/openresponses/recordings"
67+
COUNT=$(find "$RECORDINGS_DIR" -name "*.json" 2>/dev/null | wc -l)
68+
echo "recordings_count=$COUNT" >> $GITHUB_OUTPUT
69+
if [ "$COUNT" -eq 0 ]; then
70+
echo "::warning::No recordings found in tests/integration/openresponses/recordings/."
71+
echo "::warning::Run the server locally with LLAMA_STACK_TEST_INFERENCE_MODE=record-if-missing"
72+
echo "::warning::and commit the resulting recordings to enable conformance testing in CI."
73+
else
74+
echo "Found $COUNT recording(s)"
75+
fi
76+
77+
- name: Install dependencies
78+
uses: ./.github/actions/setup-runner
79+
with:
80+
python-version: '3.12'
81+
82+
- name: Install ci-tests distro provider dependencies
83+
run: uv run llama stack list-deps ci-tests --format uv | sh
84+
85+
- name: Start Llama Stack server
86+
run: |
87+
mkdir -p /tmp/llama-stack-conformance
88+
export LLAMA_STACK_LOG_WIDTH=200
89+
nohup uv run llama stack run ci-tests --port $LLAMA_STACK_PORT \
90+
> /tmp/llama-stack-conformance/server.log 2>&1 &
91+
echo "Server PID: $!"
92+
93+
- name: Wait for Llama Stack server to be ready
94+
run: |
95+
echo "Waiting for Llama Stack server..."
96+
for i in {1..60}; do
97+
if curl -s http://localhost:$LLAMA_STACK_PORT/v1/health | grep -q "OK"; then
98+
echo "Llama Stack server is ready!"
99+
exit 0
100+
fi
101+
sleep 2
102+
done
103+
echo "Llama Stack server failed to start in 120 seconds"
104+
cat /tmp/llama-stack-conformance/server.log
105+
exit 1
106+
107+
- name: Setup Bun
108+
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 #v2.0.0
109+
110+
- name: Clone OpenResponses repository
111+
run: |
112+
git clone --depth=1 https://github.com/openresponses/openresponses.git /tmp/openresponses
113+
114+
- name: Install OpenResponses dependencies
115+
working-directory: /tmp/openresponses
116+
run: bun install
117+
118+
- name: Run OpenResponses conformance tests
119+
id: run-tests
120+
run: |
121+
cd /tmp/openresponses
122+
bun run bin/compliance-test.ts \
123+
--base-url "http://localhost:$LLAMA_STACK_PORT/v1" \
124+
--api-key "llama-stack" \
125+
--model "$INFERENCE_MODEL" \
126+
--json > /tmp/openresponses-results.json 2>/dev/null || true
127+
128+
echo "=== OpenResponses Conformance Test Output ==="
129+
bun run bin/compliance-test.ts \
130+
--base-url "http://localhost:$LLAMA_STACK_PORT/v1" \
131+
--api-key "llama-stack" \
132+
--model "$INFERENCE_MODEL" \
133+
--verbose 2>&1 | tee /tmp/openresponses-output.txt || true
134+
135+
- name: Generate conformance report
136+
if: always()
137+
run: |
138+
{
139+
echo "## OpenResponses Conformance Test Results"
140+
echo ""
141+
echo "> **Note:** These tests are **informational only** and track progress toward full"
142+
echo "> [OpenResponses](https://www.openresponses.org) API conformance."
143+
echo "> Failures are expected while gaps remain in the Responses API implementation."
144+
echo "> See [#4818](https://github.com/llamastack/llama-stack/issues/4818)."
145+
echo ""
146+
echo "**Model:** \`$INFERENCE_MODEL\`"
147+
echo "**Recordings:** ${{ steps.check-recordings.outputs.recordings_count }} file(s) in \`tests/integration/openresponses/recordings/\`"
148+
echo ""
149+
} >> $GITHUB_STEP_SUMMARY
150+
151+
if [ "${{ steps.check-recordings.outputs.recordings_count }}" -eq 0 ]; then
152+
{
153+
echo "### No Recordings Found"
154+
echo ""
155+
echo "To enable conformance testing, generate recordings locally:"
156+
echo '```bash'
157+
echo "OPENAI_API_KEY=\$YOUR_KEY bash scripts/record-openresponses-conformance.sh"
158+
echo ""
159+
echo "# Then commit the recordings"
160+
echo "git add tests/integration/openresponses/recordings/"
161+
echo "git commit -m 'chore: add OpenResponses conformance recordings'"
162+
echo '```'
163+
echo "Commit the resulting \`tests/integration/openresponses/recordings/*.json\` files."
164+
} >> $GITHUB_STEP_SUMMARY
165+
elif [ -f /tmp/openresponses-results.json ] && jq -e '.summary' /tmp/openresponses-results.json > /dev/null 2>&1; then
166+
PASSED=$(jq -r '.summary.passed' /tmp/openresponses-results.json)
167+
FAILED=$(jq -r '.summary.failed' /tmp/openresponses-results.json)
168+
TOTAL=$(jq -r '.summary.total' /tmp/openresponses-results.json)
169+
170+
{
171+
echo "### Summary"
172+
echo ""
173+
echo "| Metric | Count |"
174+
echo "|--------|-------|"
175+
echo "| ✅ Passed | $PASSED |"
176+
echo "| ❌ Failed | $FAILED |"
177+
echo "| **Total** | **$TOTAL** |"
178+
echo ""
179+
echo "### Test Details"
180+
echo ""
181+
echo "| Test | Status | Duration |"
182+
echo "|------|--------|----------|"
183+
jq -r '.results[] | "| \(.name) | \(if .status == "passed" then "✅ Pass" else "❌ Fail" end) | \(.duration // "—")ms |"' \
184+
/tmp/openresponses-results.json
185+
echo ""
186+
} >> $GITHUB_STEP_SUMMARY
187+
188+
if [ "$FAILED" -gt 0 ]; then
189+
{
190+
echo "### Failure Details"
191+
echo ""
192+
jq -r '.results[] | select(.status == "failed") | "**\(.name)**\n" + ((.errors // []) | map("- \(.)") | join("\n")) + "\n"' \
193+
/tmp/openresponses-results.json
194+
} >> $GITHUB_STEP_SUMMARY
195+
fi
196+
else
197+
{
198+
echo "### Results"
199+
echo ""
200+
echo "Could not parse structured results."
201+
if [ -f /tmp/openresponses-output.txt ]; then
202+
echo ""
203+
echo "<details><summary>Raw output</summary>"
204+
echo ""
205+
echo '```'
206+
cat /tmp/openresponses-output.txt
207+
echo '```'
208+
echo ""
209+
echo "</details>"
210+
fi
211+
} >> $GITHUB_STEP_SUMMARY
212+
fi
213+
214+
- name: Upload conformance test results
215+
if: always()
216+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
217+
with:
218+
name: openresponses-conformance-results-${{ github.run_id }}
219+
path: |
220+
/tmp/openresponses-results.json
221+
/tmp/openresponses-output.txt
222+
retention-days: 30
223+
if-no-files-found: warn
224+
225+
- name: Print server log on failure
226+
if: failure()
227+
run: |
228+
echo "=== Llama Stack server log (last 200 lines) ==="
229+
tail -200 /tmp/llama-stack-conformance/server.log || true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,7 @@ tests/integration/client-typescript/node_modules/
4444

4545
# client SDK generated files
4646
client-sdks/openapi/openapi.yml
47+
client-sdks/openapi/openapi-hierarchical.yml
48+
client-sdks/openapi/api-hierarchy.yml
4749
client-sdks/openapi/sdks/
4850
client-sdks/openapi/.openapi-generator/

.pre-commit-config.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ repos:
1616
- id: check-added-large-files
1717
args: ['--maxkb=1000']
1818
- id: end-of-file-fixer
19-
exclude: '^(.*\.svg|.*\.md)$'
19+
exclude: '^(.*\.svg|.*\.md|.*\.mustache)$'
2020
- id: no-commit-to-branch
2121
- id: check-yaml
2222
args: ["--unsafe"]
@@ -27,6 +27,7 @@ repos:
2727
- id: check-executables-have-shebangs
2828
- id: check-json
2929
- id: check-shebang-scripts-are-executable
30+
exclude: '^.*\.mustache$' # these are not executables, only templates of
3031
- id: check-symlinks
3132
- id: check-toml
3233

@@ -187,6 +188,7 @@ repos:
187188
- id: check-log-usage
188189
name: Ensure 'llama_stack.log' usage for logging
189190
entry: bash
191+
exclude: '^client-sdks/openapi/.*$'
190192
language: system
191193
types: [python]
192194
pass_filenames: true

client-sdks/openapi/Makefile

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,43 @@ PYTHON := uv run python
44
# Auto-detect openapi-generator command (npm installs as openapi-generator-cli, brew as openapi-generator)
55
OPENAPI_GENERATOR := $(shell command -v openapi-generator-cli 2>/dev/null || command -v openapi-generator 2>/dev/null || echo openapi-generator-cli)
66

7-
MERGE_SCRIPT := ./merge_stainless_to_openapi.py
7+
# Scripts
8+
MERGE_SCRIPT := ./merge_stainless_config.py
9+
HIERARCHY_SCRIPT := ./build_hierarchy.py
10+
PATCH_SCRIPT := ./patch_hierarchy.py
11+
12+
# Inputs
813
PATCHES_FILE := ./patches.yml
914
STAINLESS_CONFIG := $(STAINLESS_DIR)/config.yml
1015
STAINLESS_OPENAPI := $(STAINLESS_DIR)/openapi.yml
11-
OPENAPI_OUTPUT := openapi.yml
1216
OPENAPI_CONFIG := openapi-config.json
17+
TEMPLATE_DIR := ./templates/python
18+
19+
# Outputs
20+
OPENAPI_OUTPUT := openapi.yml
21+
PROCESSED_SPEC := openapi-hierarchical.yml
22+
HIERARCHY_FILE := api-hierarchy.yml
1323
SDK_OUTPUT_DIR := sdks/python
24+
PACKAGE_NAME := $(shell grep '"packageName"' $(OPENAPI_CONFIG) | cut -d'"' -f4)
1425

1526
# Extract version from root pyproject.toml
1627
VERSION := $(shell grep 'fallback_version' ../../pyproject.toml | cut -d'"' -f2)
1728

18-
.PHONY: all sdk openapi clean help version check-generator
29+
.PHONY: all sdk openapi hierarchy clean help version check-generator
1930

2031
all: sdk
2132

2233
help:
2334
@echo "Available targets:"
24-
@echo " all - Generate SDK (default)"
25-
@echo " openapi - Generate OpenAPI spec from Stainless config"
26-
@echo " sdk - Generate Python SDK from OpenAPI spec"
27-
@echo " version - Show version that will be used for SDK"
28-
@echo " clean - Remove generated files"
29-
@echo " help - Show this help message"
35+
@echo " all - Generate SDK (default)"
36+
@echo " openapi - Generate enriched OpenAPI spec from Stainless config"
37+
@echo " hierarchy - Process spec for hierarchical SDK (leaf tags, dummy endpoints)"
38+
@echo " sdk - Generate Python SDK with hierarchical API structure"
39+
@echo " version - Show version that will be used for SDK"
40+
@echo " clean - Remove generated files"
41+
@echo " help - Show this help message"
42+
@echo ""
43+
@echo "Pipeline: openapi -> hierarchy -> sdk (each target triggers its dependencies)"
3044

3145
version:
3246
@echo "SDK version: $(VERSION)"
@@ -62,19 +76,31 @@ check-generator:
6276
echo ""; \
6377
exit 1; }
6478

79+
# Step 1: Merge Stainless config into OpenAPI spec and apply patches
6580
openapi: $(OPENAPI_OUTPUT)
6681

6782
$(OPENAPI_OUTPUT): $(MERGE_SCRIPT) $(PATCHES_FILE) $(STAINLESS_CONFIG) $(STAINLESS_OPENAPI)
6883
@echo "Generating OpenAPI spec..."
6984
$(PYTHON) $(MERGE_SCRIPT) --patch $(PATCHES_FILE) --stainless $(STAINLESS_CONFIG) --openapi $(STAINLESS_OPENAPI) --output $(OPENAPI_OUTPUT)
7085

71-
sdk: check-generator $(OPENAPI_OUTPUT)
86+
# Step 2: Extract tag hierarchy, reduce to leaf tags, create dummy endpoints, fix schemas
87+
hierarchy: $(PROCESSED_SPEC)
88+
89+
$(PROCESSED_SPEC): $(HIERARCHY_SCRIPT) $(OPENAPI_OUTPUT)
90+
@echo "Processing hierarchy..."
91+
$(PYTHON) $(HIERARCHY_SCRIPT) --source $(OPENAPI_OUTPUT) --output $(PROCESSED_SPEC) --hierarchy $(HIERARCHY_FILE)
92+
93+
# Step 3: Generate Python SDK from processed spec, then patch in hierarchy
94+
sdk: check-generator $(PROCESSED_SPEC)
7295
@echo "Generating Python SDK (version: $(VERSION))..."
7396
@mkdir -p $(SDK_OUTPUT_DIR)
74-
$(OPENAPI_GENERATOR) generate -i $(OPENAPI_OUTPUT) -g python -c $(OPENAPI_CONFIG) -o $(SDK_OUTPUT_DIR) \
75-
--additional-properties=packageVersion=$(VERSION)
97+
$(OPENAPI_GENERATOR) generate -i $(PROCESSED_SPEC) -g python -c $(OPENAPI_CONFIG) -o $(SDK_OUTPUT_DIR) \
98+
--additional-properties=packageVersion=$(VERSION) -t $(TEMPLATE_DIR)
99+
@cp -R $(TEMPLATE_DIR)/lib $(SDK_OUTPUT_DIR)/$(PACKAGE_NAME)
100+
@echo "Patching SDK with hierarchical API structure..."
101+
$(PYTHON) $(PATCH_SCRIPT) --hierarchy $(HIERARCHY_FILE) --sdk-dir $(SDK_OUTPUT_DIR) --package $(PACKAGE_NAME)
76102

77103
clean:
78104
@echo "Cleaning generated files..."
79-
@rm -f $(OPENAPI_OUTPUT)
105+
@rm -f $(OPENAPI_OUTPUT) $(PROCESSED_SPEC) $(HIERARCHY_FILE)
80106
@rm -rf sdks

0 commit comments

Comments
 (0)