Skip to content

Commit cbc748e

Browse files
authored
feat: structuredDecoding field on the model block (#1250)
1 parent 3e0684f commit cbc748e

File tree

14 files changed

+115
-61
lines changed

14 files changed

+115
-61
lines changed

.vscode/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,10 @@
44
},
55
"files.associations": {
66
"*.pdl": "yaml",
7-
}
7+
},
8+
"python.testing.pytestArgs": [
9+
"."
10+
],
11+
"python.testing.unittestEnabled": false,
12+
"python.testing.pytestEnabled": true
813
}

examples/tutorial/parser-regex.pdl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ text:
55
parameters:
66
# Tell the LLM to stop after generating an exclamation point.
77
stop: ['!']
8-
spec: {"name": string}
98
parser:
109
spec:
1110
name: string
Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1+
# Expected not to type check
2+
description: Creating JSON Data
3+
defs:
4+
data:
5+
read: type_checking_data.yaml
6+
parser: yaml
7+
spec: { questions: [string], answers: [object] }
18
text:
2-
- role: system
3-
text: You are an AI language model developed by IBM Research. You are a cautious assistant. You carefully follow instructions. You are helpful and harmless and you follow ethical guidelines and promote positive behavior.
4-
contribute: [context]
5-
- "\nWhat is the color of the sky? Write it as JSON\n"
6-
- model: watsonx/ibm/granite-34b-code-instruct
7-
parser: json
8-
spec: { color: string }
9+
- model: ollama_chat/granite3.2:2b
10+
def: model_output
11+
input:
12+
array:
13+
- role: user
14+
content:
15+
text:
16+
- for:
17+
question: ${ data.questions }
18+
answer: ${ data.answers }
19+
repeat: |
20+
${ question }
21+
${ answer }
22+
- >
23+
Question: Generate only a JSON object with fields 'name' and 'age' and set them appropriately. Write the age all in letters. Only generate a single JSON object and nothing else.
24+
spec: {name: string, age: integer}
25+
parser: json
26+
parameters:
27+
stop: ["Question"]
28+
temperature: 0

examples/tutorial/type_checking.pdl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ defs:
88
text:
99
- model: ollama_chat/granite3.2:2b
1010
def: model_output
11-
spec: {name: string, age: integer}
1211
input:
1312
array:
1413
- role: user
@@ -22,7 +21,7 @@ text:
2221
${ answer }
2322
- >
2423
Question: Generate only a JSON object with fields 'name' and 'age' and set them appropriately. Write the age all in letters. Only generate a single JSON object and nothing else.
25-
parser: yaml
24+
parser: json
2625
parameters:
2726
stop: ["Question"]
2827
temperature: 0

examples/tutorial/type_error.pdl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Expected not to type check
2+
description: Creating JSON Data
3+
defs:
4+
data:
5+
read: type_checking_data.yaml
6+
parser: yaml
7+
spec: { questions: [string], answers: [object] }
8+
text:
9+
- model: ollama_chat/granite3.2:2b
10+
def: model_output
11+
input:
12+
array:
13+
- role: user
14+
content:
15+
text:
16+
- for:
17+
question: ${ data.questions }
18+
answer: ${ data.answers }
19+
repeat: |
20+
${ question }
21+
${ answer }
22+
- >
23+
Question: Generate only a JSON object with fields 'name' and 'age' and set them appropriately. Write the age all in letters. Only generate a single JSON object and nothing else.
24+
spec: {name: string, age: integer}
25+
parser: json
26+
structuredDecoding: false
27+
parameters:
28+
stop: ["Question"]
29+
temperature: 0

pdl-live-react/src/pdl_ast.d.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,6 @@ export type Anyof = PatternType[]
264264
export type Array = PatternType[]
265265
export type Any = null
266266
export type ExpressionBool = LocalizedExpression | boolean | string
267-
export type PdlCaseResult = boolean | null
268-
export type PdlIfResult = boolean | null
269-
export type PdlMatched = boolean | null
270267
/**
271268
* List of cases to match.
272269
*
@@ -463,7 +460,7 @@ export type Aggregator = "context" | FileAggregatorConfig
463460
* Documentation associated to the aggregator config.
464461
*
465462
*/
466-
export type Description1 = string | null
463+
export type Description = string | null
467464
/**
468465
* Name of the file to which contribute.
469466
*/
@@ -1015,9 +1012,9 @@ export interface RegexParser {
10151012
* Single requirement definition.
10161013
*/
10171014
export interface RequirementType {
1018-
description: unknown
1019-
evaluate: Evaluate
1020-
transformContext: Transformcontext
1015+
expect: unknown
1016+
evaluate?: Evaluate
1017+
transformContext?: Transformcontext
10211018
}
10221019
export interface LocalizedExpression {
10231020
pdl__expr: PdlExpr
@@ -1191,6 +1188,10 @@ export interface LitellmModelBlock {
11911188
*/
11921189
model: LocalizedExpression | string
11931190
parameters?: Parameters1
1191+
/**
1192+
* Perform structured decoding if possible (i.e., `parser` and `spec` are provided and the inference platform supports it).
1193+
*/
1194+
structuredDecoding?: boolean | null
11941195
}
11951196
/**
11961197
* Set of definitions executed before the execution of the block.
@@ -2068,9 +2069,9 @@ export interface MatchCase {
20682069
case?: PatternType | null
20692070
if?: ExpressionBool | null
20702071
then: BlockType
2071-
pdl__case_result?: PdlCaseResult
2072-
pdl__if_result?: PdlIfResult
2073-
pdl__matched?: PdlMatched
2072+
pdl__case_result?: boolean | null
2073+
pdl__if_result?: boolean | null
2074+
pdl__matched?: boolean | null
20742075
}
20752076
/**
20762077
* Match any of the patterns.
@@ -3384,7 +3385,7 @@ export interface Defs20 {
33843385
[k: string]: BlockType
33853386
}
33863387
export interface FileAggregatorConfig {
3387-
description?: Description1
3388+
description?: Description
33883389
file: File1
33893390
mode?: Mode1
33903391
encoding?: Encoding

src/pdl/pdl-schema.json

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2645,6 +2645,11 @@
26452645
"default": null,
26462646
"description": "Parameters to send to the model.\n ",
26472647
"title": "Parameters"
2648+
},
2649+
"structuredDecoding": {
2650+
"$ref": "#/$defs/OptionalBool",
2651+
"default": true,
2652+
"description": "Perform structured decoding if possible (i.e., `parser` and `spec` are provided and the inference platform supports it)."
26482653
}
26492654
},
26502655
"required": [
@@ -3430,40 +3435,16 @@
34303435
"$ref": "#/$defs/BlockType"
34313436
},
34323437
"pdl__case_result": {
3433-
"anyOf": [
3434-
{
3435-
"type": "boolean"
3436-
},
3437-
{
3438-
"type": "null"
3439-
}
3440-
],
3441-
"default": null,
3442-
"title": "Pdl Case Result"
3438+
"$ref": "#/$defs/OptionalBool",
3439+
"default": null
34433440
},
34443441
"pdl__if_result": {
3445-
"anyOf": [
3446-
{
3447-
"type": "boolean"
3448-
},
3449-
{
3450-
"type": "null"
3451-
}
3452-
],
3453-
"default": null,
3454-
"title": "Pdl If Result"
3442+
"$ref": "#/$defs/OptionalBool",
3443+
"default": null
34553444
},
34563445
"pdl__matched": {
3457-
"anyOf": [
3458-
{
3459-
"type": "boolean"
3460-
},
3461-
{
3462-
"type": "null"
3463-
}
3464-
],
3465-
"default": null,
3466-
"title": "Pdl Matched"
3446+
"$ref": "#/$defs/OptionalBool",
3447+
"default": null
34673448
}
34683449
},
34693450
"required": [
@@ -3798,6 +3779,16 @@
37983779
}
37993780
]
38003781
},
3782+
"OptionalBool": {
3783+
"anyOf": [
3784+
{
3785+
"type": "boolean"
3786+
},
3787+
{
3788+
"type": "null"
3789+
}
3790+
]
3791+
},
38013792
"OptionalBoolOrStr": {
38023793
"anyOf": [
38033794
{

src/pdl/pdl_ast.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def _ensure_lower(value):
4141
"""Optional string."""
4242
OptionalInt = TypeAliasType("OptionalInt", Optional[int])
4343
"""Optional integer."""
44+
OptionalBool = TypeAliasType("OptionalBool", Optional[bool])
45+
"""Optional Boolean."""
4446
OptionalBoolOrStr = TypeAliasType("OptionalBoolOrStr", Optional[Union[bool, str]])
4547
"""Optional boolean or string."""
4648
OptionalAny = TypeAliasType("OptionalAny", Optional[Any])
@@ -629,6 +631,8 @@ class LitellmModelBlock(ModelBlock):
629631
parameters: Optional[LitellmParameters | ExpressionType[dict]] = None
630632
"""Parameters to send to the model.
631633
"""
634+
structuredDecoding: OptionalBool = True
635+
"""Perform structured decoding if possible (i.e., `parser` and `spec` are provided and the inference platform supports it)."""
632636

633637

634638
class GraniteioProcessor(BaseModel):
@@ -835,9 +839,9 @@ class MatchCase(BaseModel):
835839
"""Branch to execute if the value is matched and the condition is satisfied.
836840
"""
837841
# Field for internal use
838-
pdl__case_result: Optional[bool] = None
839-
pdl__if_result: Optional[bool] = None
840-
pdl__matched: Optional[bool] = None
842+
pdl__case_result: OptionalBool = None
843+
pdl__if_result: OptionalBool = None
844+
pdl__matched: OptionalBool = None
841845

842846

843847
class MatchBlock(StructuredBlock):

src/pdl/pdl_dumper.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ def block_to_dict( # noqa: C901
154154
d["parameters"] = expr_to_dict(block.parameters, json_compatible)
155155
if block.modelResponse is not None:
156156
d["modelResponse"] = block.modelResponse
157+
if not block.structuredDecoding:
158+
d["structuredDecoding"] = block.structuredDecoding
157159
if block.pdl__usage is not None:
158160
d["pdl__usage"] = usage_to_dict(block.pdl__usage)
159161
if block.pdl__model_input is not None:

src/pdl/pdl_interpreter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1923,9 +1923,9 @@ def generate_client_response_streaming(
19231923
scope.get("pdl_model_default_parameters", []),
19241924
)
19251925
msg_stream = LitellmModel.generate_text_stream(
1926+
block,
19261927
model_id=value_of_expr(block.model),
19271928
messages=model_input,
1928-
spec=block.spec,
19291929
parameters=litellm_parameters_to_dict(parameters),
19301930
)
19311931
case GraniteioModelBlock():

0 commit comments

Comments
 (0)