Repository: ggml-org/llama.cpp
Pull request: jinja : correct default size for string slices

*Make sure to read the [contributing guidelines](https://github.com/ggml-org/llama.cpp/blob/master/CONTRIBUTING.md) before submitting a PR*

As of b8157, when trying to use string slices in a chat template, and the slice does not specify end index (e.g. `content[1 : ]`), no output will be emitted since the default end index is calculated only for arrays, and remains 0 for strings. This PR adds handling for strings, and should be complete for currently supported data types.

<details>
<summary>test-chat-template details</summary>

`test.jinja`:
```jinja
{{- messages[0].content[:] }}
```

`test.json`:
```json
{
	"messages": [
		{ "role": "user", "content": "123456" }
	]
}
```

Before (b8157):
```
C:\llama.cpp-b8157\build\bin\Debug>test-chat-template.exe --json "C:\test.json" "C:\test.jinja"
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:767 : Member expression on object type Array, property type Integer
jinja-runtime:787 : Accessing Array index 0
jinja-runtime:753 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:767 : Member expression on object type Object, property type String
jinja-runtime:782 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:736 : Member expression is a slice: start 0, stop 0, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value messages[0].content, type: String (used), ops: slice
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:767 : Member expression on object type Array, property type Integer
jinja-runtime:787 : Accessing Array index 0
jinja-runtime:753 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:767 : Member expression on object type Object, property type String
jinja-runtime:782 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:736 : Member expression is a slice: start 0, stop 0, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value messages[0].content, type: String (used), ops: slice
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:767 : Member expression on object type Array, property type Integer
jinja-runtime:787 : Accessing Array index 0
jinja-runtime:753 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:767 : Member expression on object type Object, property type String
jinja-runtime:782 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:736 : Member expression is a slice: start 0, stop 0, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value tools[0].function.name, type: String , ops:
jinja-caps:61  : Value messages[1].tool_calls, type: Array , ops:
jinja-caps:61  : Value messages[1].tool_calls[1].function, type: Object , ops:
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:767 : Member expression on object type Array, property type Integer
jinja-runtime:787 : Accessing Array index 0
jinja-runtime:753 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:767 : Member expression on object type Object, property type String
jinja-runtime:782 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:736 : Member expression is a slice: start 0, stop 0, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value messages[1].reasoning_content, type: String , ops:
jinja-caps:280 : Caps(
  supports_parallel_tool_calls=false
  supports_preserve_reasoning=false
  supports_string_content=true
  supports_system_role=true
  supports_tool_calls=false
  supports_tools=false
  supports_typed_content=false
)

jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:767 : Member expression on object type Array, property type Integer
jinja-runtime:787 : Accessing Array index 0
jinja-runtime:753 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:767 : Member expression on object type Object, property type String
jinja-runtime:782 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:736 : Member expression is a slice: start 0, stop 0, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'

=== OUTPUT ===


C:\llama.cpp-b8157\build\bin\Debug>
```

After (this PR):
```
C:\llama.cpp-b8157\build\bin\Debug>test-chat-template.exe --json "C:\test.json" "C:\test.jinja"
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:769 : Member expression on object type Array, property type Integer
jinja-runtime:789 : Accessing Array index 0
jinja-runtime:755 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:769 : Member expression on object type Object, property type String
jinja-runtime:784 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:738 : Member expression is a slice: start 0, stop 7, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value messages[0].content, type: String (used), ops: slice
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:769 : Member expression on object type Array, property type Integer
jinja-runtime:789 : Accessing Array index 0
jinja-runtime:755 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:769 : Member expression on object type Object, property type String
jinja-runtime:784 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:738 : Member expression is a slice: start 0, stop 14, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value messages[0].content, type: String (used), ops: slice
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:769 : Member expression on object type Array, property type Integer
jinja-runtime:789 : Accessing Array index 0
jinja-runtime:755 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:769 : Member expression on object type Object, property type String
jinja-runtime:784 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:738 : Member expression is a slice: start 0, stop 12, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value tools[0].function.name, type: String , ops:
jinja-caps:61  : Value messages[1].tool_calls, type: Array , ops:
jinja-caps:61  : Value messages[1].tool_calls[1].function, type: Object , ops:
jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'tools'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:769 : Member expression on object type Array, property type Integer
jinja-runtime:789 : Accessing Array index 0
jinja-runtime:755 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:769 : Member expression on object type Object, property type String
jinja-runtime:784 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:738 : Member expression is a slice: start 0, stop 12, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'
jinja-caps:61  : Value messages[1].reasoning_content, type: String , ops:
jinja-caps:280 : Caps(
  supports_parallel_tool_calls=false
  supports_preserve_reasoning=false
  supports_string_content=true
  supports_system_role=true
  supports_tool_calls=false
  supports_tools=false
  supports_typed_content=false
)

jinja-value:1268 : global_from_json: setting key 'messages'
jinja-value:1268 : global_from_json: setting key 'bos_token'
jinja-value:1268 : global_from_json: setting key 'eos_token'
jinja-value:1268 : global_from_json: setting key 'add_generation_prompt'
jinja-runtime:90  : Identifier 'messages' found, type = Array
jinja-runtime:719 : Member expression, computing property type IntegerLiteral
jinja-runtime:769 : Member expression on object type Array, property type Integer
jinja-runtime:789 : Accessing Array index 0
jinja-runtime:755 : Member expression, object type Object, static property 'content'
jinja-runtime:278 : Trying built-in function 'content' for type Object
jinja-runtime:769 : Member expression on object type Object, property type String
jinja-runtime:784 : Accessed property 'content' value, got type: String
jinja-runtime:719 : Member expression, computing property type SliceExpression
jinja-runtime:738 : Member expression is a slice: start 0, stop 6, step 1
jinja-runtime:278 : Trying built-in function 'slice' for type String
jinja-runtime:286 : Binding built-in 'slice'

=== OUTPUT ===
123456

C:\llama.cpp-b8157\build\bin\Debug>
```

</details>

Changed files:
filename: common/jinja/runtime.cpp
patch: @@ -721,6 +721,8 @@ value member_expression::execute_impl(context & ctx) {
         int64_t arr_size = 0;
         if (is_val<value_array>(object)) {
             arr_size = object->as_array().size();
+        } else if (is_val<value_string>(object)) {
+            arr_size = object->as_string().length();
         }
 
         if (is_stmt<slice_expression>(this->property)) {