feat: add template versioning with tags support for JS and Python SDKs - #1080
Merged
Conversation
- Add Template.assignTag() and Template.deleteTag() methods - Update Template.build() to accept names as second parameter (string or array) - Support 'alias:tag' format for template versioning - Maintain backward compatibility with deprecated alias option - Add TagInfo type for tag assignment responses - Update BuildInfo to include names array - Add tests for new tag methods - Regenerate API clients with tags endpoints Based on infra PR #1524 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: c8f54f9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
- Add Template.assignTag() and Template.deleteTag() methods - Update Template.build() to accept names as second parameter (string or array) - Support 'alias:tag' format for template versioning - Maintain backward compatibility with deprecated alias option - Add TagInfo type for tag assignment responses - Update BuildInfo to include names array - Add tests for new tag methods - Regenerate API clients with tags endpoints Based on infra PR #1524 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…dation Let the API validate the mutual exclusivity of names and alias fields instead of having the SDK do the conversion/validation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The API rejects null values for optional fields. Use UNSET from the generated client to omit fields instead of sending null. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Three stacktrace tests were using `alias` property which is not recognized by the buildTemplate helper function, causing them to use random UUIDs instead of expected template names. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- JS SDK: Added normalizeBuildArguments() helper for build/buildInBackground - Python SDK: Added normalize_names() helper in types.py for build methods Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- JS SDK: tests/integration/tags.test.ts - Build template with tags - Assign additional tags - Delete tags - Verify error on non-existent tag deletion - Python SDK: sync and async integration tests - tests/sync/template_sync/test_tags_integration.py - tests/async/template_async/test_tags_integration.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move integration tests from separate files into the existing tags.test.ts and test_tags.py files. Add pytest integration marker support. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update test fixtures to use `name` instead of `alias` parameter - Pass `skip_cache` through fixtures to SDK instead of ignoring it - Update stacktrace tests mock functions to use `name` parameter - Update all test calls to use `name=` instead of `alias=` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
dobrac
force-pushed
the
feat/template-versioning-tags
branch
from
January 13, 2026 14:11
f43619a to
f4f37ec
Compare
The API returns just the tag portion (e.g., 'production') instead of the full alias:tag format. Updated integration tests to expect the correct response format. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The API returns success (204) for deleting nonexistent tags (idempotent behavior), so integration tests should not expect an error in this case. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SDK's request_build function is called with names= and alias= keyword arguments, not name=. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
mishushakov
reviewed
Jan 23, 2026
mishushakov
left a comment
Member
There was a problem hiding this comment.
reorder some stuff, improve python tests, add more explicits checks for name length, logs array
- Reuse BuildLogLevel type from types.ts in logger.ts to avoid duplication - Refactor Python tag tests to use unittest.mock (AsyncMock/Mock) instead of manual capture lists - Remove unnecessary cleanup calls in integration tests
- Remove duplicate BuildLogEntry and BuildLogLevel types - Add step field to LogEntry class to support build step info - Update mapLogEntry to return LogEntry instances - Use LogEntryLevel as single source of truth for log levels - Fix Python f-string formatting for tags message
Contributor
|
Bugbot Autofix prepared a fix for the bug found in the latest run.
Preview (5a7e357)diff --git a/packages/js-sdk/src/template/buildApi.ts b/packages/js-sdk/src/template/buildApi.ts
--- a/packages/js-sdk/src/template/buildApi.ts
+++ b/packages/js-sdk/src/template/buildApi.ts
@@ -293,7 +293,8 @@ export async function waitForBuildFinish(
new LogEntry(
logEntry.timestamp,
logEntry.level,
- stripAnsi(logEntry.message)
+ stripAnsi(logEntry.message),
+ logEntry.step
)
)
) |
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
dobrac
force-pushed
the
feat/template-versioning-tags
branch
from
January 26, 2026 23:02
7f300d9 to
61eaa9d
Compare
dobrac
force-pushed
the
feat/template-versioning-tags
branch
from
January 26, 2026 23:14
61eaa9d to
d819f77
Compare
mishushakov
reviewed
Jan 27, 2026
mishushakov
reviewed
Jan 27, 2026
mishushakov
reviewed
Jan 27, 2026
mishushakov
reviewed
Jan 27, 2026
mishushakov
reviewed
Jan 27, 2026
mishushakov
reviewed
Jan 27, 2026
mishushakov
reviewed
Jan 27, 2026
mishushakov
approved these changes
Jan 27, 2026
mishushakov
left a comment
Member
There was a problem hiding this comment.
minor nits, but overall looks good, happy to merge
…consistency - Fix JSDoc param order in Template.build and buildInBackground (template, name, options) - Reorder Python SDK parameters: move tags after alias in build methods - Update request_build function signature to match main.py ordering - Add error handling with build info capture to JS test setup matching Python conftest.py
The step field on LogEntry was set from API responses but never used by consumers. BuildStatusReason.step (used for stack trace resolution) is preserved.
Contributor
|
Bugbot Autofix prepared a fix for the bug found in the latest run.
Preview (984da47)diff --git a/packages/python-sdk/e2b/template_async/build_api.py b/packages/python-sdk/e2b/template_async/build_api.py
--- a/packages/python-sdk/e2b/template_async/build_api.py
+++ b/packages/python-sdk/e2b/template_async/build_api.py
@@ -158,7 +158,7 @@ def _map_build_status_reason(reason) -> Optional[BuildStatusReason]:
return BuildStatusReason(
message=reason.message,
step=reason.step if not isinstance(reason.step, Unset) else None,
- log_entries=[_map_log_entry(e) for e in (reason.log_entries or [])],
+ log_entries=[_map_log_entry(e) for e in (reason.log_entries if not isinstance(reason.log_entries, Unset) and reason.log_entries else [])],
)
diff --git a/packages/python-sdk/e2b/template_sync/build_api.py b/packages/python-sdk/e2b/template_sync/build_api.py
--- a/packages/python-sdk/e2b/template_sync/build_api.py
+++ b/packages/python-sdk/e2b/template_sync/build_api.py
@@ -157,7 +157,7 @@ def _map_build_status_reason(reason) -> Optional[BuildStatusReason]:
return BuildStatusReason(
message=reason.message,
step=reason.step if not isinstance(reason.step, Unset) else None,
- log_entries=[_map_log_entry(e) for e in (reason.log_entries or [])],
+ log_entries=[_map_log_entry(e) for e in (reason.log_entries if not isinstance(reason.log_entries, Unset) and reason.log_entries else [])],
) |
Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jakub Dobry <jakub.dobry8@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add template versioning support using tags to the JS and Python SDKs. Templates can now be built with multiple tags (in
name:tagformat), and tags can be assigned or deleted from existing builds.Features
Template Building with Tags
Build templates with one or more tags to enable versioning and environment-based deployments.
aliasparameterTag Management
Manage tags on existing template builds:
assignTag- Assign new tag(s) to an existing buildremoveTag- Remove a tag from a templateSDK Usage
JavaScript/TypeScript
Python
Based on infra PR #1524
Note
Introduces tag-based template versioning across JS and Python SDKs and updates the build API.
nameorname:tag; multiple tags supported;aliasremains for backward compatibility (normalized internally)Template.assignTags()/assign_tags()andTemplate.removeTags()/remove_tags(); adds/templates/tagsendpoints and generated models/typesname/tags, maps build status/reason/log entries to new types, exposes tag helpersTemplate.build(template, "name")signature; extensive unit/integration tests addedaliasin v3 request), scripts includetagsspecWritten by Cursor Bugbot for commit c8f54f9. This will update automatically on new commits. Configure here.