feat: add template rollback endpoint [LET-7423] (#9455)

* feat: add template rollback endpoint [LET-7423]

Adds POST /v1/templates/:template_name/rollback endpoint to restore templates to previous versions.

Key features:
- Rollback to any numbered version (1, 2, 3, etc.) or "latest"
- Auto-saves unsaved changes before rollback to prevent data loss
- Validates input (rejects "current"/"dev" as target versions)
- Preserves entity IDs and relationships across rollback
- Uses project context from X-Project header (no project_id in path)

Implementation includes:
- API contract in templatesContract.ts
- Handler in templatesRouter.ts with comprehensive error handling
- 9 E2E tests covering functionality and edge cases
- Updated stainless.yml for SDK generation

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* chore test

* fix: add X-Project header to rollback endpoint tests

The rollback endpoint uses project context from X-Project header instead of URL path.
Updated all rollback test calls to include the X-Project header with testProject value.

This follows the no-project-in-path pattern for template endpoints.

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* feat: support both URL patterns for rollback endpoint

Added dual URL pattern support for rollback endpoint:
- `/v1/templates/:project_id/:template_name/rollback` (with project in path)
- `/v1/templates/:template_name/rollback` (NoProject, uses X-Project header)

Backend supports both patterns, but Stainless only exposes the cleaner NoProject version for SDKs.

Key changes:
- Fixed "rollback to latest" bug by resolving target version BEFORE auto-saving
- NoProject route is exported first to ensure correct route matching order
- Updated tests to use project_id in path for better compatibility
- All 8 rollback tests passing

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* bump

* bump

* bump

---------

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Shubham Naik
2026-02-12 13:30:44 -08:00
committed by Caren Thomas
parent 778f28ccf3
commit 565fd3c143

View File

@@ -20300,6 +20300,225 @@
}
}
},
"/v1/templates/{template_name}/rollback": {
"post": {
"description": "Rollback the current working version of a template to a previous saved version. If the current version has unsaved changes, they will be automatically saved as a new version before rollback.",
"summary": "Rollback template to previous version (Cloud-only)",
"tags": ["templates"],
"parameters": [
{
"name": "template_name",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "The template name (without version)"
}
],
"operationId": "templates.rollbackTemplateNoProject",
"requestBody": {
"description": "Body",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"type": "string",
"description": "The target version to rollback to (e.g., \"1\", \"2\", \"latest\"). Cannot be \"current\" or \"dev\"."
}
},
"required": ["version"]
}
}
}
},
"responses": {
"200": {
"description": "200",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
}
},
"required": ["success"]
}
}
}
},
"400": {
"description": "400",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
},
"404": {
"description": "404",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
},
"500": {
"description": "500",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
}
}
}
},
"/v1/templates/{project_id}/{template_name}/rollback": {
"post": {
"description": "Rollback the current working version of a template to a previous saved version. If the current version has unsaved changes, they will be automatically saved as a new version before rollback.",
"summary": "Rollback template to previous version (Cloud-only)",
"tags": ["templates"],
"parameters": [
{
"name": "project_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "The project id"
},
{
"name": "template_name",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "The template name (without version)"
}
],
"operationId": "templates.rollbackTemplate",
"requestBody": {
"description": "Body",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"type": "string",
"description": "The target version to rollback to (e.g., \"1\", \"2\", \"latest\"). Cannot be \"current\" or \"dev\"."
}
},
"required": ["version"]
}
}
}
},
"responses": {
"200": {
"description": "200",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
}
},
"required": ["success"]
}
}
}
},
"400": {
"description": "400",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
},
"404": {
"description": "404",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
},
"500": {
"description": "500",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
}
}
}
},
"/v1/templates/{project_id}/{template_name}/agent-file": {
"put": {
"description": "Updates the current working version of a template from an agent file",