feat(2397): add AI-generated "What's New" for release notes#2417
feat(2397): add AI-generated "What's New" for release notes#2417ycanales wants to merge 6 commits into
Conversation
julioest
left a comment
There was a problem hiding this comment.
Really nice work on this! The approval gate, parser tolerance for LLM output drift, and the --validate flag are all great decisions.
I left one inline comment regarding the markdown rendering. Pre-approving! ✅
herzog0
left a comment
There was a problem hiding this comment.
I'm still reviewing as it's a very dense PR, but I figured I should start with these two comments
|
@herzog0 I agree it would more consistent if we reset the approval, thanks for the suggestion! Adjusted. |
julhoang
left a comment
There was a problem hiding this comment.
Hi @ycanales , this is awesome work!! I love the wide range of command options for testing and covering different cases.
I've left a couple of suggestions inline. Besides those, I'm wondering whether we need the whats_new_html field at all. My understanding is that it gives admin users a friendly preview in the admin panel but isn't actually consumed by the website – the card component will be reading from whats_new_items, right?
If that's the case, I think we should show whats_new_items in Django Admin instead, since that's the true output served to the website. While testing, I removed the bold label from the "New Libraries" item, and the HTML field still rendered that list item – but it failed the regex in whats_new_items and wasn't parsed. An admin editor seeing this would be confused about why the website doesn't match the whats_new_html preview. So, I think we should drop whats_new_html and surface whats_new_items directly. Does that sound reasonable to you?
| "--all-missing", | ||
| is_flag=True, | ||
| default=False, | ||
| help="Queue generation for every active version that has no summary yet.", |
There was a problem hiding this comment.
Can we revise this help text to mention that the "active version" are only those that have a release note HTML on the Rendered Content page (http://localhost:8000/admin/core/renderedcontent/)?
Maybe something like: "Queue generation for every active version that has stored release notes in Rendered Content page, but no summary yet. Versions without release notes are skipped."
There was a problem hiding this comment.
The _html field was to embed it on the site, but I totally missed that we currently have a |markdown templatetag we can use to render, so it's not needed. Good catch!
There was a problem hiding this comment.
Thanks for the feedback, makes sense to me. Adjusted!
|
|
||
| release_note_text = _release_note_text(rendered_content) | ||
| logger.info( | ||
| "generate_whats_new_dispatching", | ||
| version_pk=version_pk, | ||
| version_name=version.name, | ||
| input_chars=len(release_note_text), | ||
| ) |
There was a problem hiding this comment.
Should we add a length check on release_note_text here? I'm not sure how long release notes can get or whether they could overflow the LLM token limit, especially if we're selecting a free model. Probably not likely but I think a guardrail seems worthwhile.
There was a problem hiding this comment.
It's good to have a limit, I've set 100k chars which is close to the model limit of around 131k tokens and leaves space for the prompt and output.
| if version_slug: | ||
| qs = qs.filter(slug=version_slug) | ||
| elif all_missing: | ||
| qs = qs.filter(whats_new="") if not force else qs |
There was a problem hiding this comment.
Should we add a force check on line 92 as well?
It seems like running this command docker compose exec web ./manage.py generate_whats_new --version=boost-1-89-0 currently overrides the existing content the same way as having --force would.
There was a problem hiding this comment.
Behavior updated, it will filter for whats_new="" now unless --force is specified. Thanks!
| """Parse `whats_new` markdown bullets into a list of {title, description} | ||
| dicts for the v3 release-highlights card. | ||
|
|
||
| Accepts the Markdown unordered-list bullets the LLM is instructed | ||
| to emit; a leading ``-`` or ``*`` marker is required: | ||
| - `- **New libraries** — sentence` | ||
| - `* **New libraries:** sentence` | ||
| Trailing `:` inside the label is stripped. |
There was a problem hiding this comment.
Can we update the documentation here to also say that the bold category label is expected/required by the regex?
There was a problem hiding this comment.
Good catch, I've added it to the docstring 👍
| def regenerate_whats_new(self, request, queryset): | ||
| queued = 0 | ||
| for version in queryset: | ||
| Version.objects.filter(pk=version.pk).update( |
There was a problem hiding this comment.
I think we should only clear the fields once the results are in. Say the broker is offline for any reason or an error happens, the field won't be blank.
There was a problem hiding this comment.
Good catch, now this will only dispatch, and save_whats_new will do the overwrite.
| response = client.chat.completions.create(model=WHATS_NEW_MODEL, messages=messages) | ||
| try: | ||
| content = response.choices[0].message.content | ||
| except (AttributeError, IndexError) as e: | ||
| logger.error("generate_whats_new_response_error", error=str(e)) | ||
| return None |
There was a problem hiding this comment.
Maybe we should include the .create() call in the try/catch to log the error, and then re-throw is its an instance of OpenAIError? (te leverage the autoretry_for option)
There was a problem hiding this comment.
Good call, I've adjusted the try/except to cover the API call.

Issue: #2397
Summary & Context
Adds an AI-generated "What's New" summary to the v3 Boost release detail page (issue #2397). Version model, and gated behind an admin-controlled approval flag.
Changes
Model + migration (versions/models.py, versions/migrations/0027_*.py)
Celery pipeline (versions/tasks.py)
Auto-dispatch on import (versions/releases.py)
Management command (versions/management/commands/generate_whats_new.py)
Other
render_whats_new_markdownincore.htmlhelper.Test plan
generate_whats_newcommand:docker compose exec web ./manage.py generate_whats_new --version=boost-1-89-0 --forceVersionDetailview and related template in this PR?Screenshots
Command
Celery
Self-review Checklist