open-notebook/prompts
Yehuda 6f565136d0
fix(podcasts): restore the language instruction and stop the prompts handing the model a copyable skeleton (#1334)
* fix(podcasts): restore the language instruction and stop the prompts handing the model a copyable skeleton (#1238)

Two independent defects in prompts/podcast/*.jinja, plus the failure hints that
made both of them hard to diagnose. Split out of #1239 at review request; the
voice pre-flight from that PR stays there.

Language
--------
These templates shadow podcast-creator's bundled ones - the library resolves
Path.cwd()/prompts/podcast/<name>.jinja before its own package resources, and
this app configures only profiles - and the app's copies never referenced
`{{ language }}`. The value is plumbed correctly end to end, so an episode
profile set to he-IL produced an English outline and English segment titles:
EpisodeProfile.language looked supported and did nothing.

The bundled block is restored in both templates, and a regression test fails
when a variable the bundled template uses is missing from the app's copy - the
drift that lost it in the first place.

Copyable skeleton
-----------------
Both templates showed a fill-in JSON skeleton (`"speaker": "[Actual Speaker
Name]"`, a bare `...`) inside a ```json fence while also instructing the model
not to use fences. Models returned the skeleton verbatim, which failed
podcast-creator's speaker-name validation and aborted the episode - discarding
the outline and every segment already generated.

The example now carries the episode's real speaker names (serialized with
tojson, so a name containing a quote can't break it) and written-out sample
values, so a verbatim copy is valid output. Placeholders and truncation are
banned explicitly, the contradictory fence and the second copyable example are
gone, and the example is labelled a two-entry excerpt that restates the
required turns/num_segments count so it can't read as a finished answer.

No sample is rendered at all when a language is set: any hard-coded sample is
English, and a copied English line in a Hebrew episode goes straight to TTS.
The structure is stated in prose there, and format_instructions still carries
the schema.

Hints
-----
explain_generation_failure() maps a failure to the hint that fits it. The GPT-5
extended-thinking note was the only one, keyed on `Invalid json output` /
`Expecting value`, so `Invalid speaker name` got nothing and a truncated Gemini
response was advised to switch to gpt-4o. Placeholder speaker names, unusable
voices and truncated output now each get their own explanation.

* fix(podcasts): make the failure hints reachable and scope the not-found one (#1238)

Review follow-ups on this PR.

- The hint mapper never ran for the failures it was written for. `except
  ValueError: raise` sits ahead of the handler that attaches hints, and both
  LangChain's OutputParserException and json.JSONDecodeError are ValueError
  subclasses - so a placeholder speaker name, `Invalid json output` and a
  truncated response all left untouched. That includes the pre-existing GPT-5
  extended-thinking note, which has been dead for exactly the case it
  describes. The ValueError branch now attaches the hint and re-raises a
  ValueError, keeping the command layer's permanent-failure contract intact.
- `Requested entity was not found` no longer claims the voice is at fault.
  Google returns it for any missing resource, including a model id on the
  outline or transcript call, so the hint now names both candidates and says
  which is likelier when audio had already started. The voice-specific hint
  stays keyed on `Voice name ... is not supported`, which does name the voice.
- A solo speaker profile renders a one-entry example; the prose called it a
  two-entry excerpt and told the model to return more than "the two shown".
  Both now follow speakers|length.
- The template drift check counted Jinja's `not` as a variable, so
  `{% if not language %}` would fail the check the moment one template negated
  a test the other didn't.

* chore(podcasts): rebase on main, ruff format, update the truncation hint

- Rebased onto main (CHANGELOG conflict).
- tests/test_podcast_prompt_templates.py formatted with ruff (CI now gates
  ruff format, #1429).
- The truncated-JSON hint quoted podcast-creator's old 5000-token transcript
  cap; since 0.13 (#1446) outline and transcript request up to 8192, so the
  hint now says to set max_tokens to the model's limit when it stops earlier.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBYpxzSS62Y3TZkgB9NUZy

* fix(podcasts): keep the JSON contract in English; English keeps the sample

- The language instruction now says the JSON keys (and outline size values,
  transcript speaker names) stay exactly as written, so a non-English run
  can't translate them and fail validation.
- English locales resolve to "English"; they keep the (English) sample.
- The drift check uses jinja2.meta, so variables used only as `for`
  iterables count too.
- Docs: solo transcript excerpts are one-entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBYpxzSS62Y3TZkgB9NUZy

* docs(podcasts): the excerpt's entries are reusable, the excerpt is not a full answer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBYpxzSS62Y3TZkgB9NUZy

---------

Co-authored-by: Yehuda Korotkin <yehuda.korotkin@ness-tech.co.il>
Co-authored-by: Luis Novo <lfnovo@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 04:56:36 -03:00
..
ask feat(prompts): steer models toward $$ math delimiters (#1057) 2026-07-11 18:25:39 -03:00
chat feat(prompts): steer models toward $$ math delimiters (#1057) 2026-07-11 18:25:39 -03:00
pattern fix: stop compiling user-controlled prompts as Jinja2 template source (#1004) 2026-07-10 10:28:39 -03:00
podcast fix(podcasts): restore the language instruction and stop the prompts handing the model a copyable skeleton (#1334) 2026-10-04 04:56:36 -03:00
source_chat fix: include source content in Source Chat context (#1226) 2026-08-01 18:39:19 -03:00
transformation feat(prompts): steer models toward $$ math delimiters (#1057) 2026-07-11 18:25:39 -03:00