Skip to content

Python: fix: CodeTokenizer: handle spaces inside quoted named-arg values - #14478

Open
Wu Shuwen (dajiaohuang) wants to merge 2 commits into
microsoft:mainfrom
dajiaohuang:fix/code-tokenizer-quoted-named-arg
Open

Wu Shuwen (dajiaohuang) wants to merge 2 commits into
microsoft:mainfrom
dajiaohuang:fix/code-tokenizer-quoted-named-arg

Conversation

@dajiaohuang

Copy link
Copy Markdown

Description

When parsing templates like {{func key='hello world'}}, the CodeTokenizer incorrectly included spaces inside quoted named-arg values, causing NamedArgBlockSyntaxError.

Root cause

The VALUE state in the tokenizer's main loop appends every character to current_token_content without checking whether a space is a token separator. When a space inside a quoted value is followed by an alphanumeric character (the continuation of the quoted text), the space is incorrectly treated as a token boundary.

Two changes fix this:

  1. Space handling in VALUE mode: A space now ends the quoted value only when the following character is not a valid quoted-value continuation (alphanumeric, _, -, $, quote, VAR_PREFIX).

  2. Closing delimiter check: The closing quote is recognized as a block boundary only when the character after it is not alphanumeric. This correctly handles quoted values adjacent to punctuation like }}.

Reproduction

from semantic_kernel.template_engine.code_tokenizer import CodeTokenizer
CodeTokenizer().tokenize("{{func key='hello world'}}")
# Previously: NamedArgBlockSyntaxError
# After fix: correctly splits into FunctionIdBlock, NamedArgBlock, and trailing FunctionIdBlock

Fixes #14460.

When parsing templates like {{func key='hello world'}}, the tokenizer
incorrectly included spaces inside quoted named-arg values because
the VALUE state did not check for a closing delimiter when a space
was encountered.

Two changes:
1. A space in VALUE mode now only ends the value when followed by a
   non-alphanumeric, non-$-, non-quote character (i.e., a genuine
   token separator, not part of the quoted text).
2. The closing delimiter check now additionally verifies that the
   character after the quote is not alphanumeric, which correctly
   handles quoted values adjacent to punctuation like }}.

Fixes microsoft#14460.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The tokenizer does not enter named-argument value handling, so the reported case remains unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

Fixes CodeTokenizer handling of spaces in quoted named-argument values.

Changes:

  • Adds quoted-value space handling.
  • Adds closing-quote lookahead logic.
File Summary
python/​semantic_kernel/​template_engine/​code_tokenizer.py Adjusts tokenizer state and quoted-value parsing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +91 to +95
if current_char == Symbols.SPACE and next_char not in (
Symbols.SGL_QUOTE,
Symbols.DBL_QUOTE,
Symbols.VAR_PREFIX,
) and not next_char.isalnum() and next_char not in ("_", "-"):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review finding (blocking): Quoted named-argument values with spaces are still split

The advertised {{func key='hello world'}} case still starts in the FUNCTION_ID state, and the tokenizer never enters the new named-argument value branch while scanning the equals sign and quote. The space after hello therefore still takes the generic separator path and raises NamedArgBlockSyntaxError. Please enter a quoted named-argument state when = is followed by a quote, and add a regression test for this exact template.

The previous fix had two issues:
1. It added a broken space-handling branch that incorrectly terminated ValBlocks on spaces,
   causing tokens after quoted values to be consumed into the ValBlock.
2. The closing-delimiter check used text[index+2] (off-by-one), preventing legitimate
   closing quotes (e.g. in escape sequences like 'f\\'xy') from being detected.
3. It never added the state transition from FUNCTION_ID to NAMED_ARG when the opening
   quote appears mid-token after '=', which is the root cause of the original bug.

The root cause was that when parsing 'key='hello world'', the opening quote appears
after '=' (still mid-FUNCTION_ID token), not after a space separator. The code never
switched into quoted-value mode, so the space inside 'hello world' incorrectly
terminated the FUNCTION_ID token.

Fix:
- Remove the broken space-handling and incorrect index+2 check.
- When in FUNCTION_ID mode and the current char is a quote and '=' is already present
  in the token content, switch to NAMED_ARG mode (setting text_value_delimiter) so that
  spaces inside the quoted value are preserved and the closing quote ends the NamedArgBlock.
- When closing a quoted block, create NamedArgBlock (not ValBlock) if in NAMED_ARG mode.
- Handle NAMED_ARG in the end-of-loop final-capture.
- Add regression test for issue microsoft#14460.
@dajiaohuang

Copy link
Copy Markdown
Author

Fixed: Completed the fix for spaces in quoted named-arg values

The original PR had the right goal but the implementation had two issues that caused the 39 test failures:

Root cause of the failures

  1. The added space-handling branch (lines 91-101) incorrectly terminated quoted values on spaces, causing all tokens after a quote to be consumed into the ValBlock (e.g. "direct" arg1=$arg1 arg2="arg2" was parsed as a single ValBlock).

  2. The closing-delimiter check used text[index+2] (off-by-one: it looked two characters ahead instead of one), which prevented the legitimate closing quote in escape sequences like call 'f\\'xy' from being detected, so the test test_it_throws_when_separators_are_missing no longer raised.

  3. The real bug was not addressed: when parsing key='hello world', the opening quote appears after = (mid-FUNCTION_ID token), not after a space separator. The code never transitioned out of FUNCTION_ID mode into a quoted-value mode, so the space inside "'hello world' incorrectly terminated the FUNCTION_ID token at key='hello. The PR fix tried to patch this from within the VALUE/NAMED_ARG branch, but that branch was never entered in the first place.

What this fix does

  • Removes the broken space-handling and the incorrect index+2 closing-delimiter check.
  • Adds the missing state transition: when in FUNCTION_ID mode, if the current char is a quote (' or ") and = is already present in the token content (i.e. we just saw the opening quote of a named-arg value like key='), switch to BlockTypes.NAMED_ARG mode and set text_value_delimiter. In this mode, spaces are just appended (not treated as token separators), and the matching closing quote ends the block as a NamedArgBlock (not ValBlock).
  • Handles NAMED_ARG in the end-of-loop final-token capture.
  • Adds a regression test test_named_args_with_spaces_in_quoted_value covering the issue Python: CodeTokenizer splits quoted named-arg values on spaces (NamedArgBlockSyntaxError) #14460 scenario for both single and double quotes, plus multiple spaced named args.

Test results

  • All 451 tests/unit/template_engine/ tests pass (was 39 failed).
  • All 738 tests across template_engine, functions, and kernel pass.

The fix correctly tokenizes:

  • func key='hello world' → [FunctionIdBlock("func"), NamedArgBlock("key='hello world'")] ✓
  • plugin.function "direct" arg1=$arg1 arg2="arg2" → 4 blocks ✓
  • Escape sequences func 'f\'oo' still work ✓
  • Missing separators call 'f\\\\'xy' still raise CodeBlockSyntaxError ✓

@semantic-kernel-automation semantic-kernel-automation Bot added the python Pull requests for the Python Semantic Kernel label Oct 8, 2026
@github-actions github-actions Bot changed the title fix: CodeTokenizer: handle spaces inside quoted named-arg values Python: fix: CodeTokenizer: handle spaces inside quoted named-arg values Oct 8, 2026

This branch was previously deployed

1 inactive deployment
github-app-auth — 5592924d Deployed Oct 8, 2026 by dajiaohuang via add_label #29296
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: CodeTokenizer splits quoted named-arg values on spaces (NamedArgBlockSyntaxError)

3 participants