Skip to content

fix: escape every double-quote when embedding in Python triple-quoted strings - #2758

Open
PratikDhanave wants to merge 1 commit into
aws:v1.xfrom
PratikDhanave:fix/python-triple-quote-escape
Open

PratikDhanave wants to merge 1 commit into
aws:v1.xfrom
PratikDhanave:fix/python-triple-quote-escape

Conversation

@PratikDhanave

Copy link
Copy Markdown

Description

When the CLI embeds a service-controlled string into a Python triple-double-quoted literal ("""…"""), it only escaped full """ runs. A value that ends in a double-quote (or two) left that quote adjacent to the closing """ delimiter, producing """". Python reads that as a closed string plus a dangling quote — a SyntaxError: unterminated string literal — so the generated main.py will not run.

Two helpers shared the bug, both doing …replace(/"""/g, '\"\"\"'):

  • escapePythonTripleQuoted in src/core/project/bedrockAgentImport/baseTranslator.ts, used by generateSystemPrompt to emit SYSTEM_PROMPT = """<instruction>""" for an imported Bedrock Agent.
  • the escapePyStr Handlebars helper in src/core/project/templates/renderer.ts, used in src/assets/templates/export-harness-python/main.py as DEFAULT_SYSTEM_PROMPT = """{{escapePyStr systemPromptText}}""" for an exported harness.

The instruction / system prompt text is service-controlled, so a user cannot work around this from the CLI.

Fix

Escape every double-quote instead of only """ runs:

-  return value.replace(/\\/g, "\\\\").replace(/"""/g, '\"\"\"');
+  return value.replace(/\\/g, "\\\\").replace(/"/g, '\"');

Escaping each " still turns a """ run into \"\"\" (so prior behavior is preserved) and additionally keeps a trailing quote inside the literal. Verified the output compiles and round-trips under real python3:

ORIGINAL (buggy): SYSTEM_PROMPT = """Always answer in "quotes""""
  -> SyntaxError: unterminated string literal (detected at line 1)
FIXED:            SYSTEM_PROMPT = """Always answer in \"quotes\""""
  -> compiles OK; round-trip equal to the original instruction: True

Tests

Added a regression test for each helper.

Fail-pre (on the unfixed code):

error: expect(received).toBe(expected)
Expected: "Always answer in \"quotes\""
Received: "Always answer in "quotes""
(fail) escapePythonTripleQuoted > escapes a trailing double-quote so it does not merge with the closing delimiter

Pass-post (touched packages):

bun test src/core/project/bedrockAgentImport/ src/core/project/templates/
 159 pass  0 fail   (11 files)

Related Issue

Closes #2757

Documentation PR

Not applicable — this is an internal code-generation bug fix with no user-facing documentation or command surface change.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

How have you tested the change? Added escapePythonTripleQuoted / escapePyStr regression tests (fail-pre / pass-post above) and confirmed the generated Python compiles and round-trips under python3.

  • I ran bun test (4699 pass / 6 fail). The 6 failures are pre-existing on an unmodified v1.x — I reproduced the identical 6 on the base commit before my change — and are unrelated to this PR: 2 in src/components/RouterScreen.test.tsx (menu brand-banner rendering) and 4 in src/handlers/update/update.screen.test.tsx (update screen), both Ink TUI rendering suites sensitive to terminal size / TTY. The bedrockAgentImport and templates packages this PR touches are fully green (159 pass / 0 fail)
  • I ran the relevant end-to-end tests with bun run test:e2e — not applicable; this change makes no AWS calls and touches only CPU-only string-escaping used in code generation
  • I ran bun run typecheck
  • I ran bun run lint:check
  • I ran bun run format:check
  • I ran bun run audit — could not run locally (bun audit reported UnknownLockfileVersion against the committed lockfile under my local Bun)
  • I ran bun run secrets:check
  • I ran bun run build
  • If I modified src/assets/, I updated affected snapshots — N/A, src/assets/ unchanged
  • If I re-recorded fixtures or golden files — N/A, no fixtures or golden files changed
  • This PR does not change command.md

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective
  • I have updated the documentation accordingly — N/A, no docs affected
  • I have added an appropriate example to the documentation — no new docs needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published — N/A

… strings

escapePythonTripleQuoted and the escapePyStr template helper only escaped
full """ runs. A value ending in a double-quote (or two) left the quote
adjacent to the closing """ delimiter, forming """" — which Python reads as
a closed string plus a dangling quote, a SyntaxError. An imported Bedrock
Agent or exported harness whose instruction/system prompt ended in a quote
produced a main.py that would not run.

Escape every double-quote instead; this still collapses """ runs safely and
keeps trailing quotes inside the literal. Adds regression tests for both
helpers.
@PratikDhanave
PratikDhanave requested a review from a team November 4, 2026 17:16
@github-actions github-actions Bot added the size/s PR size: S label Nov 4, 2026
@PratikDhanave PratikDhanave changed the title fix: escape every double-quote when embedding strings in Python triple-quoted literals fix: escape every double-quote when embedding in Python triple-quoted strings Nov 9, 2026
@github-actions github-actions Bot added size/s PR size: S and removed size/s PR size: S labels Nov 9, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated Python breaks when an imported/exported agent instruction ends in a double-quote

1 participant