-
Notifications
You must be signed in to change notification settings - Fork 29
Description
Summary
The sdk/python/generate_models.sh and generate_ts_schema_types.js scripts both expect a spec/ directory containing pre-resolved JSON schemas. However:
spec/is gitignored (line 3 of.gitignore)- No script exists to generate
spec/fromsource/schemas/ - Running the generators fails with
FileNotFoundError: /path/to/spec
Background
UCP schemas in source/schemas/ contain ucp_request and ucp_response annotations that control field visibility per direction and operation. These annotations must be resolved before generating SDK models.
Per CONTRIBUTING.md:
"Schemas live in
source/and are published withucp_*annotations intact. Agents use ucp-schema to resolve annotations for specific operations at runtime."
Current State of Scripts
| Script | Input | Output | Status |
|---|---|---|---|
main.py (MkDocs) |
source/schemas/ |
Resolves at runtime | Works - calls ucp-schema resolve on-demand |
generate_ts_schema_types.js |
spec/ |
generated/schema-types.ts |
Broken - spec/ doesn't exist |
sdk/python/generate_models.sh |
../../spec/ |
src/ucp_sdk/models/ |
Broken - spec/ doesn't exist |
How main.py Resolves Schemas (lines 88-137)
cmd = [
"ucp-schema",
"resolve",
str(schema_path),
"--request" if direction == "request" else "--response",
"--op",
operation,
]
if bundle:
cmd.append("--bundle")
result = subprocess.run(cmd, capture_output=True, text=True, check=False)This works for documentation because it resolves at runtime. But the SDK generators need pre-resolved schemas in spec/.
Missing Models
Comparing source/schemas/shopping/ with models/schemas/shopping/:
| UCP Schema | Models Generated |
|---|---|
cart.json |
None - completely missing |
All other schemas (checkout.json, discount.json, fulfillment.json, buyer_consent.json, ap2_mandate.json, order.json, payment.json) have corresponding models.
Proposed Solution: generate_spec.sh
Create a script that populates spec/ from source/schemas/ using ucp-schema resolve. This script should:
- Resolve annotated schemas for all directions/operations
- Bundle
$refpointers for self-contained schemas - Mirror the structure expected by existing generators
Suggested Implementation
#!/bin/bash
# generate_spec.sh - Generate resolved schemas into spec/ directory
#
# This script uses ucp-schema to resolve UCP annotations from source/schemas/
# and outputs self-contained JSON schemas to spec/ for SDK generators.
set -e
cd "$(dirname "$0")"
# Directories
SOURCE_DIR="source/schemas"
SPEC_DIR="spec"
# Schemas with UCP annotations
ANNOTATED_SCHEMAS=(
"shopping/checkout.json"
"shopping/cart.json"
"shopping/discount.json"
"shopping/fulfillment.json"
"shopping/ap2_mandate.json"
"shopping/buyer_consent.json"
)
# Schemas without UCP annotations (just bundle refs)
PLAIN_SCHEMAS=(
"shopping/order.json"
"shopping/payment.json"
)
# Operations for request direction (matching existing models)
REQUEST_OPS=("create" "update")
# Check for ucp-schema
if ! command -v ucp-schema &> /dev/null; then
echo "Error: ucp-schema not found."
echo "Install with: cargo install ucp-schema"
exit 1
fi
# Setup directories
echo "Setting up spec/ directory..."
rm -rf "$SPEC_DIR"
mkdir -p "$SPEC_DIR/schemas/shopping"
mkdir -p "$SPEC_DIR/handlers"
# Resolve annotated schemas
echo "Resolving annotated schemas..."
for schema in "${ANNOTATED_SCHEMAS[@]}"; do
basename=$(basename "$schema" .json)
echo " Processing $basename..."
# Response schema (read operation)
ucp-schema resolve "$SOURCE_DIR/$schema" \
--response --op read --bundle --pretty \
> "$SPEC_DIR/schemas/shopping/${basename}_resp.json"
# Request schemas for each operation
for op in "${REQUEST_OPS[@]}"; do
ucp-schema resolve "$SOURCE_DIR/$schema" \
--request --op "$op" --bundle --pretty \
> "$SPEC_DIR/schemas/shopping/${basename}_${op}_req.json"
done
done
# Bundle plain schemas
echo "Bundling plain schemas..."
for schema in "${PLAIN_SCHEMAS[@]}"; do
basename=$(basename "$schema" .json)
echo " Bundling $basename..."
ucp-schema resolve "$SOURCE_DIR/$schema" \
--response --op read --bundle --pretty \
> "$SPEC_DIR/schemas/shopping/${basename}.json"
done
# Copy types (no resolution needed)
echo "Copying type schemas..."
mkdir -p "$SPEC_DIR/schemas/shopping/types"
cp "$SOURCE_DIR/shopping/types/"*.json "$SPEC_DIR/schemas/shopping/types/"
echo ""
echo "Done! Resolved schemas written to $SPEC_DIR/"
find "$SPEC_DIR" -name "*.json" | wc -l | xargs echo "Total JSON files:"Updated Workflow
After adding generate_spec.sh:
source/schemas/ --(generate_spec.sh)--> spec/ --(generate_models.sh)--> models/
| |
| +--(generate_ts_schema_types.js)--> generated/
|
uses ucp-schema resolve
CI Integration
Add to .github/workflows/docs.yml or create a new workflow:
- name: Generate spec/ from source/
run: ./generate_spec.sh
- name: Generate Python models
run: bash sdk/python/generate_models.sh
- name: Generate TypeScript types
run: node generate_ts_schema_types.jsPrevious Attempt
I attempted to create a workaround script at /Users/dguim/localwork/ucp/generate_pydantic_models.sh that:
- Used
ucp-schema resolveto generate resolved schemas - Ran
datamodel-code-generatoron the output
However, this produced problematic Pydantic models. For example, in the generated response/checkout.py:
class Instrument(Checkout):
"""A payment instrument with selection state."""
model_config = ConfigDict(
extra="allow",
)
selected: bool | None = NoneThis incorrectly has Instrument inheriting from Checkout, which doesn't make semantic sense - a payment instrument should not be a full checkout object. This appears to be an artifact of how datamodel-code-generator interprets the allOf composition in the bundled JSON Schema.
This suggests that either:
- The schema bundling strategy needs adjustment
datamodel-code-generatoroptions need tuning- The
spec/structure should be different from what I attempted
Questions for Maintainers
-
Is this the intended approach? Should
spec/be generated fromsource/usingucp-schema? -
Naming convention: Should resolved schemas use
{name}_resp.json/{name}_{op}_req.jsonformat, or a different structure? -
Why is Cart missing?
cart.jsonexists insource/schemas/shopping/but has no generated models. -
Handler schemas: Should
source/handlers/also be resolved intospec/handlers/?
Related Files
.gitignoreline 3:/spec/main.pylines 88-137: Runtime resolution for docsgenerate_ts_schema_types.jsline 5:SOURCE_ROOT = path.resolve(__dirname, 'spec')sdk/python/generate_models.shline 11:SCHEMA_DIR="../../spec/"ucp-schemaCLI: https://github.com/universal-commerce-protocol/ucp-schema